Module: TT::Edges

Defined in:
TT_Lib2/edges.rb

Overview

Collection of methods to manipulate sets of edges.

Since:

  • 2.5.0

Defined Under Namespace

Modules: Gaps

Class Method Summary collapse

Class Method Details

.common_vertex(edge1, edge2) ⇒ Sketchup::Vertex|Nil

Parameters:

  • edge1 (Sketchup::Edge)
  • edge2 (Sketchup::Edge)

Returns:

  • (Sketchup::Vertex|Nil)

Since:

  • 2.5.0



54
55
56
57
58
59
60
61
# File 'TT_Lib2/edges.rb', line 54

def self.common_vertex(edge1, edge2)
  for v1 in edge1.vertices
    for v2 in edge2.vertices
      return v1 if v1 == v2
    end
  end
  nil
end

.find_curves(entities, progress_in_ui = false) ⇒ Array<Array<Sketchup::Edge>>

Find continous sets of edges not part of faces. The result is an array of more arrays. Each sub-array contains a set of sorted edges.

Sub-arrays may contains arrays of only one edge.

Parameters:

  • entities (Array<Sketchup::Entity>)

Returns:

  • (Array<Array<Sketchup::Edge>>)

    An Array of Arrays.

Since:

  • 2.5.0



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'TT_Lib2/edges.rb', line 73

def self.find_curves( entities, progress_in_ui=false )
  cache = {} # Use Hash for quick lookups
  entities.each { |e|
    next unless e.is_a?( Sketchup::Edge ) && e.faces.empty?
    cache[e] = e
  }
  if progress_in_ui && progress_in_ui.is_a?( TT::Progressbar )
    progress = progress_in_ui
  else
    progress = TT::Progressbar.new( cache, 'Finding curves' )
  end
  curves = []
  until cache.empty?     
    curve = {} # Use Hash for quick lookups
    stack = [ cache.keys.first ]
    until stack.empty?
      # Fetch the next edges in the stack and add to the curve
      edge = stack.shift
      curve[edge] = edge
      cache.delete(edge)
      progress.next if progress_in_ui
      # Find next edges
      for v in edge.vertices
        vert_edges = v.edges
        next if vert_edges.size != 2
        for e in vert_edges
          stack << e unless curve.key?(e)
        end
      end
    end # until stack.empty?
    curves << self.sort( curve )
  end # until cache.empty?
  curves
end

.find_isolated_curves(entities) ⇒ Array<Array<Sketchup::Edge>>

Finds all sets of edges forming a curve not connected to any other geometry. Returns an array of sorted curves. (Curve = array of edges)

Parameters:

  • entities (Array<Sketchup::Entity>)

Returns:

  • (Array<Array<Sketchup::Edge>>)

    An Array of Arrays.

Since:

  • 2.5.0



116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'TT_Lib2/edges.rb', line 116

def self.find_isolated_curves(entities)
  source = entities.to_a
  curves = []
  until source.empty?
    entity = source.shift
    next unless entity.is_a?( Sketchup::Edge )
    connected = entity.all_connected
    source -= connected
    next unless connected.all? { |e| e.is_a?(Sketchup::Edge) }
    sorted_edges = self.sort( connected )
    curves << sorted_edges unless sorted_edges.nil?
  end
  return curves
end

.repair_splits(entities, progress_in_ui = false) ⇒ Integer

Attempts to merge colinear edges into one edge. Makes use of SketchUp's own healing feature. Based on repair_broken_lines.rb by Carlo Roosen 2004

If progress_in_ui is true then a TT::Progressbar object is used to give UI feedback to the user about the process.

If progress_in_ui is a TT::Progressbar object then that is used instead and .next is called for each entity.

Parameters:

  • entities (Array<Sketchup::Entity>)
  • progress_in_ui (Boolean|TT::Progressbar) (defaults to: false)

Returns:

  • (Integer)

    Number of splits repaired.

Since:

  • 2.5.0



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'TT_Lib2/edges.rb', line 147

