0% found this document useful (0 votes)
12 views4 pages

Animated Heart Shape Generator in Python

This document defines a Heart class that generates and animates a heart shape on a Tkinter canvas. It initializes points on the heart curve and diffusion points around it. For each frame, it calculates new positions for the points and adds them to a dictionary of all points for that frame. The render method draws the points on the canvas from the all_points dictionary. The draw function continuously redraws the canvas by incrementing the frame number and calling render.

Uploaded by

linh
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views4 pages

Animated Heart Shape Generator in Python

This document defines a Heart class that generates and animates a heart shape on a Tkinter canvas. It initializes points on the heart curve and diffusion points around it. For each frame, it calculates new positions for the points and adds them to a dictionary of all points for that frame. The render method draws the points on the canvas from the all_points dictionary. The draw function continuously redraws the canvas by incrementing the frame number and calling render.

Uploaded by

linh
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

import random

from math import sin, cos, pi, log


from tkinter import *

CANVAS_WIDTH = 640
CANVAS_HEIGHT = 480
CANVAS_CENTER_X = CANVAS_WIDTH / 2
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2
IMAGE_ENLARGE = 11
HEART_COLOR = "#ff2121"

def heart_function(t, shrink_ratio: float = IMAGE_ENLARGE):

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):

ratio_x = - beta * log([Link]())


ratio_y = - beta * log([Link]())

dx = ratio_x * (x - CANVAS_CENTER_X)
dy = ratio_y * (y - CANVAS_CENTER_Y)

return x - dx, y - dy

def shrink(x, y, ratio):

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):

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 = {}
[Link](2000)

self.random_halo = 1000

self.generate_frame = generate_frame
for frame in range(generate_frame):
[Link](frame)

def build(self, number):


for _ in range(number):
t = [Link](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 = [Link](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) + [Link](-1,


1)
dy = ratio * force * (y - CANVAS_CENTER_Y) + [Link](-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 = [Link](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 += [Link](-14, 14)
y += [Link](-14, 14)
size = [Link]((1, 2, 2))
all_points.append((x, y, size))

for x, y in self._points:
x, y = self.calc_position(x, y, ratio)
size = [Link](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 = [Link](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 = [Link](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)
[Link](160, draw, main, render_canvas, render_heart,
render_frame + 1)

if __name__ == '__main__':
root = Tk()
canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT,
width=CANVAS_WIDTH)
[Link]()
heart = Heart()
draw(root, canvas, heart)
[Link]()

Common questions

Powered by AI

The canvas setup with parameters like CANVAS_WIDTH and CANVAS_HEIGHT (set to 640 and 480 respectively) sets the boundaries for the heart's display area, determining the maximum spatial extent within which points can be drawn. The canvas color is set to black ('bg'='black'), which contrasts with the 'HEART_COLOR' (#ff2121), enhancing the heart's visibility against the dark background. These parameters ensure that the heart is centered using CANVAS_CENTER_X and CANVAS_CENTER_Y, contributing to a balanced visual composition where the heart is dynamically animated yet remains within viewable bounds .

The 'shrink' method utilizes inverse distance weighting by computing a force based on the inverse distance from the canvas center, raised to the power of 0.6. This mathematical principle emphasizes stronger shrinking effects for points further from the center, simulating an inward contraction force. By applying this weighted force to points, the method alters animation dynamics by modifying point positioning in a non-linear manner. This can simulate effects like focused contraction or gradient scaling, impacting the heart’s perceived motion and structural cohesion in animation .

The 'calc_position' method adjusts the position of heart points by calculating a force vector that simulates an attractive or repulsive effect based on the inverse distance to the center of the canvas. The strength of this force is influenced by the 'ratio' parameter and a small random offset. By modifying points in this way, the method dynamically changes the positions of points to create more visually compelling animations that appear to expand, contract, or ripple based on the calculated forces. This is essential for generating smooth transitions between frames and ensuring that the visual representation of the heart is fluid and dynamic .

The heart function calculates the (x, y) coordinates using parametric equations for a heart shape: x = 16 * (sin(t) ** 3) and y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t)). These equations scale the sine and cosine functions to form the distinct lobed shape of a heart. The parameters include a time variable 't' which acts as an angle in radians, determining the position around the heart's perimeter when plotted. Additionally, a 'shrink_ratio' parameter is applied to enlarge or shrink the heart shape geometrically before translating it to the center of the canvas by adjusting its position based on CANVAS_CENTER_X and CANVAS_CENTER_Y .

Visual points for each frame are organized into a dictionary structure called 'all_points', with keys corresponding to frame numbers and values being lists of tuples representing point coordinates and sizes. This organization allows efficient access and management of point data for each frame, enabling the render method to draw each frame's visual representation sequentially and correctly. By storing frame-specific data this way, the animation is rendered smoothly, ensuring frames transition seamlessly without recomputing points unnecessarily, thus optimizing performance .

The 'render' method updates the visual display by iterating over the tuples in 'all_points' for the current frame. For each tuple, it extracts (x, y) coordinates and size, and draws a rectangle on the canvas using 'render_canvas.create_rectangle', with a fill color defined by 'HEART_COLOR'. By clearing the canvas with 'render_canvas.delete('all')' before drawing, it ensures only the current frame's points are displayed, creating the effect of animation as successive frames are drawn. This process allows for per-frame updates, maintaining smooth animations as the object state progresses .

The code employs several methods to enhance randomness and diffusion effects: 1) The 'scatter_inside' method introduces randomness in the placement of edge and center points by applying logarithmic scaling to random values, 2) Random selection of points for diffusion in both edge and center areas, and 3) Adding small random integer offsets to point coordinates in the 'calc_position' and during halo point generation. These techniques together create the impression of a diffuse glow and softening around the heart's edges, enhancing its organic appearance in animations .

The 'draw' function ensures continuous animation by using the 'after' method, which schedules the next frame's rendering to occur after a specified delay (160 ms). This creates a loop where the function calls itself with an incremented frame number, creating an ongoing sequence of render calls. The use of 'main.after' facilitates this looping by linking execution of the current frame to the trigger for the next, effectively maintaining an animated loop as long as the program continues to run .

The method 'scatter_inside' is used to create a diffusion effect by modifying the (x, y) coordinates calculated for the heart. It achieves this by introducing random deviations based on a logarithmic random scaling factor. The deviations dx and dy are calculated using a ratio derived from the logarithmic function and applied to the distance from the center (CANVAS_CENTER_X, CANVAS_CENTER_Y). This scattering creates a more randomized and distributed look around the heart's edge and center points, enhancing the visual complexity of the rendered shape .

The 'Heart' class utilizes the 'curve' function to determine the animation characteristics by mapping frame numbers to curve values. The function outputs values based on the sine of a multiple of π, modulating the animation's speed and intensity. This curve influences the 'ratio' in the 'calc' method, affecting how force is applied when adjusting point positions. By varying over frames, this creates dynamic visual effects such as pulsation and wave-like movements of the heart, significantly impacting how the heart's animation is perceived .

You might also like