❤️AllenIverrui❤️ 😊 个人博客 😊 gitee 😊 B站 近期文章: 😄《docker 常规软件的安装》 😄《Linux配置静态ip》 《😄Docker-compose容器编排》
文章目录
- 爱心代码合集
- three.js
- html + javascript
- c++
- python -1
- python -2
爱心代码合集
所有代码均来源于网络,若侵犯到你的利益请联系删除
视频教程 https://b23.tv/0jY9AH5
three.js
浏览地址 love.alleniverrui.top
html + javascript
浏览地址 love.alleniverrui.top/2
代码地址 https://gitee.com/alleniverrui/love
c++
所需环境 easyx
#include<graphics.h> #include <conio.h> #include<time.h> #include<math.h> #include<stdlib.h> //爱心点结构体 struct Point { double x, y; //坐标 COLORREF color; //颜色 }; //颜色数组 COLORREF colors[7] = { RGB(255,32,83),RGB(252,222,250) ,RGB(255,0,0) ,RGB(255,0,0) ,RGB(255,2,2) ,RGB(255,0,8) ,RGB(255,5,5) }; //COLORREF colors[7] = { RGB(55,132,83),RGB(252,222,250) ,RGB(25,120,130) ,RGB(25,230,40) ,RGB(25,24,112) ,RGB(255,230,128) ,RGB(25,5,215) }; const int xScreen = 1200; //屏幕宽度 const int yScreen = 800; //屏幕高度 const double PI = 3.1426535159; //圆周率 const double e = 2.71828; //自然数e const double averag_distance = 0.162; //弧度以0.01增长时,原始参数方程每个点的平均距离 const int quantity = 506; //一个完整爱心所需点的数量 const int circles = 210; //组成爱心主体的爱心个数(每个爱心会乘以不同系数) const int frames = 20; //爱心扩张一次的帧数 Point origin_points[quantity]; //创建一个保存原始爱心数据的数组 Point points[circles * quantity]; //创建一个保存所有爱心数据的数组 IMAGE images[frames]; //创建图片数组 //坐标转换函数 double screen_x(double x) { x += xScreen / 2; return x; } //坐标转换函数 double screen_y(double y) { y = -y + yScreen / 2; return y; } //创建x1-x2的随机数的函数 int creat_random(int x1, int x2) { if (x2 > x1) return rand() % (x2 - x1 + 1) + x1; else return 0; } //创建爱心扩张一次的全部数据,并绘制成20张图片保存 // 1 用参数方程计算出一个爱心的所有坐标并保存在 origin_points 中 // 2 重复对 origin_points 的所有坐标乘上不同的系数获得一个完整的爱心坐标数据,并保存在 points 中 // 3 通过一些数学逻辑计算 points 中所有点扩张后的坐标并绘制,并覆盖掉原来的数据(循环20次) // 4 计算圆的外层那些闪动的点,不保存这些点的数据(循环20次) void creat_data() { int index = 0; //保存相邻的坐标信息以便用于计算距离 double x1 = 0, y1 = 0, x2 = 0, y2 = 0; for (double radian = 0.1; radian <= 2 * PI; radian += 0.005) { //爱心的参数方程 x2 = 16 * pow(sin(radian), 3); y2 = 13 * cos(radian) - 5 * cos(2 * radian) - 2 * cos(3 * radian) - cos(4 * radian); //计算两点之间的距离 开根号((x1-x2)平方 + (y1-y1)平方) double distance = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); //只有当两点之间的距离大于平均距离才保存这个点,否则跳过这个点 if (distance > averag_distance) { //x1和y1保留当前数据 //x2和y2将在下一次迭代获得下一个点的坐标 x1 = x2, y1 = y2; origin_points[index].x = x2; origin_points[index++].y = y2; } } index = 0; for (double size = 0.1; size <= 20; size += 0.1) { //用sigmoid函数计算当前系数的成功概率 //用个例子说明一下,假设有100个点成功概率为 90%,那么就可能会有90个点经过筛选保留下来 // 假设有100个点成功概率为 20%,那么就可能会有20个点经过筛选保留下来 double success_p = 1 / (1 + pow(e, 8 - size / 2)); //遍历所有原始数据 for (int i = 0; i < quantity; ++i) { //用概率进行筛选 if (success_p > creat_random(0, 100) / 100.0) { //从颜色数组随机获得一个颜色 points[index].color = colors[creat_random(0, 6)]; //对原始数据乘上系数保存在points中 points[index].x = size * origin_points[i].x + creat_random(-4, 4); points[index++].y = size * origin_points[i].y + creat_random(-4, 4); } } } //index当前值就是points中保存了结构体的数量 int points_size = index; for (int frame = 0; frame < frames; ++frame) { //初始化每张图片宽xScreen,高yScreen images[frame] = IMAGE(xScreen, yScreen); //把第frame张图像设为当前工作图片 SetWorkingImage(&images[frame]); //计算爱心跳动的坐标 for (index = 0; index < points_size; ++index) { double x = points[index].x, y = points[index].y; //把当前值赋值给x和y double distance = sqrt(pow(x, 2) + pow(y, 2)); //计算当前点与原点的距离 double diatance_increase = -0.0009 * distance * distance + 0.35714 * distance + 5; //把当前距离代入方程获得该点的增长距离 //根据增长距离计算x轴方向的增长距离 x_increase = diatance_increase * cos(当前角度) //cos(当前角度)= x / distance double x_increase = diatance_increase * x / distance / frames; //根据增长距离计算x轴方向的增长距离 x_increase = diatance_increase * sin(当前角度) //sin(当前角度)= y / distance double y_increase = diatance_increase * y / distance / frames; //因为以上计算得到的是一整个过程的增长距离,而整个过程持续20帧,因此要除20 //用新的数据覆盖原来的数据 points[index].x += x_increase; points[index].y += y_increase; //提取当前点的颜色设置为绘画颜色 setfillcolor(points[index].color); //注意,因为以上所有坐标是基于数学坐标的 //因此绘制到屏幕是就要转换为屏幕坐标 solidcircle(screen_x(points[index].x), screen_y(points[index].y), 1); } //产生外围闪动的点 for (double size = 17; size < 23; size += 0.3) { for (index = 0; index < quantity; ++index) { //当系数大于等于20,通过概率为百分之四十,当系数小于20,通过概率为百分之五 //20作为关键值是因为爱心主体的最大系数就是20 if ((creat_random(0, 100) / 100.0 > 0.6 && size >= 20) || (size < 20 && creat_random(0, 100) / 100.0 > 0.95)) { double x, y; if (size >= 20) { //用frame的平方的正负值作为上下限并加减15产生随机数 //用frame的平方的好处是frame越大,外围闪动的点运动范围越大 x = origin_points[index].x * size + creat_random(-frame * frame / 5 - 15, frame * frame / 5 + 15); y = origin_points[index].y * size + creat_random(-frame * frame / 5 - 15, frame * frame / 5 + 15); } else { //对于系数小于20的处理与爱心点一样 x = origin_points[index].x * size + creat_random(-5, 5); y = origin_points[index].y * size + creat_random(-5, 5); } //随机获取颜色并设置为当前绘图颜色 setfillcolor(colors[creat_random(0, 6)]); //把数学坐标转换为屏幕坐标再进行绘制 solidcircle(screen_x(x), screen_y(y), 1); //需要注意的是,我并没有保存这些点,因为这些点不需要前一帧的坐标数据 //只需要当前系数就可绘制出来,因此没 必要保存 } } } } } int main() { initgraph(xScreen, yScreen); //创建屏幕 BeginBatchDraw(); //开始批量绘图 srand(time(0)); //初始化随机种子 creat_data(); //调用函数产生20张图片 SetWorkingImage(); //调用函数把工作图像恢复为窗口,没有添加参数默认为窗口 //因为接下是用窗口播放图片,因此要把绘图效果设置为窗口 bool extend = true, shrink = false; for (int frame = 0; !_kbhit();) //退出条件为检测到按键信息 { putimage(0, 0, &images[frame]); //播放第frame张图片 FlushBatchDraw(); //刷新批量绘图 Sleep(20); //延时20毫秒 cleardevice(); //清除屏幕,用来播放下一帧图片 //注意 creat data 产生的只是爱心扩张的20张图片,并没有产生爱心收缩的图片 //但是把扩张的图片倒着播放就产生的收缩的效果 //所以下面这个 if else 语句就是决定图片是正常播放还是倒着播放 if (extend) //扩张时, ++frame,正常播放 frame == 19 ? (shrink = true, extend = false) : ++frame; else //收缩时, --frame,倒着播放 frame == 0 ? (shrink = false, extend = true) : --frame; } EndBatchDraw(); //关闭批量绘图 closegraph(); //关闭绘图窗口 return 0; //结束程序 }
复制
python -1
import random from math import sin, cos, pi, log from tkinter import * CANVAS_WIDTH = 640 # 画布的宽 CANVAS_HEIGHT = 480 # 画布的高 CANVAS_CENTER_X = CANVAS_WIDTH / 2 # 画布中心的X轴坐标 CANVAS_CENTER_Y = CANVAS_HEIGHT / 2 # 画布中心的Y轴坐标 IMAGE_ENLARGE = 11 # 放大比例 HEART_COLOR = "#ff6781" # 心的颜色,这个是粉红 def heart_function(t, shrink_ratio: float = IMAGE_ENLARGE): """ “爱心函数生成器” :param shrink_ratio: 放大比例 :param t: 参数 :return: 坐标 """ # 基础函数 x = 16 * (sin(t) ** 3) y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t)) # 放大 x *= shrink_ratio y *= shrink_ratio # 移到画布中央 x += CANVAS_CENTER_X y += CANVAS_CENTER_Y return int(x), int(y) def scatter_inside(x, y, beta=0.15): """ 随机内部扩散 :param x: 原x :param y: 原y :param beta: 强度 :return: 新坐标 """ ratio_x = - beta * log(random.random()) ratio_y = - beta * log(random.random()) dx = ratio_x * (x - CANVAS_CENTER_X) dy = ratio_y * (y - CANVAS_CENTER_Y) return x - dx, y - dy def shrink(x, y, ratio): """ 抖动 :param x: 原x :param y: 原y :param ratio: 比例 :return: 新坐标 """ force = -1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.6) # 这个参数... dx = ratio * force * (x - CANVAS_CENTER_X) dy = ratio * force * (y - CANVAS_CENTER_Y) return x - dx, y - dy def curve(p): """ 自定义曲线函数,调整跳动周期 :param p: 参数 :return: 正弦 """ # 可以尝试换其他的动态函数,达到更有力量的效果(贝塞尔?) return 2 * (2 * sin(4 * p)) / (2 * pi) class Heart: """ 爱心类 """ def __init__(self, generate_frame=20): self._points = set() # 原始爱心坐标集合 self._edge_diffusion_points = set() # 边缘扩散效果点坐标集合 self._center_diffusion_points = set() # 中心扩散效果点坐标集合 self.all_points = {} # 每帧动态点坐标 self.build(2000) self.random_halo = 1000 self.generate_frame = generate_frame for frame in range(generate_frame): self.calc(frame) def build(self, number): # 爱心 for _ in range(number): t = random.uniform(0, 2 * pi) # 随机不到的地方造成爱心有缺口 x, y = heart_function(t) self._points.add((x, y)) # 爱心内扩散 for _x, _y in list(self._points): for _ in range(3): x, y = scatter_inside(_x, _y, 0.05) self._edge_diffusion_points.add((x, y)) # 爱心内再次扩散 point_list = list(self._points) for _ in range(4000): x, y = random.choice(point_list) x, y = scatter_inside(x, y, 0.17) self._center_diffusion_points.add((x, y)) @staticmethod def calc_position(x, y, ratio): # 调整缩放比例 force = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520) # 魔法参数 dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1) dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1) return x - dx, y - dy def calc(self, generate_frame): ratio = 10 * curve(generate_frame / 10 * pi) # 圆滑的周期的缩放比例 halo_radius = int(4 + 6 * (1 + curve(generate_frame / 10 * pi))) halo_number = int(3000 + 4000 * abs(curve(generate_frame / 10 * pi) ** 2)) all_points = [] # 光环 heart_halo_point = set() # 光环的点坐标集合 for _ in range(halo_number): t = random.uniform(0, 2 * pi) # 随机不到的地方造成爱心有缺口 x, y = heart_function(t, shrink_ratio=11.6) # 魔法参数 x, y = shrink(x, y, halo_radius) if (x, y) not in heart_halo_point: # 处理新的点 heart_halo_point.add((x, y)) x += random.randint(-14, 14) y += random.randint(-14, 14) size = random.choice((1, 2, 2)) all_points.append((x, y, size)) # 轮廓 for x, y in self._points: x, y = self.calc_position(x, y, ratio) size = random.randint(1, 3) all_points.append((x, y, size)) # 内容 for x, y in self._edge_diffusion_points: x, y = self.calc_position(x, y, ratio) size = random.randint(1, 2) all_points.append((x, y, size)) for x, y in self._center_diffusion_points: x, y = self.calc_position(x, y, ratio) size = random.randint(1, 2) all_points.append((x, y, size)) self.all_points[generate_frame] = all_points def render(self, render_canvas, render_frame): for x, y, size in self.all_points[render_frame % self.generate_frame]: render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=HEART_COLOR) def draw(main: Tk, render_canvas: Canvas, render_heart: Heart, render_frame=0): render_canvas.delete('all') render_heart.render(render_canvas, render_frame) main.after(160, draw, main, render_canvas, render_heart, render_frame + 1) if __name__ == '__main__': root = Tk() # 一个Tk canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH) canvas.pack() heart = Heart() # 心 draw(root, canvas, heart) # 开始画画~ root.mainloop()
复制
python -2
所需环境 open cv
from tkinter import * from matplotlib import pyplot as plt from PIL import Image import random import math import numpy as np import os import colorsys import cv2 from scipy.ndimage.filters import gaussian_filter from math import sin, cos, pi, log canvas_width = 600 canvas_height = 600 world_width = 0.05 world_heigth = 0.05 # 中间心的参数 points = None fixed_point_size = 20000 fixed_scale_range = (4, 4.3) min_scale = np.array([1.0, 1.0, 1.0]) * 0.9 max_scale = np.array([1.0, 1.0, 1.0]) * 0.9 min_heart_scale = -15 max_heart_scale = 16 # 外围随机心参数 random_point_szie = 7000 random_scale_range = (3.5, 3.9) random_point_maxvar = 0.2 # 心算法参数 mid_point_ignore = 0.95 # 相机参数 camera_close_plane = 0.1 camera_position = np.array([0.0, -2.0, 0.0]) # 点的颜色 hue = 0.92 color_strength = 255 # 常用向量缓存 zero_scale = np.array([0.0, 0.0, 0.0]) unit_scale = np.array([1.0, 1.0, 1.0]) color_white = np.array([255, 255, 255]) axis_y = np.array([0.0, 1.0, 0.0]) # 渲染缓存 render_buffer = np.empty((canvas_width, canvas_height, 3), dtype=int) strength_buffer = np.empty((canvas_width, canvas_height), dtype=float) # 随机点文件缓存 points_file = "temp.txt" # 渲染结果 total_frames = 30 output_dir = "./output" # 格式 image_fmt = "jpg" def color(value): digit = list(map(str, range(10))) + list("ABCDEF") string = '#' for i in value: a1 = i // 16 a2 = i % 16 string += digit[a1] + digit[a2] return string def heart_func(x, y, z, scale): bscale = scale bscale_half = bscale / 2 x = x * bscale - bscale_half y = y * bscale - bscale_half z = z * bscale - bscale_half return (x ** 2 + 9 / 4 * (y ** 2) + z ** 2 - 1) ** 3 - (x ** 2) * (z ** 3) - 9 / 200 * (y ** 2) * (z ** 3) def lerp_vector(a, b, ratio): result = a.copy() for i in range(3): result[i] = a[i] + (b[i] - a[i]) * ratio return result def lerp_int(a, b, ratio): return (int)(a + (b - a) * ratio) def lerp_float(a, b, ratio): return (a + (b - a) * ratio) def distance(point): return (point[0] ** 2 + point[1] ** 2 + point[2] ** 2) ** 0.5 def dot(a, b): return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] def inside_rand(tense): x = random.random() y = -tense * math.log(x) return y # 生成中间心 def genPoints(pointCount, heartScales): result = np.empty((pointCount, 3)) index = 0 while index < pointCount: # 生成随机点 x = random.random() y = random.random() z = random.random() # 扣掉心中间的点 mheartValue = heart_func(x, 0.5, z, heartScales[1]) mid_ignore = random.random() if mheartValue < 0 and mid_ignore < mid_point_ignore: continue heartValue = heart_func(x, y, z, heartScales[0]) z_shrink = 0.01 sz = z - z_shrink sheartValue = heart_func(x, y, sz, heartScales[1]) # 保留在心边上的点 if heartValue < 0 and sheartValue > 0: result[index] = [x - 0.5, y - 0.5, z - 0.5] # 向内扩散 len = 0.7 result[index] = result[index] * (1 - len * inside_rand(0.2)) # 重新赋予深度 newY = random.random() - 0.5 rheartValue = heart_func(result[index][0] + 0.5, newY + 0.5, result[index][2] + 0.5, heartScales[0]) if rheartValue > 0: continue result[index][1] = newY # 删掉肚脐眼 dist = distance(result[index]) if dist < 0.12: continue index = index + 1 if index % 100 == 0: print("{ind} generated {per}%".format(ind=index, per=((index / pointCount) * 100))) return result # 生成随机心 def genRandPoints(pointCount, heartScales, maxVar, ratio): result = np.empty((pointCount, 3)) index = 0 while index < pointCount: x = random.random() y = random.random() z = random.random() mheartValue = heart_func(x, 0.5, z, heartScales[1]) mid_ignore = random.random() if mheartValue < 0 and mid_ignore < mid_point_ignore: continue heartValue = heart_func(x, y, z, heartScales[0]) sheartValue = heart_func(x, y, z, heartScales[1]) if heartValue < 0 and sheartValue > 0: result[index] = [x - 0.5, y - 0.5, z - 0.5] dist = distance(result[index]) if dist < 0.12: continue len = 0.7 result[index] = result[index] * (1 - len * inside_rand(0.2)) index = index + 1 for i in range(pointCount): var = maxVar * ratio randScale = 1 + random.normalvariate(0, var) result[i] = result[i] * randScale return result # 世界坐标到相机本地坐标 def world_2_cameraLocalSapce(world_point): new_point = world_point.copy() new_point[1] = new_point[1] + camera_position[1] return new_point # 相机本地坐标到相机空间坐标 def cameraLocal_2_cameraSpace(cameraLocalPoint): depth = distance(cameraLocalPoint) cx = cameraLocalPoint[0] * (camera_close_plane / cameraLocalPoint[1]) cz = -cameraLocalPoint[2] * (cx / cameraLocalPoint[0]) cameraLocalPoint[0] = cx cameraLocalPoint[1] = cz return cameraLocalPoint, depth # 相机空间坐标到屏幕坐标 def camerSpace_2_screenSpace(cameraSpace): x = cameraSpace[0] y = cameraSpace[1] # convert to view space centerx = canvas_width / 2 centery = canvas_height / 2 ratiox = canvas_width / world_width ratioy = canvas_height / world_heigth viewx = centerx + x * ratiox viewy = canvas_height - (centery + y * ratioy) cameraSpace[0] = viewx cameraSpace[1] = viewy return cameraSpace.astype(int) # 绘制世界坐标下的点 def draw_point(worldPoint): cameraLocal = world_2_cameraLocalSapce(worldPoint) cameraSpsace, depth = cameraLocal_2_cameraSpace(cameraLocal) screeSpace = camerSpace_2_screenSpace(cameraSpsace) draw_size = int(random.random() * 3 + 1) draw_on_buffer(screeSpace, depth, draw_size) # 绘制到缓存上 def draw_on_buffer(screenPos, depth, draw_size): if draw_size == 0: return elif draw_size == 1: draw_point_on_buffer(screenPos[0], screenPos[1], color_strength, depth) elif draw_size == 2: draw_point_on_buffer(screenPos[0], screenPos[1], color_strength, depth) draw_point_on_buffer(screenPos[0] + 1, screenPos[1] + 1, color_strength, depth) elif draw_size == 3: draw_point_on_buffer(screenPos[0], screenPos[1], color_strength, depth) draw_point_on_buffer(screenPos[0] + 1, screenPos[1] + 1, color_strength, depth) draw_point_on_buffer(screenPos[0] + 1, screenPos[1], color_strength, depth) elif draw_size == 4: draw_point_on_buffer(screenPos[0], screenPos[1], color_strength, depth) draw_point_on_buffer(screenPos[0] + 1, screenPos[1], color_strength, depth) draw_point_on_buffer(screenPos[0], screenPos[1] + 1, color_strength, depth) draw_point_on_buffer(screenPos[0] + 1, screenPos[1] + 1, color_strength, depth) # 根据色调和颜色强度获取颜色 def get_color(strength): result = None if strength >= 1: result = colorsys.hsv_to_rgb(hue, 2 - strength, 1) else: result = colorsys.hsv_to_rgb(hue, 1, strength) r = min(result[0] * 256, 255) g = min(result[1] * 256, 255) b = min(result[2] * 256, 255) return np.array((r, g, b), dtype=int) # 可以根据深度做一些好玩的 def draw_point_on_buffer(x, y, color, depth): if x < 0 or x >= canvas_width or y < 0 or y >= canvas_height: return # 混合 strength = float(color) / 255 strength_buffer[x, y] = strength_buffer[x, y] + strength # 绘制缓存 def draw_buffer_on_canvas(output=None): render_buffer.fill(0) for i in range(render_buffer.shape[0]): for j in range(render_buffer.shape[1]): render_buffer[i, j] = get_color(strength_buffer[i, j]) im = Image.fromarray(np.uint8(render_buffer)) im = im.rotate(-90) if output is None: plt.imshow(im) plt.show() else: im.save(output) def paint_heart(ratio, randratio, outputFile=None): global strength_buffer global render_buffer global points # 清空缓存 strength_buffer.fill(0) for i in range(fixed_point_size): # 缩放 point = points[i] * lerp_vector(min_scale, max_scale, ratio) # 球型场 dist = distance(point) radius = 0.4 sphere_scale = radius / dist point = point * lerp_float(0.9, sphere_scale, ratio * 0.3) # 绘制 draw_point(point) # 生成一组随机点 randPoints = genRandPoints(random_point_szie, random_scale_range, random_point_maxvar, randratio) for i in range(random_point_szie): # 绘制 draw_point(randPoints[i]) # 高斯模糊 for i in range(1): strength_buffer = gaussian_filter(strength_buffer, sigma=0.8) # 绘制缓存 draw_buffer_on_canvas(outputFile) def show_images(): img = None for i in range(total_frames): save_name = "{name}.{fmt}".format(name=i, fmt=image_fmt) save_path = os.path.join(output_dir, save_name) img = cv2.imread(save_path, cv2.IMREAD_ANYCOLOR) cv2.imshow("Img", img) cv2.waitKey(25) def gen_images(): global points if not os.path.isdir(output_dir): os.mkdir(output_dir) # 尝试加载或生成中间心 if not os.path.exists(points_file): print("未发现缓存点,重新生成中") points = genPoints(fixed_point_size, fixed_scale_range) np.savetxt(points_file, points) else: print("发现缓存文件,跳过生成") points = np.loadtxt(points_file) for i in range(total_frames): print("正在处理图片... ", i) frame_ratio = float(i) / (total_frames - 1) frame_ratio = frame_ratio ** 2 ratio = math.sin(frame_ratio * math.pi) * 0.743144 randratio = math.sin(frame_ratio * math.pi * 2 + total_frames / 2) save_name = "{name}.{fmt}".format(name=i, fmt=image_fmt) save_path = os.path.join(output_dir, save_name) paint_heart(ratio, randratio, save_path) print("图片已保存至", save_path) if __name__ == "__main__": gen_images() while True: show_images()
复制