Hey @monomonnik
The problem is, that the rose is made of a single path and not two overlapping objects. I hoped there is some kind of a blend mode to clear overlapping colors.
habakuk
@habakuk
Best posts made by habakuk
Latest posts made by habakuk
-
RE: Even-Odd Fill Rule
-
Even-Odd Fill Rule
Subject: Help Needed with Even-Odd Fill Rule for Maurer Rose Animation
Hello DrawBot Community,
Me and my imaginary friend (AI) are reaching out for human intellignce once again. I'm currently working on creating an animated Moire Effect based on a Maurer Rose using DrawBot and have encountered an issue with applying the even-odd fill rule. The animation is supposed to alternate fills correctly to mimic the visual effect seen in examples like the one on this website. https://www.sqrt.ch/Buch/Maurer/maurerrosesanim.html However, doe to the missing even-odd filling rule, we haven't been able to achieve the desired effect.
Here's what I’ve tried so far:
Initial Attempt Without Even-Odd Fill Rule: (be carefull running this script, it takes ages to render. reduce the z variable to a low prime number)
# Parameters for the Maurer Rose n = 5 d = 1 z = 853 ms = 90 dStroke = 1 dFarbe = (0, 0, 1) # Blue stroke color cFarbe = (1, 0, 0) # Red fill color newDrawing() for frame in range(z): newPage(1010, 1010) frameDuration(ms / 1000) translate(width() / 2, height() / 2) fill(0) rect(-width() / 2, -height() / 2, width(), height()) path = BezierPath() for theta in range(z + 1): k = (theta * d * 2 * pi) / z r = -500 * sin(n * k) x = r * cos(k) y = r * sin(k) if theta == 0: path.moveTo((x, y)) else: path.lineTo((x, y)) path.closePath() fill(*cFarbe) drawPath(path) stroke(*dFarbe) strokeWidth(dStroke) lineJoin('round') drawPath(path) d += 1 saveImage("maurer_rose_animation.gif") endDrawing()
Attempt Without Unsupported Methods:
# Draw the fill and stroke def draw_maurer_rose(d, n, z, dStroke, dFarbe, cFarbe): path = BezierPath() for theta in range(z + 1): k = (theta * d * 2 * pi) / z r = -500 * sin(n * k) x = r * cos(k) y = r * sin(k) if theta == 0: path.moveTo((x, y)) else: path.lineTo((x, y)) path.closePath() fill(*cFarbe) drawPath(path) stroke(*dFarbe) strokeWidth(dStroke) lineJoin('round') drawPath(path) # Animation loop for frame in range(z): newPage(1010, 1010) frameDuration(ms / 1000) translate(width() / 2, height() / 2) fill(1) rect(-width() / 2, -height() / 2, width(), height()) draw_maurer_rose(d, n, z, dStroke, dFarbe, cFarbe) d += 1 saveImage("maurer_rose_animation.gif") endDrawing()
...despite several attempts, I haven't been able to achieve the desired even-odd fill rule effect. I would appreciate any guidance or suggestions on how to properly implement the even-odd fill rule for this animation in DrawBot.
Thank you in advance for your help!
-
RE: extracting anchor and control points in a variable font
Thank you @mmonomonnik ! Your sample code helped solving the issue I was facing with correctly visualizing the on-curve and off-curve points for a variable font.
Me and my imaginary friend now got the correct method for extracting and differentiating between on-curve and off-curve pointsand are able to correctly identifying and iterating through the segments of each contour. An important fix was ensuring that lines were drawn only between appropriate points, avoiding unnecessary connections that had previously cluttered the visualization.!
-
extracting anchor and control points in a variable font
Hi there
I have to reach out for real human natural intelligence - since the imaginary intelligence called AI is not able to help in this case. thank you in advance!Issue: Difficulty extracting and drawing anchor and control points in a variable font using DrawBot.
Font: RobotoFlex VariableFont
Initial situation:
I want to extract and draw the anchor and control points of a variable font. I tried different approaches to extracting and plotting the points but kept running into problems. Here are the details of the attempts and the errors encountered:Script 1
# Set up canvas canvas_width = 500 canvas_height = 500 txt = "H" variable_font_path = "/Users/tobiasulrich/Downloads/Roboto_Flex/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf" fontSize = 400 point_size = 10 # Größere Punktgröße für bessere Sichtbarkeit newPage(canvas_width, canvas_height) fill(1) # Weißer Hintergrund rect(0, 0, canvas_width, canvas_height) fill(0) # Schwarzer Text stroke(0) strokeWidth(1) # Create a FormattedString with the text and variable font formattedString = FormattedString(txt, font=variable_font_path, fontSize=fontSize) # Get the Bézier path of the text using FormattedString path = BezierPath() path.text(formattedString, (50, 50)) # Draw the text path drawPath(path) # Initialize lists to hold on-curve and off-curve points on_curve_points = [] off_curve_points = [] # Iterate through contours and segments to extract points output = "" for contour in path.contours: for segment in contour: # Debug print to check the structure of the segment print("Segment:", segment) if hasattr(segment, 'points'): if segment.type == 'moveTo': x, y = segment.points[0] output += f"moveTo: ({x}, {y})\n" on_curve_points.append((x, y)) elif segment.type == 'lineTo': x, y = segment.points[0] output += f"lineTo: ({x}, {y})\n" on_curve_points.append((x, y)) elif segment.type == 'curveTo': cp1 = segment.points[0] cp2 = segment.points[1] pt = segment.points[2] output += f"curveTo: control point 1: ({cp1[0]}, {cp1[1]}), control point 2: ({cp2[0]}, {cp2[1]}), on-curve point: ({pt[0]}, {pt[1]})\n" off_curve_points.append((cp1[0], cp1[1])) off_curve_points.append((cp2[0], cp2[1])) on_curve_points.append((pt[0], pt[1])) # Draw on-curve points fill(1, 0, 0) # Rot für on-curve Punkte stroke(None) for (x, y) in on_curve_points: print("Drawing on-curve point at:", x, y) oval(x - point_size / 2, y - point_size / 2, point_size, point_size) # Draw off-curve points fill(0, 1, 0) # Grün für off-curve Punkte stroke(None) for (x, y) in off_curve_points: print("Drawing off-curve point at:", x, y) oval(x - point_size / 2, y - point_size / 2, point_size, point_size) # Save the image saveImage("H_with_anchor_points.png") # Ausgabe der Koordinaten print(output)
Error
Traceback (most recent call last): File "<untitled>", line 35, in <module> AttributeError: 'list' object has no attribute 'type'
Script 2
# Set up canvas canvas_width = 500 canvas_height = 500 txt = "O" variable_font_path = "/Users/tobiasulrich/Downloads/Roboto_Flex/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf" fontSize = 400 point_size = 10 # Größere Punktgröße für bessere Sichtbarkeit newPage(canvas_width, canvas_height) fill(1) # Weißer Hintergrund rect(0, 0, canvas_width, canvas_height) fill(0) # Schwarzer Text stroke(0) strokeWidth(1) # Create a FormattedString with the text and variable font formattedString = FormattedString(txt, font=variable_font_path, fontSize=fontSize) # Get the Bézier path of the text using FormattedString path = BezierPath() path.text(formattedString, (50, 50)) # Draw the text path drawPath(path) # Initialize lists to hold on-curve and off-curve points on_curve_points = [] off_curve_points = [] # Iterate through contours and segments to extract points for contour in path.contours: for segment in contour: # Debug print to check the structure of the segment print("Segment:", segment) if hasattr(segment, 'points'): if segment.type == 'moveTo': x, y = segment.points[0] print("moveTo:", x, y) on_curve_points.append((x, y)) elif segment.type == 'lineTo': x, y = segment.points[0] print("lineTo:", x, y) on_curve_points.append((x, y)) elif segment.type == 'curveTo': cp1 = segment.points[0] cp2 = segment.points[1] pt = segment.points[2] print("curveTo:", cp1, cp2, pt) off_curve_points.append(cp1) off_curve_points.append(cp2) on_curve_points.append(pt) # Draw on-curve points fill(1, 0, 0) # Red for on-curve points stroke(None) for (x, y) in on_curve_points: print("Drawing on-curve point at:", x, y) oval(x - point_size / 2, y - point_size / 2, point_size, point_size) # Draw off-curve points fill(0, 1, 0) # Green for off-curve points stroke(None) for (x, y) in off_curve_points: print("Drawing off-curve point at:", x, y) oval(x - point_size / 2, y - point_size / 2, point_size, point_size) # Save the image saveImage("O_with_anchor_points.png")
Error: No error, but no points visible
Konsole
Segment: [(79.296875, 50.0)] Segment: [(81.25, 50.0)] Segment: [(81.25, 197.265625)] Segment: [(247.265625, 197.265625)] Segment: [(247.265625, 50.0)] Segment: [(249.21875, 50.0)] Segment: [(249.21875, 334.375)] Segment: [(247.265625, 334.375)] Segment: [(247.265625, 198.828125)] Segment: [(81.25, 198.828125)] Segment: [(81.25, 334.375)] Segment: [(79.296875, 334.375)]
Script 3
# Set up canvas canvas_width = 500 canvas_height = 500 txt = "H" variable_font_path = "/Library/Fonts/RobotoFlex-VariableFont_GRAD,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC,opsz,slnt,wdth,wght.ttf" font_size = 400 # Neue Seite erstellen und Hintergrund setzen newPage(canvas_width, canvas_height) fill(1) # Weißer Hintergrund rect(0, 0, canvas_width, canvas_height) fill(0) # Schwarzer Text # Schriftart setzen und prüfen, ob sie korrekt geladen wird font(variable_font_path) fontSize(font_size) # Alle Achsen der aktuellen Schriftart auflisten variations = listFontVariations() for axis, data in variations.items(): print(f"Axis: {axis}, Data: {data}") # Eine Variation der aktuellen Schriftart auswählen if 'wght' in variations: fontVariations(wght=500) # Create a FormattedString with the text and variable font formattedString = FormattedString(txt, font=variable_font_path, fontSize=font_size) # Get the Bézier path of the text using FormattedString path = BezierPath() path.text(formattedString, (50, 50)) # Initialize lists to hold on-curve and off-curve points on_curve_points = [] off_curve_points = [] # Iterate through contours and segments to extract points output = "" for contour in path.contours: for segment in contour: # Debug print to check the structure of the segment if hasattr(segment, 'points'): points = segment.points if segment.type == 'moveTo': x, y = points[0] output += f"moveTo: ({x}, {y})\n" on_curve_points.append((x, y)) elif segment.type == 'lineTo': x, y = points[0] output += f"lineTo: ({x}, {y})\n" on_curve_points.append((x, y)) elif segment.type == 'curveTo': cp1 = points[0] cp2 = points[1] pt = points[2] output += f"curveTo: control point 1: ({cp1[0]}, {cp1[1]}), control point 2: ({cp2[0]}, {cp2[1]}), on-curve point: ({pt[0]}, {pt[1]})\n" off_curve_points.append((cp1[0], cp1[1])) off_curve_points.append((cp2[0], cp2[1])) on_curve_points.append((pt[0], pt[1])) # Draw on-curve points fill(1, 0, 0) # Rot für on-curve Punkte stroke(None) for (x, y) in on_curve_points: print("Drawing on-curve point at:", x, y) oval(x - point_size / 2, y - point_size / 2, point_size, point_size) # Draw off-curve points fill(0, 1, 0) # Grün für off-curve Punkte stroke(None) for (x, y) in off_curve_points: print("Drawing off-curve point at:", x, y) oval(x - point_size / 2, y - point_size / 2, point_size, point_size) # Save the image saveImage("H_with_anchor_points.png") # Ausgabe der Koordinaten print(output)
Error
Traceback (most recent call last): File "<untitled>", line 42, in <module> AttributeError: 'list' object has no attribute 'type'
-
RE: How to mirror/flip a object?
Hallo @jo thanks alot - at the moment i use the lissajus only to create different nice looking loops. I changed the values as you suggested and of course it is working now and delivers a new nice looking loop.
I`d love to make some more loops with more "natural, subtle and slow" movements. I saw your great visualisations of the different variable font movements and hoped to create a custom path to do so - but i failed...if you like to play around with my very first 5 letter variable font (HABKU) you are very welcome. http://habaland.ch/images/habaroll8GX.ttf
i added the the plus and minus to avoid the font doing the whole move to the min and max, because the backgraound would be visible then. (but most likely i created only a mess ) and by the way, i hate the black circle i had to ad "behind the scene" - id love o have a cleaner solution.
...at the moment i am trying to figure out where to append the savedState() without messing everything up...
greetings from Bern
-
RE: How to mirror/flip a object?
# -------------------------- # imports import sys sys.path.append("..") from helper_functions import * # -------------------------- # settings p_w, p_h = 1000, 1000 margin = 40 dia = 4 steps = 600 # lissajous values a = 2 # 2, 3, 4 are decent values b = a + 1 delta = 0 # pi/2, pi/3, pi/4 f_name = "habaroll8" axes = ['wght', 'wdth'] # -------- axis1_min = listFontVariations(f_name)[axes[0]]['minValue'] axis1_def = listFontVariations(f_name)[axes[0]]['defaultValue'] axis1_max = listFontVariations(f_name)[axes[0]]['maxValue'] axis2_min = listFontVariations(f_name)[axes[1]]['minValue'] axis2_def = listFontVariations(f_name)[axes[1]]['defaultValue'] axis2_max = listFontVariations(f_name)[axes[1]]['maxValue'] axis_w = p_w - 2 * margin axis_h = p_h - 2 * margin def_x = map_val(axis1_def, axis1_min, axis1_max, 0, axis_w) def_y = map_val(axis2_def, axis2_min, axis2_max, 0, axis_h) # -------------------------- # functions def a_page(): newPage(p_w,p_h) fill(1) rect(0, 0, p_w, p_h) translate(margin, margin) fill(0.92, 0.90, 0.87) rect(0, 0, axis_w, axis_h) font(f_name) fontSize(820 ) # -------------------------- # Drawings pts = [] for st in range(steps): # newDrawing() a_page() angle = 2 * pi / steps * st x = .5 + .5 * sin( a * angle + delta ) y = .5 + .5 * sin( b * angle ) curr_axis1 = ip(axis1_min + 20, axis1_max - 20, x) curr_axis2 = ip(axis2_min + 20, axis2_max - 20, y) var_values = { axes[0] : curr_axis1, axes[1] : curr_axis2 } fontVariations(**var_values) #black ring to avoid the background "bleed through" fill(None) stroke(0) strokeWidth(60) oval(125, 95, 700, 700) # the black part (fake 3D) stroke(0) strokeWidth(4) fill(0) text('A', (axis_w/2, axis_h/8), align = 'center') # the pink blob letter stroke(None) fill(0.79, 0.52, 0.67) scale(x=1.25, y=1.25) translate(x=-95, y=-80) text('A', (axis_w/2, axis_h/8), align = 'center') # the blob shadow (would be great to have the shadow behind the pink blob!) fill(0) translate(-120, 110) scale(x=0.9, y=-.05) skew(25, 0) rotate(-3) text('A', (axis_w/2, axis_h/8), align = 'center') saveImage('lissajous_var_test12.gif')
-
RE: How to mirror/flip a object?
Hey @jo - thank you very much! That was the issue - damn, i am still in trouble with the the basics. Actually i am pretty stoked to have you here responding, because i am messing around with your code... i`d love to ad different lissajous curves to my blobbish letters, and i hoped changing the numbers (a = 2 # 2, 3, 4 are decent values) would do the trick - but it does not really change that much - sometimes even the loop is not longer working. Would you mind having a look at my codemess? (i mean, your code - and my mess )
-
RE: How to mirror/flip a object?
Hello @ricardov Yes, i tried negative scaling, but it gives no result. It gives no error, but there is also nothing happening...
-
RE: How to mirror/flip a object?
My goal is to draw a shadow, so I have to mirror the letter. (i achieved scaling, skewing, but not flipping)
newPage(1000, 1000) font('Skia') fontSize(600) fill(0.79, 0.52, 0.67) text('A', (300, 200)) fill(0) scale(x=1, y=0.05) text('A', (300, 800))
-
How to mirror/flip a object?
Hello World, i have a struggle on a very simple task - how can i mirror/flip a bezier path object (or a text) horizontal and vertical?
thanks in advance