Module: TT::Edges::Gaps

Defined in:
TT_Lib2/edges.rb

Overview

Collection of methods to find and repair small gaps and stray edges.

Since:

  • 2.5.0

Class Method Summary collapse

Class Method Details

.close(entities, vertex, result, epsilon) ⇒ Boolean

Pair with the results of TT::Edges::Gaps.find.

Parameters:

  • entities (Sketchup::Entities)

    Entities collection where the vertex belong to.

  • vertex (Sketchup::Vertex)
  • result (Hash)

    The returned hash from TT::Edges::Gaps.find.

  • epsilon (Length)

    The max distance for which the gap can be closed.

Returns:

  • (Boolean)

    Returns true if the gap was closed.

Since:

  • 2.5.0



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'TT_Lib2/edges.rb', line 317

def self.close( entities, vertex, result, epsilon )
  # 1. Closest projected open end
  data = result[:vertex_projected]
  if data[:dist] && data[:dist][0] + data[:dist][1] < epsilon
    pt1 = data[:point]
    pt2 = data[:point2]
    entities.add_line( vertex.position, pt1 )
    entities.add_line( pt1, pt2 )
    return true
  end
  # 2. Closest edge
  data = result[:edge]
  if data[:dist] && data[:dist] < epsilon
    entities.add_line( vertex.position, data[:point] )
    return true
  end
  # 3. Closest open vertex
  data = result[:vertex]
  if data[:dist] && data[:dist] < epsilon
    entities.add_line( vertex.position, data[:point] )
    return true
  end
  false
end

.close_all(entities, epsilon, erase_small_edges = false, progress_in_ui = false) ⇒ Integer

Tries to connect all open ended edges to other edges if the distance is less than epsilon. If an open-ended edge can't be connected it'll erase it if its length is less than epsilon.

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 (Sketchup::Entities|Array<Sketchup::Entity>)

    Entities to process.

  • epsilon (Length)

    The max distance for which the gap can be closed.

  • erase_small_edges (Boolean) (defaults to: false)

    If true it will erase all stray edges shorter than epsilon.

  • progress_in_ui (Boolean|TT::Progressbar) (defaults to: false)

Returns:

  • (Integer)

    Returns the number of fixes done.

Since:

  • 2.5.0



360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'TT_Lib2/edges.rb', line 360

def self.close_all( entities, epsilon, erase_small_edges=false, progress_in_ui=false )
  fixes = 0
  return fixes if entities.length == 0
  context = entities[0].parent.entities
  edges = entities.select { |e| e.is_a?( Sketchup::Edge ) }
  small_edges = []
  end_vertices = self.find_end_vertices( edges )
  if progress_in_ui && progress_in_ui.is_a?( TT::Progressbar )
    progress = progress_in_ui
  else
    progress = TT::Progressbar.new( end_vertices, 'Closing open ends' )
  end
  for v in end_vertices
    progress.next if progress_in_ui
    result = self.find(v, end_vertices, edges)
    closed = self.close( context, v, result, epsilon )
    fixes += 1 if closed
    if !closed && erase_small_edges
      edge = v.edges.first
      if edge.length < epsilon
        small_edges << edge 
        fixes += 1
      end
    end
  end # for
  Sketchup.status_text  = 'Erasing small edges...' if progress_in_ui
  if erase_small_edges && !small_edges.empty?
    context.erase_entities( small_edges )
  end
  fixes
end

.find(vertex, open_ends, edges) ⇒ Hash

Finds possible connections for vertex within the set of open_ends and edges.

The returned hash contains three keys:

  • :vertex_projected - the closest connection by extending two edges towards each other.

  • :vertex - the closest open-end vertex

  • :edge - the closest edge

Each value contains another hash with the following keys:

  • :dist the distance from vertex to :point

  • :point the point which vertex can be extended to.

  • :point2 Only availible to :vertex_projected. The origin of the end vertex of the other edge. In this case :point is the intersecting point where the two edges meet.

