Class: Geometry::Polyline
- Inherits:
-
Object
- Object
- Geometry::Polyline
- Defined in:
- lib/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.
Instance Method Summary collapse
-
#eql?(other) ⇒ Bool
(also: #==)
Check the equality of two Polylines.
- #initialize(*args) ⇒ Polyline constructor
-
#offset(distance) ⇒ Polygon
(also: #leftset)
Offset the receiver by the specified distance.
-
#rightset(distance) ⇒ Polygon
Rightset the receiver by the specified distance.
Constructor Details
#initialize(Edge, Edge, ...) ⇒ Polyline #initialize(Point, Point, ...) ⇒ Polyline
Construct a new Polyline from Points and/or Edges
The constructor will try to convert all of its arguments into {Point}s and
{Edge}s. Then successive {Point}s will be collpased into {Edge}s. Successive
{Edge}s that share a common vertex will be added to the new {Polyline}. If
there's a gap between {Edge}s it will be automatically filled with a new
{Edge}.
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/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/geometry/polyline.rb', line 16 def edges @edges end |
#vertices ⇒ Object (readonly)
Returns the value of attribute vertices.
16 17 18 |
# File 'lib/geometry/polyline.rb', line 16 def vertices @vertices end |
Instance Method Details
#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/geometry/polyline.rb', line 92 def eql?(other) @vertices.zip(other.vertices).all? {|a,b| a == b} end |
#offset(distance) ⇒ Polygon Also known as: leftset
Offset the receiver by the specified distance. A positive distance
will offset to the left, and a negative distance to the right.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/geometry/polyline.rb', line 101 def offset(distance) bisectors = offset_bisectors(distance) offsets = bisectors.each_cons(2).to_a # Create the offset edges and then wrap them in Hashes so the edges # can be altered while walking the array active_edges = edges.zip(offsets).map do |e,offset| offset = Edge.new(e.first+offset.first.vector, e.last+offset.last.vector) # Skip zero-length edges {:edge => (offset.first == offset.last) ? nil : offset} 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 |
#rightset(distance) ⇒ Polygon
Rightset the receiver by the specified distance
147 148 149 |
# File 'lib/geometry/polyline.rb', line 147 def rightset(distance) offset(-distance) end |