Class: Ruby2D::Polyline
- Inherits:
-
Object
- Object
- Ruby2D::Polyline
- Includes:
- Renderable
- Defined in:
- lib/ruby2d/polyline.rb
Overview
A connected sequence of line segments. Stroke-only (no fill).
Set closed: true to connect the last point back to the first.
Constant Summary collapse
- MITER_LIMIT =
Miter-join limit, matching
R2D_MITER_LIMITin the C extension (the SVG default). A sharp corner's miter is clamped toMITER_LIMIT * stroke_width / 2. 4.0
Constants included from Interactive
Interactive::OBJECT_EVENTS, Interactive::OBJECT_EVENT_FILTER_PREDICATES
Instance Attribute Summary collapse
-
#closed ⇒ Object
Returns the value of attribute closed.
-
#rotate ⇒ Object
Returns the value of attribute rotate.
-
#stroke_width ⇒ Object
Returns the value of attribute stroke_width.
Attributes included from Renderable
#color, #padding_bottom, #padding_left, #padding_right, #padding_top, #visible, #x_align, #y_align, #z
Class Method Summary collapse
-
.render(points:, rotate: 0, rx: nil, ry: nil, color: nil, colour: nil, opacity: nil, stroke_width: 1, closed: false) ⇒ Object
Render a polyline without creating an instance.
Instance Method Summary collapse
-
#color=(c) ⇒ Object
The stroke color.
-
#contains?(x, y) ⇒ Boolean
Test whether (x, y) lies on the polyline's stroke.
- #height ⇒ Object
-
#initialize(points:, z: 0, rotate: 0, rx: nil, ry: nil, color: nil, colour: nil, opacity: nil, stroke_width: 1, closed: false, add: true, visible: true) ⇒ Polyline
constructor
Create a polyline points is an array of [x, y] pairs with N >= 2 vertices.
-
#opacity ⇒ Object
Get opacity.
-
#opacity=(value) ⇒ Object
Set opacity.
-
#points ⇒ Object
The vertices as an array of [x, y] pairs.
-
#rx ⇒ Object
Get the rotation center x coordinate.
-
#rx=(val) ⇒ Object
Set the rotation center x coordinate.
-
#ry ⇒ Object
Get the rotation center y coordinate.
-
#ry=(val) ⇒ Object
Set the rotation center y coordinate.
-
#vertex_count ⇒ Object
Number of vertices.
-
#width ⇒ Object
Bounding-box width and height (extent across all vertices).
-
#x ⇒ Object
Centroid x.
-
#x=(new_x) ⇒ Object
Set the centroid x coordinate, translating all vertices.
-
#y ⇒ Object
Centroid y.
-
#y=(new_y) ⇒ Object
Set the centroid y coordinate, translating all vertices.
Methods included from Renderable
#_alignment_anchor_dx, #_alignment_anchor_dy, #_apply_padding, #_extract_alignment, #_point_in_polygon?, #_point_on_segment?, #_require_numeric_position, #_resolve_alignment, #_unrotate, #_validate_dimensions, #add, #colour=, flatten_color, flatten_per_vertex, flatten_points, flatten_resolved_color, #hide, #padding=, #remove, resolve_color_or_default, resolve_single_color, #show
Methods included from Interactive
#_fire_event, #interactive?, #off, #on
Constructor Details
#initialize(points:, z: 0, rotate: 0, rx: nil, ry: nil, color: nil, colour: nil, opacity: nil, stroke_width: 1, closed: false, add: true, visible: true) ⇒ Polyline
Create a polyline points is an array of [x, y] pairs with N >= 2 vertices
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/ruby2d/polyline.rb', line 17 def initialize(points:, z: 0, rotate: 0, rx: nil, ry: nil, color: nil, colour: nil, opacity: nil, stroke_width: 1, closed: false, add: true, visible: true) raise ArgumentError, 'Polyline requires at least 2 points' if points.length < 2 raise ArgumentError, 'points must be an array of [x, y] pairs' \ unless points.all? { |p| p.is_a?(Array) && p.length == 2 } @coordinates = points.flat_map { |x, y| [x.to_f, y.to_f] } @z = z @rotate = rotate @_user_rx = rx @_user_ry = ry @stroke_width = stroke_width @closed = closed self.color = color || colour || 'white' self.opacity = opacity unless opacity.nil? @visible = visible self.add if add end |
Instance Attribute Details
#closed ⇒ Object
Returns the value of attribute closed.
9 10 11 |
# File 'lib/ruby2d/polyline.rb', line 9 def closed @closed end |
#rotate ⇒ Object
Returns the value of attribute rotate.
9 10 11 |
# File 'lib/ruby2d/polyline.rb', line 9 def rotate @rotate end |
#stroke_width ⇒ Object
Returns the value of attribute stroke_width.
9 10 11 |
# File 'lib/ruby2d/polyline.rb', line 9 def stroke_width @stroke_width end |
Class Method Details
.render(points:, rotate: 0, rx: nil, ry: nil, color: nil, colour: nil, opacity: nil, stroke_width: 1, closed: false) ⇒ Object
Render a polyline without creating an instance
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/ruby2d/polyline.rb', line 177 def self.render(points:, rotate: 0, rx: nil, ry: nil, color: nil, colour: nil, opacity: nil, stroke_width: 1, closed: false) Window.render_ready_check raise ArgumentError, 'Polyline requires at least 2 points' if points.length < 2 n = points.length coords = Renderable.flatten_points(points) pvs = Renderable.flatten_color(color || colour, n, opacity, label: self) if rotate != 0 ccx = 0.0; ccy = 0.0 n.times do |i| ccx += coords[i * 2] ccy += coords[i * 2 + 1] end ccx /= n ccy /= n coords = rotate_coords(coords, rotate, rx || ccx, ry || ccy) end Ext.stroke_path(coords, stroke_width, pvs, closed) if stroke_width > 0 end |
Instance Method Details
#color=(c) ⇒ Object
The stroke color. Accepts a single color or a Color::Set of
vertex_count colors (one per vertex) interpolated along the path.
143 144 145 146 |
# File 'lib/ruby2d/polyline.rb', line 143 def color=(c) @color = Renderable.resolve_color_or_default(c, vertex_count, label: self.class) @_stroke_cc = nil end |
#contains?(x, y) ⇒ Boolean
Test whether (x, y) lies on the polyline's stroke. Hit-tests against the exact shape the renderer draws — the ribbon between the outer and inner stroke outlines, with mitered joints and butt-capped open ends — so the clickable region matches the visible pixels, corners and all. A closed path joins at every vertex (no open ends).
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/ruby2d/polyline.rb', line 63 def contains?(x, y) return false unless @stroke_width.positive? x, y = _unrotate(x, y) if @rotate != 0 n = vertex_count outer, inner = compute_stroke_outline edges = @closed ? n : n - 1 edges.times do |i| j = (i + 1) % n # The renderer fills each edge as the quad outer[i] → inner[i] → # inner[j] → outer[j]; the point is on the stroke iff it lies inside any # of those quads. The miter outline makes the corners exact. oi = outer[i]; ii = inner[i] oj = outer[j]; ij = inner[j] return true if _point_in_polygon?( [oi[0], oi[1], ii[0], ii[1], ij[0], ij[1], oj[0], oj[1]], x, y ) end false end |
#height ⇒ Object
53 54 55 56 |
# File 'lib/ruby2d/polyline.rb', line 53 def height ys = @coordinates.each_slice(2).map(&:last) ys.max - ys.min end |
#opacity ⇒ Object
Get opacity. Returns the per-vertex array when set, otherwise the uniform alpha from the first vertex color.
172 173 174 |
# File 'lib/ruby2d/polyline.rb', line 172 def opacity @_per_vertex_opacity || @color&.opacity end |
#opacity=(value) ⇒ Object
Set opacity. Accepts a single value (applied to all vertices) or an array of per-vertex values (length must equal vertex_count).
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/ruby2d/polyline.rb', line 150 def opacity=(value) if value.is_a?(Array) n = vertex_count raise ArgumentError, "opacity array must have #{n} values, one for each vertex. #{value.length} were given." \ unless value.length == n # Clamp each entry to 0.0..1.0, matching the scalar path (Color#opacity=). # NaN can't be clamped (Float::NAN.clamp raises), so map it to 0.0 first. @_per_vertex_opacity = value.map do |v| f = v.to_f f = 0.0 if f.nan? f.clamp(0.0, 1.0) end else @_per_vertex_opacity = nil @color.opacity = value end @_stroke_cc = nil end |
#points ⇒ Object
The vertices as an array of [x, y] pairs
43 44 45 |
# File 'lib/ruby2d/polyline.rb', line 43 def points @coordinates.each_slice(2).to_a end |
#rx ⇒ Object
Get the rotation center x coordinate
122 123 124 |
# File 'lib/ruby2d/polyline.rb', line 122 def rx @_user_rx.nil? ? x : @_user_rx end |
#rx=(val) ⇒ Object
Set the rotation center x coordinate
132 133 134 |
# File 'lib/ruby2d/polyline.rb', line 132 def rx=(val) @_user_rx = val end |
#ry ⇒ Object
Get the rotation center y coordinate
127 128 129 |
# File 'lib/ruby2d/polyline.rb', line 127 def ry @_user_ry.nil? ? y : @_user_ry end |
#ry=(val) ⇒ Object
Set the rotation center y coordinate
137 138 139 |
# File 'lib/ruby2d/polyline.rb', line 137 def ry=(val) @_user_ry = val end |
#vertex_count ⇒ Object
Number of vertices
38 39 40 |
# File 'lib/ruby2d/polyline.rb', line 38 def vertex_count @coordinates.length / 2 end |
#width ⇒ Object
Bounding-box width and height (extent across all vertices)
48 49 50 51 |
# File 'lib/ruby2d/polyline.rb', line 48 def width xs = @coordinates.each_slice(2).map(&:first) xs.max - xs.min end |
#x ⇒ Object
Centroid x
84 85 86 87 88 89 |
# File 'lib/ruby2d/polyline.rb', line 84 def x sum = 0.0 n = vertex_count n.times { |i| sum += @coordinates[i * 2] } sum / n end |
#x=(new_x) ⇒ Object
Set the centroid x coordinate, translating all vertices
100 101 102 103 104 105 106 107 108 |
# File 'lib/ruby2d/polyline.rb', line 100 def x=(new_x) _require_numeric_position(:x, new_x) dx = new_x - x i = 0 while i < @coordinates.length @coordinates[i] += dx i += 2 end end |
#y ⇒ Object
Centroid y
92 93 94 95 96 97 |
# File 'lib/ruby2d/polyline.rb', line 92 def y sum = 0.0 n = vertex_count n.times { |i| sum += @coordinates[i * 2 + 1] } sum / n end |
#y=(new_y) ⇒ Object
Set the centroid y coordinate, translating all vertices
111 112 113 114 115 116 117 118 119 |
# File 'lib/ruby2d/polyline.rb', line 111 def y=(new_y) _require_numeric_position(:y, new_y) dy = new_y - y i = 1 while i < @coordinates.length @coordinates[i] += dy i += 2 end end |