Parameters:

  • vertex (Sketchup::Vertex)

    The open-end vertex to find connections for.

  • open_ends (Array<Sketchup::Vertex>)

    Set of availible open-end vertices.

  • edges (Array<Sketchup::Edge>)

    Set of edges to connect to.

Returns:

  • (Hash)

    Returns a hash with possible connection options.

Since:

  • 2.5.0



414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
# File 'TT_Lib2/edges.rb', line 414

def self.find( vertex, open_ends, edges )
  origin = vertex.position
  edge = vertex.edges.first
  other = edge.other_vertex( vertex ).position
  vector = origin.vector_to( other )
  line = edge.line
  
  ends = open_ends - [ vertex, edge.other_vertex( vertex ) ]
  end_edges = ends.map { |v| v.edges.first }
  
  distances = {}
  ends.each { |v|
    distances[v] = origin.distance( v.position )
  }
  
  # 1. Closest projected open end
  projected_vertices = {}
  projected_vertices_pt = {}
  for v in ends
    e = v.edges.first
    pt = Geom::intersect_line_line( line, e.line )
    next if pt.nil?

    direction = origin.vector_to(pt)
    next unless direction.valid?
    next if direction.samedirection?(vector)

    projected_vertices[v] = [
      origin.distance( pt ),
      pt.distance( v.position )
    ]
    projected_vertices_pt[v] = pt
  end
  closest_projected_vertex = projected_vertices.keys.min { |a,b|
    va = projected_vertices[a]
    vb = projected_vertices[b]
    if va[0] == vb[0]
      va[1] <=> vb[1]
    else
      va[0] <=> vb[0]
    end
  }
  pt = projected_vertices_pt[closest_projected_vertex]
  tmp = projected_vertices[closest_projected_vertex]
  dist = (tmp.nil?) ? nil : tmp[0]
  result = {}
  result[:vertex_projected] = { :dist => tmp, :point => pt, :point2 => closest_projected_vertex }
  
  # 3. Closest open vertex
  closest_open_vertex = ends.min { |a,b|
    distances[a] <=> distances[b]
  }
  pt = (closest_open_vertex) ? closest_open_vertex.position : nil
  dist = distances[closest_open_vertex]
  result[:vertex] = { :dist => dist, :point => pt }
  
  # 2. Closest edge
  edge_distances = {}
  edge_distances_pt = {}
  for e in edges
    next if e == edge
    pt = Geom::intersect_line_line( line, e.line )
    next if pt.nil?
    #next if pt == other
    pt1, pt2 = e.vertices.map { |v| v.position }
    next unless TT::Point3d.between?( pt1, pt2, pt, true )
    v = origin.vector_to(pt)
    next unless v.valid?
    next if v.samedirection?(vector)
    edge_distances[e] = origin.distance( pt )
    edge_distances_pt[e] = pt
  end
  closest_edge = edge_distances.keys.min { |a,b|
    edge_distances[a] <=> edge_distances[b]
  }
  pt = edge_distances_pt[closest_edge]
  dist = edge_distances[closest_edge]
  result[:edge] = { :dist => dist, :point => pt }
  
  result
end

.find_end_vertices(entities) ⇒ Array<Sketchup::Vertex>

Finds all open-ended edges in entities and returns an array of vertices for each open end.

Parameters:

  • entities (Sketchup::Entities|Array<Sketchup::Entity>)

Returns:

  • (Array<Sketchup::Vertex>)

Since:

  • 2.5.0



504
505
506
507
508
509
510
511
512
# File 'TT_Lib2/edges.rb', line 504

def self.find_end_vertices( entities )
  vertices = []
  for e in entities
    next unless e.is_a?( Sketchup::Edge )
    open_ends =  e.vertices.select { |v| v.edges.length == 1 }
    vertices.concat( open_ends )
  end
  vertices
end