toposhirt/cylinder_drawing_example.py

115 lines
3.4 KiB
Python

import cairocffi as cairo
import math
def draw_cylinder_at_xy(ctx: cairo.Context, x: int, y: int, cyl_width:int, cyl_height: int, top_ellipse_height: int, top_ellipse_color=(1,1,1)):
pat = cairo.LinearGradient(x, y, x + cyl_width, y)
pat.add_color_stop_rgb(0, 1, 1, 1) # White top
pat.add_color_stop_rgb(1, 0.2, 0.2, 1) # Blue bottom
# 1. Draw Bottom Ellipse (White)
ctx.set_line_width(1.0)
ctx.save()
ctx.translate(x + cyl_width / 2, y)
ctx.scale(1, top_ellipse_height / cyl_width ) # Ellipse scale
ctx.arc(0, 0, cyl_width / 2, 0, 2 * math.pi)
ctx.restore()
#ctx.set_source_rgb(1, 1, 1) # White
ctx.set_line_width(0.0)
ctx.set_source(pat)
ctx.fill_preserve()
#ctx.set_source_rgb(0, 0, 0)
#ctx.set_line_width(1)
ctx.stroke()
# 2. Draw the rectangle body
ctx.set_line_width(1.0)
ctx.rectangle(x, y, cyl_width, -cyl_height)
ctx.set_source(pat)
ctx.fill()
ctx.stroke()
# 3. Draw top Ellipse (White)
if True:
ctx.set_line_width(1.0)
ctx.save()
ctx.translate(x + cyl_width / 2, y-cyl_height)
ctx.scale(1, top_ellipse_height / (cyl_width / 2) * 0.5) # Ellipse scale
ctx.arc(0, 0, cyl_width / 2, 0, 2 * math.pi)
ctx.restore()
ctx.set_source_rgb(top_ellipse_color[0], top_ellipse_color[1], top_ellipse_color[2])
ctx.fill_preserve()
# Outline for better visibility
ctx.set_source_rgb(0, 0, 0)
ctx.set_line_width(1)
ctx.stroke()
def draw_cylinders(width, height, filename):
# Setup surface and context
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
ctx = cairo.Context(surface)
# White background
ctx.set_source_rgb(1, 1, 1)
ctx.paint()
# Cylinder dimensions
cyl_width = 80
cyl_height = 200
top_ellipse_height = 30
spacing = 50
# Starting position
start_x = 50
y = 50
for i in range(3):
x = start_x + i * (cyl_width + spacing)
# 1. Draw Side Gradient (Rect + Arc)
# Create a horizontal linear gradient: White (top) to Blue (bottom)
pat = cairo.LinearGradient(x, y, x+cyl_width, y)
pat.add_color_stop_rgb(0, 1, 1, 1) # White top
pat.add_color_stop_rgb(1, 0.2, 0.2, 1) # Blue bottom
# Draw the rectangle body
ctx.rectangle(x, y + top_ellipse_height / 2, cyl_width, cyl_height - top_ellipse_height / 2)
ctx.set_source(pat)
ctx.fill()
# 2. Draw Top Ellipse (White)
ctx.save()
ctx.translate(x + cyl_width / 2, y + top_ellipse_height / 2)
ctx.scale(1, top_ellipse_height / (cyl_width / 2) * 0.5) # Ellipse scale
ctx.arc(0, 0, cyl_width / 2, 0, 2 * math.pi)
ctx.restore()
ctx.set_source_rgb(1, 1, 1) # White
ctx.fill_preserve()
# Outline for better visibility
ctx.set_source_rgb(0, 0, 0)
ctx.set_line_width(1)
ctx.stroke()
# Save to PNG
surface.write_to_png(filename)
print(f"Saved {filename}")
if __name__ == "__main__":
surface = cairo.SVGSurface("cylinder.svg", 800, 800)
ctx = cairo.Context(surface)
ctx.set_source_rgb(0, 1, 0)
ctx.paint()
draw_cylinder_at_xy(ctx, 100,300, 50,150,10)
draw_cylinder_at_xy(ctx, 300,300, 60,110,10, top_ellipse_color=(0.9, 0.4, 0.7))
surface.write_to_png("cylinder.png")
print("Saved cylinder.png")
surface.finish()