Class: Geometry::Polyline
- Inherits:
-
Object
- Object
- Geometry::Polyline
- Defined in:
- lib/aurora-geometry/polyline.rb
Overview
A Polyline is like a Polygon in that it only contains straight lines, but also like a Path in that it isn’t necessarily closed.
http://en.wikipedia.org/wiki/Polyline
Usage
Direct Known Subclasses
Instance Attribute Summary collapse
-
#edges ⇒ Object
readonly
Returns the value of attribute edges.
-
#vertices ⇒ Object
readonly
Returns the value of attribute vertices.
Bisectors collapse
-
#bisectors ⇒ Array<Vector>
Generate the angle bisector unit vectors for each vertex.
-
#left_bisectors ⇒ Array<Vector>
Generate left-side angle bisector unit vectors for each vertex.
-
#right_bisectors ⇒ Array<Vector>
Generate right-side angle bisector unit vectors for each vertex.
-
#spokes ⇒ Array<Vector>
Generate the spokes for each vertex.
Instance Method Summary collapse
-
#close ⇒ Polyline
Clone the receiver, close it, then return it.
-
#close! ⇒ Polyline
Close the receiver and return it.
- #closed? ⇒ Bool
-
#eql?(other) ⇒ Bool
(also: #==)
Check the equality of two Polylines.
-
#initialize(*args) ⇒ Polyline
constructor
Construct a new Polyline from Points and/or Edges.
-
#offset(distance) ⇒ Polyline
(also: #leftset)
Offset the receiver by the specified distance.
-
#reverse ⇒ Polyline
Clone the receiver, reverse it, then return it.
-
#reverse! ⇒ Polyline
Reverse the receiver and return it.
-
#rightset(distance) ⇒ Polyline
Rightset the receiver by the specified distance.
Constructor Details
#initialize(Edge, Edge, ...) ⇒ Polyline #initialize(Point, Point, ...) ⇒ Polyline
The constructor will try to convert all of its arguments into Geometry::Points and Edges. Then successive Geometry::Points will be collpased into Edges. Successive Edges that share a common vertex will be added to the new Geometry::Polyline. If there’s a gap between Edges it will be automatically filled with a new Edge.
Construct a new Polyline from Points and/or Edges
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/aurora-geometry/polyline.rb', line 28 def initialize(*args) args.map! {|a| (a.is_a?(Array) || a.is_a?(Vector)) ? Point[a] : a} args.each {|a| raise ArgumentError, "Unknown argument type #{a.class}" unless a.is_a?(Point) or a.is_a?(Edge) } @edges = []; @vertices = []; first = args.shift if first.is_a?(Point) @vertices.push first elsif first.is_a?(Edge) @edges.push first @vertices.push *(first.to_a) end args.reduce(@vertices.last) do |previous,n| if n.is_a?(Point) if n == previous # Ignore repeated Points previous else if @edges.last new_edge = Edge.new(previous, n) if @edges.last.parallel?(new_edge) popped_edge = @edges.pop # Remove the previous Edge @vertices.pop(@edges.size ? 1 : 2) # Remove the now unused vertex, or vertices if n == popped_edge.first popped_edge.first else push_edge Edge.new(popped_edge.first, n) push_vertex popped_edge.first push_vertex n n end else push_edge Edge.new(previous, n) push_vertex n n end else push_edge Edge.new(previous, n) push_vertex n n end end elsif n.is_a?(Edge) if previous == n.first push_edge n push_vertex n.last elsif previous == n.last push_edge n.reverse! push_vertex n.last else e = Edge.new(previous, n.first) push_edge e, n push_vertex *(e.to_a), *(n.to_a) end n.last end end end |
Instance Attribute Details
#edges ⇒ Object (readonly)
Returns the value of attribute edges.
16 17 18 |
# File 'lib/aurora-geometry/polyline.rb', line 16 def edges @edges end |
#vertices ⇒ Object (readonly)
Returns the value of attribute vertices.
16 17 18 |
# File 'lib/aurora-geometry/polyline.rb', line 16 def vertices @vertices end |
Instance Method Details
#bisectors ⇒ Array<Vector>
If the Geometry::Polyline isn’t closed (the normal case), then the first and last vertices will be given bisectors that are perpendicular to themselves.
Generate the angle bisector unit vectors for each vertex
136 137 138 139 |
# File 'lib/aurora-geometry/polyline.rb', line 136 def bisectors # Multiplying each bisector by the sign of k flips any bisectors that aren't pointing towards the interior of the angle bisector_map {|b, k| k <=> 0 } end |
#close ⇒ Polyline
Clone the receiver, close it, then return it
99 100 101 |
# File 'lib/aurora-geometry/polyline.rb', line 99 def close clone.close! end |
#close! ⇒ Polyline
Close the receiver and return it
105 106 107 108 |
# File 'lib/aurora-geometry/polyline.rb', line 105 def close! push_edge Edge.new(@edges.last.last, @edges.first.first) unless @edges.empty? || closed? self end |
#closed? ⇒ Bool
Check to see if the Geometry::Polyline is closed (ie. is it a Geometry::Polygon?)
112 113 114 |
# File 'lib/aurora-geometry/polyline.rb', line 112 def closed? @edges.last.last == @edges.first.first end |
#eql?(other) ⇒ Bool Also known as: ==
Check the equality of two Geometry::Polylines. Note that if two Geometry::Polylines have
opposite winding, but are otherwise identical, they will be considered unequal.
92 93 94 |
# File 'lib/aurora-geometry/polyline.rb', line 92 def eql?(other) @vertices.zip(other.vertices).all? {|a,b| a == b} end |
#left_bisectors ⇒ Array<Vector>
This is similar to the #bisector method, but generates vectors that always point to the left side of the Geometry::Polyline instead of towards the inside of each corner
Generate left-side angle bisector unit vectors for each vertex
144 145 146 |
# File 'lib/aurora-geometry/polyline.rb', line 144 def left_bisectors bisector_map end |
#offset(distance) ⇒ Polyline Also known as: leftset
A positive distance will offset to the left, and a negative distance to the right.
Offset the receiver by the specified distance
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/aurora-geometry/polyline.rb', line 170 def offset(distance) bisector_pairs = if closed? bisector_edges = offset_bisectors(distance) bisector_edges.push(bisector_edges.first).each_cons(2) else offset_bisectors(distance).each_cons(2) end # Create the offset edges and then wrap them in Hashes so the edges # can be altered while walking the array active_edges = edges.zip(bisector_pairs).map do |e,offset| offset_edge = Edge.new(e.first+offset.first.vector, e.last+offset.last.vector) # Skip zero-length edges {:edge => (offset_edge.first == offset_edge.last) ? nil : offset_edge} end # Walk the array and handle any intersections for i in 0..(active_edges.count-1) do e1 = active_edges[i][:edge] next unless e1 # Ignore deleted edges intersection, j = find_last_intersection(active_edges, i, e1) if intersection e2 = active_edges[j][:edge] if intersection.is_a? Point active_edges[i][:edge] = Edge.new(e1.first, intersection) active_edges[j][:edge] = Edge.new(intersection, e2.last) else # Handle the collinear case active_edges[i][:edge] = Edge.new(e1.first, e2.last) active_edges[j].delete(:edge) end # Delete everything between e1 and e2 for k in i..j do next if (k==i) or (k==j) # Exclude e1 and e2 active_edges[k].delete(:edge) end redo # Recheck the modified edges end end Polyline.new *(active_edges.map {|e| e[:edge]}.compact.map {|e| [e.first, e.last]}.flatten) end |
#reverse ⇒ Polyline
Clone the receiver, reverse it, then return it
118 119 120 |
# File 'lib/aurora-geometry/polyline.rb', line 118 def reverse self.class.new *(edges.reverse.map! {|edge| edge.reverse! }) end |
#reverse! ⇒ Polyline
Reverse the receiver and return it
124 125 126 127 128 |
# File 'lib/aurora-geometry/polyline.rb', line 124 def reverse! vertices.reverse! edges.reverse!.map! {|edge| edge.reverse! } self end |
#right_bisectors ⇒ Array<Vector>
This is similar to the #bisector method, but generates vectors that always point to the right side of the Geometry::Polyline instead of towards the inside of each corner
Generate right-side angle bisector unit vectors for each vertex
151 152 153 |
# File 'lib/aurora-geometry/polyline.rb', line 151 def right_bisectors bisector_map {|b, k| -1 } end |
#rightset(distance) ⇒ Polyline
Rightset the receiver by the specified distance
220 221 222 |
# File 'lib/aurora-geometry/polyline.rb', line 220 def rightset(distance) offset(-distance) end |
#spokes ⇒ Array<Vector>
If the Geometry::Polyline isn’t closed (the normal case), then the first and last vertices will be given bisectors that are perpendicular to themselves.
Generate the spokes for each vertex. A spoke is the same as a bisector, but in the oppostire direction (bisectors point towards the inside of each corner; spokes point towards the outside)
159 160 161 162 |
# File 'lib/aurora-geometry/polyline.rb', line 159 def spokes # Multiplying each bisector by the negated sign of k flips any bisectors that aren't pointing towards the exterior of the angle bisector_map {|b, k| 0 <=> k } end |