Class: Contrek::Concurrent::Polyline

Inherits:
Object
  • Object
show all
Includes:
Partitionable
Defined in:
lib/contrek/finder/concurrent/polyline.rb

Constant Summary collapse

TRACKED_OUTER =
1 << 0
TRACKED_INNER =
1 << 1

Instance Attribute Summary collapse

Attributes included from Partitionable

#parts

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Partitionable

#add_part, #find_first_part_by_position, #insert_after, #inspect_parts, #partition!, #sew!

Constructor Details

#initialize(tile:, polygon:, shape: nil, bounds: nil) ⇒ Polyline

Returns a new instance of Polyline.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/contrek/finder/concurrent/polyline.rb', line 12

def initialize(tile:, polygon:, shape: nil, bounds: nil)
  @tile = tile
  @name = tile.shapes.count
  @raw = polygon
  @shape = shape
  @flags = 0
  @mixed_tile_origin = false # becomes true when is sewn with polyline coming from other side tile

  if bounds.nil?
    find_boundary
  else
    @min_x = bounds[:min_x]
    @max_x = bounds[:max_x]
    @min_y = bounds[:min_y]
    @max_y = bounds[:max_y]
  end
end

Instance Attribute Details

#max_yObject (readonly)

Returns the value of attribute max_y.



9
10
11
# File 'lib/contrek/finder/concurrent/polyline.rb', line 9

def max_y
  @max_y
end

#min_yObject (readonly)

Returns the value of attribute min_y.



9
10
11
# File 'lib/contrek/finder/concurrent/polyline.rb', line 9

def min_y
  @min_y
end

#mixed_tile_originObject

Returns the value of attribute mixed_tile_origin.



10
11
12
# File 'lib/contrek/finder/concurrent/polyline.rb', line 10

def mixed_tile_origin
  @mixed_tile_origin
end

#nameObject (readonly)

Returns the value of attribute name.



9
10
11
# File 'lib/contrek/finder/concurrent/polyline.rb', line 9

def name
  @name
end

#next_tile_eligible_shapesObject (readonly)

Returns the value of attribute next_tile_eligible_shapes.



9
10
11
# File 'lib/contrek/finder/concurrent/polyline.rb', line 9

def next_tile_eligible_shapes
  @next_tile_eligible_shapes
end

#rawObject (readonly)

Returns the value of attribute raw.



9
10
11
# File 'lib/contrek/finder/concurrent/polyline.rb', line 9

def raw
  @raw
end

#shapeObject

Returns the value of attribute shape.



10
11
12
# File 'lib/contrek/finder/concurrent/polyline.rb', line 10

def shape
  @shape
end

#tileObject

Returns the value of attribute tile.



10
11
12
# File 'lib/contrek/finder/concurrent/polyline.rb', line 10

def tile
  @tile
end

Class Method Details

.is_within?(test_seq, container_seq) ⇒ Boolean

Returns:

  • (Boolean)


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/contrek/finder/concurrent/polyline.rb', line 156

def self.is_within?(test_seq, container_seq)
  target = test_seq.first
  return false unless target
  tx, ty = target[:x], target[:y]
  inside = false
  j = container_seq.length - 1
  container_seq.each_with_index do |p_i, i|
    p_j = container_seq[j]
    if (p_i[:y] > ty) != (p_j[:y] > ty)
      intersect_x = (p_j[:x] - p_i[:x]) * (ty - p_i[:y]).to_f / (p_j[:y] - p_i[:y]) + p_i[:x]
      if tx < intersect_x
        inside = !inside
      end
    end
    j = i
  end
  inside
end

Instance Method Details

#boundary?Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/contrek/finder/concurrent/polyline.rb', line 94

def boundary?
  @tile.tg_border?({x: @min_x}) || @tile.tg_border?({x: @max_x})
end

#clear!Object



98
99
100
# File 'lib/contrek/finder/concurrent/polyline.rb', line 98

def clear!
  @raw = []
end

#empty?Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/contrek/finder/concurrent/polyline.rb', line 90

def empty?
  @raw.empty?
end

#get_boundsObject



149
150
151
152
153
154
# File 'lib/contrek/finder/concurrent/polyline.rb', line 149

def get_bounds
  {min_x: @min_x,
   max_x: @max_x,
   min_y: @min_y,
   max_y: @max_y}
end

#infoObject