def self.repair_splits( entities, progress_in_ui=false )
  temp_edges = []
  return 0 if entities.length == 0
  
  parent = entities[0].parent.entities

  if progress_in_ui && progress_in_ui.is_a?( TT::Progressbar )
    progress = progress_in_ui
  else
    progress = TT::Progressbar.new( entities, 'Repairing split edges' )
  end
  for e in entities.to_a
    next unless e.is_a?(Sketchup::Edge)

    progress.next if progress_in_ui
    
    for vertex in e.vertices
      next unless vertex.edges.length == 2
      # (?) Like coplanar faces - can one compare vectors like this? Or do one
      # have to check if all vertices lie on the same line?
      v1 = vertex.edges[0].line[1]
      v2 = vertex.edges[1].line[1]
      next unless v1.parallel?(v2)
      # To repair a broken edge a temporary edge is placed at their shared vertex.
      # This temporary edge is then later erased which causes the two edges to
      # merge.
      pt1 = vertex.position
      pt2 = pt1.clone
      pt2.x += rand(1000) / 100.0
      pt2.y += rand(1000) / 100.0
      pt2.z += rand(1000) / 100.0
      temp_edge = parent.add_line( pt1, pt2 )
      temp_edges << temp_edge unless temp_edge.nil?
    end
  end
  
  parent.erase_entities(temp_edges) unless temp_edges.empty?

  temp_edges.size
end

.sort(edges) ⇒ Array<Sketchup::Edge>

TODO:

Comment source

Sorts the given set of edges from start to end. If the edges form a loop an arbitrary start is picked.

Parameters:

  • edges (Array<Sketchup::Edge>)

Returns:

  • (Array<Sketchup::Edge>)

    Sorted set of edges.

Since:

  • 2.5.0



198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'TT_Lib2/edges.rb', line 198

def self.sort( edges )
  if edges.is_a?( Hash )
    self.sort_from_hash( edges )
  elsif edges.is_a?( Enumerable )
    lookup = {}
    for edge in edges
      lookup[edge] = edge
    end
    self.sort_from_hash( lookup )
  else
    raise ArgumentError, '"edges" argument must be a collection of edges.'
  end
end

.sort_from_hash(edges) ⇒ Array<Sketchup::Edge>

Sorts the given set of edges from start to end. If the edges form a loop an arbitrary start is picked.

Parameters:

  • edges (Hash)

    Sketchup::Edge as keys

Returns:

  • (Array<Sketchup::Edge>)

    Sorted set of edges.

Since:

  • 2.5.0



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'TT_Lib2/edges.rb', line 220

def self.sort_from_hash( edges )
  # Get starting edge - then trace the connected edges from either end.
  start_edge = edges.keys.first
  
  # Find the next left and right edge
  vertices = start_edge.vertices
  
  left = []
  for e in vertices.first.edges
    left << e if e != start_edge && edges[e]
  end
  
  right = []
  for e in vertices.last.edges
    right << e if e != start_edge && edges[e]
  end
  
  return nil if left.size > 1 || right.size > 1 # Check for forks
  left = left.first
  right = right.first
  
  # Sort edges from start to end
  sorted = [start_edge]
  
  # Right
  edge = right
  until edge.nil?
    sorted << edge
    connected = []
    for v in edge.vertices
      for e in v.edges
        connected << e if edges[e] && !sorted.include?(e)
      end
    end
    return nil if connected.size > 1 # Check for forks
    edge = connected.first
  end
  
  # Left
  unless sorted.include?( left ) # Fix: 2.6.0
    edge = left
    until edge.nil?
      sorted.unshift( edge )
      connected = []
      for v in edge.vertices
        for e in v.edges
          connected << e if edges[e] && !sorted.include?(e)
        end
      end
      return nil if connected.size > 1 # Check for forks
      edge = connected.first
    end
  end
  
  sorted
end

.sort_vertices(curve) ⇒ Array<Sketchup::Vertex>

Note:

The first vertex will also appear last if the curve forms a loop.

Takes a sorted set of edges and returns a sorted set of vertices. Use TT::Edges.sort to sort a set of edges.

Parameters:

  • curve (Array<Sketchup::Edge>)

    Set of sorted edge.

Returns:

  • (Array<Sketchup::Vertex>)

    Sorted set of vertices.

Since:

  • 2.5.0



287
288
289
290
291
292
293
294
295
296
297
298
# File 'TT_Lib2/edges.rb', line 287

def self.sort_vertices(curve)
  return curve[0].vertices if curve.size <= 1
  vertices = []
  # Find the first vertex.
  common = self.common_vertex( curve[0], curve[1] ) # (?) Errorcheck?
  vertices << curve[0].other_vertex( common )
  # Now the rest can be added.
  curve.each { |edge|
    vertices << edge.other_vertex(vertices.last) # (?) Errorcheck?
  }
  return vertices
end