"""Line2D and Polygon2D -- 2D shape rendering nodes."""
from ..descriptors import Property
from ..math.types import Vec2
from ..properties import Colour
from .node2d import Node2D
[docs]
class Line2D(Node2D):
"""Anti-aliased polyline with configurable width and colour.
Stores a list of (x, y) points and draws connected line segments.
Supports joint modes, end caps, and gradient colouring along the line.
"""
points = Property((), hint="List of (x, y) tuples")
width = Property(2.0, range=(0.1, 1000.0), hint="Line width in pixels")
colour = Colour((1.0, 1.0, 1.0, 1.0))
joint_mode = Property("sharp", enum=["sharp", "bevel", "round"], hint="Joint style")
begin_cap_mode = Property("none", enum=["none", "round"], hint="Start cap style")
end_cap_mode = Property("none", enum=["none", "round"], hint="End cap style")
gradient = Property(None, hint="Optional list of (t, colour) for gradient along line")
gizmo_colour = Colour((0.2, 0.9, 0.4, 0.7))
[docs]
def draw(self, renderer):
"""Draw the polyline. Renderer must support draw_line()."""
pts = self.points
if len(pts) < 2:
return
# Apply full node transform (position + rotation + scale)
transformed = self.transform_points([Vec2(p[0], p[1]) for p in pts])
for i in range(len(transformed) - 1):
renderer.draw_line(
(transformed[i].x, transformed[i].y),
(transformed[i + 1].x, transformed[i + 1].y),
colour=self.colour, thickness=self.width,
)
[docs]
def get_gizmo_lines(self) -> list[tuple[Vec2, Vec2]]:
"""Return the polyline as connected line segments in world space."""
pts = self.points
if len(pts) < 2:
return []
transformed = self.transform_points([Vec2(p[0], p[1]) for p in pts])
return [(transformed[i], transformed[i + 1]) for i in range(len(transformed) - 1)]
[docs]
class Polygon2D(Node2D):
"""Filled polygon rendered from a list of vertices.
Vertices are in local space and transformed by the node's position,
rotation, and scale. Supports optional UV coordinates and texture.
"""
polygon = Property((), hint="List of (x, y) vertices")
colour = Colour((1.0, 1.0, 1.0, 1.0))
uv = Property((), hint="Optional UV coordinates per vertex")
texture = Property(None, hint="Texture source: file path, PNG bytes, or RGBA uint8 ndarray")
[docs]
def draw(self, renderer):
"""Draw the filled polygon. Renderer must support draw_polygon()."""
verts = self.polygon
if len(verts) < 3:
return
# Apply full node transform (position + rotation + scale)
transformed = self.transform_points([Vec2(v[0], v[1]) for v in verts])
renderer.draw_polygon([(t.x, t.y) for t in transformed], colour=self.colour)