42
43
44
# File 'lib/contrek/finder/concurrent/polyline.rb', line 42

def info
  "w#{@tile.name} S#{@name}"
end

#inspectObject



30
31
32
# File 'lib/contrek/finder/concurrent/polyline.rb', line 30

def inspect
  "#{self.class}#{named} (#{raw.count} => #{raw.inspect})"
end

#intersection(other) ⇒ Object

returns for every position of intersection an array composed by the indexes of parts (self,other) involved es [[1,3],,…]. The first time the sequence for self is computed is stored.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/contrek/finder/concurrent/polyline.rb', line 64

def intersection(other)
  if @tracked_endpoints.nil?
    @tracked_endpoints = {} # memoize found sequence
    parts.each_with_index do |part, part_index|
      next if !part.is?(Part::SEAM) && part.trasmuted
      part.each do |pos|
        next if pos.end_point.nil?
        @tracked_endpoints[pos.end_point.object_id] = part_index
      end
    end
  end
  matching_parts = []
  other.parts.each_with_index do |part, part_index|
    next if !part.is?(Part::SEAM) && part.trasmuted
    part.each do |pos|
      if (self_index = @tracked_endpoints[pos.end_point.object_id])
        matching_parts << [self_index, part_index]
        false
      else
        true
      end
    end
  end
  matching_parts
end

#namedObject



34
35
36
# File 'lib/contrek/finder/concurrent/polyline.rb', line 34

def named
  "[b#{@tile.name} S#{@name} #{"B" if boundary?}]"
end

#numpy_rawObject



38
39
40
# File 'lib/contrek/finder/concurrent/polyline.rb', line 38

def numpy_raw
  raw.flat_map { |p| [p[:x], p[:y]] }
end

#on?(flag) ⇒ Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/contrek/finder/concurrent/polyline.rb', line 54

def on?(flag)
  (@flags & flag) != 0
end

#precalc!Object

Pre-detects, for the current polyline, adjacent ones in the neighboring tile that vertically intersect.



109
110
111
112
113
114
115
116
# File 'lib/contrek/finder/concurrent/polyline.rb', line 109

def precalc!
  @next_tile_eligible_shapes = @tile
    .circular_next.boundary_shapes
    .select { |s|
    !s.outer_polyline.on?(Polyline::TRACKED_OUTER) &&
      vert_intersect?(s.outer_polyline)
  }
end

#reset_tracked_endpoints!Object



58
59
60
# File 'lib/contrek/finder/concurrent/polyline.rb', line 58

def reset_tracked_endpoints!
  @tracked_endpoints = nil
end

#turn_off(flag) ⇒ Object



50
51
52
# File 'lib/contrek/finder/concurrent/polyline.rb', line 50

def turn_off(flag)
  @flags &= ~flag
end

#turn_on(flag) ⇒ Object



46
47
48
# File 'lib/contrek/finder/concurrent/polyline.rb', line 46

def turn_on(flag)
  @flags |= flag
end

#vert_bounds_intersect?(vertical_bounds) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/contrek/finder/concurrent/polyline.rb', line 122

def vert_bounds_intersect?(vertical_bounds)
  !(@max_y < vertical_bounds[:min] || vertical_bounds[:max] < @min_y)
end

#vert_intersect?(other) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/contrek/finder/concurrent/polyline.rb', line 118

def vert_intersect?(other)
  !(@max_y < other.min_y || other.max_y < @min_y)
end

#widthObject



102
103
104
105
# File 'lib/contrek/finder/concurrent/polyline.rb', line 102

def width
  return 0 if empty?
  @max_x - @min_x
end

#within?(raw_coords) ⇒ Boolean

verifies if enclosed in the given sequence (raycasting technique)

Returns:

  • (Boolean)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/contrek/finder/concurrent/polyline.rb', line 127

def within?(raw_coords)
  is_within = false
  self_y = raw.first[:y]
  self_x = raw.first[:x]
  last_node = raw_coords.last
  return false if last_node.nil?
  lx = last_node[:x]
  ly = last_node[:y]
  raw_coords.each do |pos|
    cx = pos[:x]
    cy = pos[:y]
    if (cy > self_y) != (ly > self_y)
      intersect_x = lx + (self_y - ly).to_f * (cx - lx) / (cy - ly)
      if self_x < intersect_x
        is_within = !is_within
      end
    end
    lx, ly = cx, cy
  end
  is_within
end