contrek 1.3.3 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/Gemfile.lock +3 -1
  4. data/README.md +28 -28
  5. data/contrek.gemspec +1 -0
  6. data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +2 -0
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +0 -2
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +11 -5
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +8 -10
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +4 -1
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +114 -42
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +1 -1
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +2 -1
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +1 -1
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +66 -116
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +1 -1
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +1 -0
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +2 -87
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +1 -13
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.cpp +0 -1
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +1 -57
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +1 -4
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +31 -17
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +0 -16
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +0 -9
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +1 -1
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/DouglasPeuckerReducer.cpp +177 -0
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/DouglasPeuckerReducer.h +52 -0
  29. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/RasterReducer.cpp +109 -0
  30. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/RasterReducer.h +32 -0
  31. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.h +6 -1
  32. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +4 -0
  33. data/lib/contrek/bitmaps/painting.rb +27 -10
  34. data/lib/contrek/bitmaps/png_bitmap.rb +3 -0
  35. data/lib/contrek/bitmaps/raw_bitmap.rb +1 -0
  36. data/lib/contrek/bitmaps/rendering.rb +74 -0
  37. data/lib/contrek/finder/concurrent/cursor.rb +62 -84
  38. data/lib/contrek/finder/concurrent/finder.rb +2 -1
  39. data/lib/contrek/finder/concurrent/part.rb +4 -77
  40. data/lib/contrek/finder/concurrent/partitionable.rb +1 -58
  41. data/lib/contrek/finder/concurrent/queueable.rb +23 -5
  42. data/lib/contrek/finder/concurrent/sequence.rb +0 -15
  43. data/lib/contrek/finder/concurrent/tile.rb +1 -1
  44. data/lib/contrek/finder/node.rb +26 -8
  45. data/lib/contrek/finder/node_cluster.rb +91 -37
  46. data/lib/contrek/finder/polygon_finder.rb +1 -1
  47. data/lib/contrek/reducers/douglas_peucker_reducer.rb +191 -0
  48. data/lib/contrek/reducers/raster_reducer.rb +72 -0
  49. data/lib/contrek/version.rb +1 -1
  50. data/lib/contrek.rb +3 -0
  51. metadata +23 -2
@@ -51,24 +51,15 @@ module Contrek
51
51
  if part.innerable?
52
52
  all_parts = []
53
53
  tracked_end_points = []
54
- bounds = {min: polyline.max_y, max: 0}
55
- traverse_inner(part, all_parts, bounds, tracked_end_points)
56
- range_of_bounds = (bounds[:min]..bounds[:max])
57
-
54
+ traverse_inner(part, all_parts, tracked_end_points)
58
55
  retme_sequence = Sequence.new
59
56
  all_parts.each do |part|
60
57
  part.touch!
61
- retme_sequence.move_from(part) do |position|
62
- next false if part.is?(Part::ADDED) && !(range_of_bounds === position.payload[:y])
63
-
64
- !(polyline.tile.tg_border?(position.payload) && position.end_point.tracked_outer)
65
- end
66
- end
67
- if retme_sequence.is_not_vertical
68
- inner_polyline = InnerPolyline.new(sequence: retme_sequence)
69
- return_inner_polylines << inner_polyline
70
- mark_children(tracked_end_points, polyline, inner_polyline) if treemap
58
+ retme_sequence.append(part)
71
59
  end
60
+ inner_polyline = InnerPolyline.new(sequence: retme_sequence)
61
+ return_inner_polylines << inner_polyline
62
+ mark_children(tracked_end_points, polyline, inner_polyline) if treemap
72
63
  end
73
64
  end
74
65
  shape_index += 1
@@ -78,76 +69,55 @@ module Contrek
78
69
 
79
70
  private
80
71
 
81
- # finds each part (and relative polyline) inscribed between two end_points and sets the
82
- # founded inner_polyline which be later used to define in which parent hole is placed.
83
- def mark_children(end_points, outer_polyline, inner_polyline)
84
- end_points.each_slice(2) do |a, b|
85
- range = [a.position[:y], b.position[:y]].sort
86
- (range[0] + 1).upto(range[1] - 1) do |y|
87
- if (end_point = @cluster.hub.payloads[y])
88
- end_point.queues.each do |part|
89
- if part.polyline != outer_polyline
90
- part.polyline.inside_inner_polyline = inner_polyline
91
- end
92
- end
93
- end
94
- end
95
- end
96
- end
97
-
98
- # rubocop:disable Lint/NonLocalExitFromIterator
99
- def traverse_outer(act_part, all_parts, shapes_sequence, outer_joined_polyline)
100
- last_part = all_parts.last
101
- all_parts << act_part if last_part != act_part
102
- if act_part.is?(Part::EXCLUSIVE)
103
- return if act_part.size == 0
104
- while (position = act_part.next_position)
105
- outer_joined_polyline.add(position)
106
- end
107
- else
108
- return if act_part.dead_end && all_parts.size > 1 && last_part.is?(Part::SEAM) && last_part.polyline == act_part.polyline
109
- while (new_position = act_part.iterator)
110
- return if outer_joined_polyline.size > 1 &&
111
- outer_joined_polyline.head.payload == new_position.payload &&
112
- act_part == all_parts.first
113
- outer_joined_polyline.add(Position.new(position: new_position.payload, hub: @cluster.hub))
114
- new_position.end_point.tracked_outer = true
115
- versus = act_part.versus
116
- part = new_position.end_point.queues.find do |p|
117
- (p.mirror || act_part.mirror || p.versus == -versus) && p.polyline.tile != act_part.polyline.tile
72
+ def traverse_outer(start_part, all_parts, shapes_sequence, outer_joined_polyline)
73
+ act_part = start_part
74
+
75
+ while act_part
76
+ last_part = all_parts.last
77
+ all_parts << act_part if last_part != act_part
78
+ jumped_to_new_part = false
79
+ if act_part.is?(Part::EXCLUSIVE)
80
+ return if act_part.size == 0
81
+ while (position = act_part.next_position)
82
+ outer_joined_polyline.add(position)
118
83
  end
119
- if part
120
- if all_parts[-2] != part
121
- cont = true
122
- if all_parts.size >= 2
123
- map = all_parts[-2..].map(&:type).uniq
124
- cont = false if map.size == 1 && map.first == Part::SEAM
125
- end
126
- if cont
127
- shapes_sequence << part.polyline.shape if !shapes_sequence.include?(part.polyline.shape)
84
+ else
85
+ while (new_position = act_part.iterator)
86
+ if outer_joined_polyline.size > 1 &&
87
+ outer_joined_polyline.head.payload == new_position.payload &&
88
+ act_part == all_parts.first
89
+ return
90
+ end
91
+ new_position.end_point.tracked_outer = true
92
+ versus = act_part.versus
93
+ part = new_position.end_point.queues.find do |p|
94
+ (p.versus == -versus) && p.polyline.tile != act_part.polyline.tile
95
+ end
96
+ if part
97
+ if all_parts[-2] != part
98
+ if !shapes_sequence.include?(part.polyline.shape)
99
+ shapes_sequence << part.polyline.shape
100
+ end
128
101
  part.next_position(new_position)
129
- part.dead_end = true
130
- traverse_outer(part, all_parts, shapes_sequence, outer_joined_polyline)
131
- return
102
+ act_part = part
103
+ jumped_to_new_part = true
104
+ break
132
105
  end
133
106
  end
107
+ act_part.next_position
134
108
  end
135
- act_part.next_position
136
109
  end
110
+ next if jumped_to_new_part
111
+ next_part = act_part.circular_next
112
+ next_part.rewind!
113
+ act_part = next_part
137
114
  end
138
- next_part = act_part.circular_next
139
- next_part.rewind!
140
- traverse_outer(act_part.circular_next, all_parts, shapes_sequence, outer_joined_polyline)
141
115
  end
142
116
 
143
- def traverse_inner(act_part, all_parts, bounds, tracked_end_points)
117
+ # rubocop:disable Lint/NonLocalExitFromIterator
118
+ def traverse_inner(act_part, all_parts, tracked_end_points)
144
119
  return if act_part == all_parts.first
145
120
 
146
- if act_part.size > 0
147
- min_y, max_y = act_part.to_a.minmax_by { |p| p[:y] }
148
- bounds[:min] = [bounds[:min], min_y[:y]].min
149
- bounds[:max] = [bounds[:max], max_y[:y]].max
150
- end
151
121
  if act_part.innerable?
152
122
  all_parts << act_part
153
123
  while (act_part = act_part.circular_next)
@@ -161,15 +131,6 @@ module Contrek
161
131
  next if dest_part_versus != 0 && dest_part_versus == act_part.versus
162
132
 
163
133
  tracked_end_points << act_part.head.end_point
164
-
165
- link_seq = dest_part.continuum_to?(act_part)
166
- if link_seq.any?
167
- ins_part = Part.new(Part::ADDED, act_part.polyline)
168
- link_seq.each do |pos|
169
- ins_part.add(Position.new(position: nil, hub: nil, known_endpoint: pos))
170
- end
171
- all_parts << ins_part
172
- end
173
134
  shape = dest_part.polyline.shape
174
135
  if !dest_part.polyline.on?(Polyline::TRACKED_OUTER)
175
136
  @shapes_sequence << shape
@@ -179,7 +140,7 @@ module Contrek
179
140
  dest_part.polyline.turn_on(Polyline::TRACKED_OUTER)
180
141
  if !dest_part.touched
181
142
  dest_part.touch!
182
- traverse_inner(dest_part.circular_next, all_parts, bounds, tracked_end_points)
143
+ traverse_inner(dest_part.circular_next, all_parts, tracked_end_points)
183
144
  return
184
145
  end
185
146
  end
@@ -188,10 +149,27 @@ module Contrek
188
149
  end
189
150
  end
190
151
  elsif act_part.next
191
- traverse_inner(act_part.next, all_parts, bounds, tracked_end_points)
152
+ traverse_inner(act_part.next, all_parts, tracked_end_points)
192
153
  end
193
154
  end
194
155
  # rubocop:enable Lint/NonLocalExitFromIterator
156
+
157
+ # finds each part (and relative polyline) inscribed between two end_points and sets the
158
+ # founded inner_polyline which be later used to define in which parent hole is placed.
159
+ def mark_children(end_points, outer_polyline, inner_polyline)
160
+ end_points.each_slice(2) do |a, b|
161
+ range = [a.position[:y], b.position[:y]].sort
162
+ (range[0] + 1).upto(range[1] - 1) do |y|
163
+ if (end_point = @cluster.hub.payloads[y])
164
+ end_point.queues.each do |part|
165
+ if part.polyline != outer_polyline
166
+ part.polyline.inside_inner_polyline = inner_polyline
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
195
173
  end
196
174
  end
197
175
  end
@@ -93,7 +93,8 @@ module Contrek
93
93
  compress: ((compress_time * 1000).round(3) if @options.has_key?(:compress))
94
94
  }.compact,
95
95
  width: @maximum_width,
96
- height: @height
96
+ height: @height,
97
+ versus: options[:versus]
97
98
  }
98
99
  metadata[:treemap] = @whole_tile.compute_treemap if options[:treemap]
99
100
  Contrek::Finder::Result.new(raw_polygons, metadata)
@@ -7,25 +7,16 @@ module Contrek
7
7
 
8
8
  SEAM = 1
9
9
  EXCLUSIVE = 0
10
- ADDED = 2
11
10
 
12
11
  attr_reader :polyline, :touched
13
- attr_accessor :next, :circular_next, :prev, :type, :dead_end, :inverts,
14
- :trasmuted, :versus, :mirror, :next_seam, :transmutation_skip
12
+ attr_accessor :next, :circular_next, :type, :versus
15
13
  def initialize(type, polyline)
16
14
  @type = type
17
15
  @polyline = polyline
18
16
  @next = nil
19
- @next_seam = nil
20
17
  @circular_next = nil
21
- @prev = nil
22
- @dead_end = false
23
18
  @touched = false
24
- @inverts = false
25
- @trasmuted = false
26
19
  @versus = 0
27
- @mirror = false
28
- @transmutation_skip = false
29
20
  end
30
21
 
31
22
  def is?(type)
@@ -57,12 +48,11 @@ module Contrek
57
48
 
58
49
  def name
59
50
  {Part::EXCLUSIVE => "EXCLUSIVE",
60
- Part::SEAM => "SEAM",
61
- Part::ADDED => "ADDED"}[type]
51
+ Part::SEAM => "SEAM"}[type]
62
52
  end
63
53
 
64
54
  def inspect
65
- "part #{polyline.parts.index(self)} (mir=#{@mirror} versus=#{@versus} inv=#{@inverts} trm=#{@trasmuted} touched=#{@touched} dead_end =#{@dead_end}, #{size}x) of #{polyline.named} (#{name}) (#{to_a.map { |e| "[#{e[:x]},#{e[:y]}]" }.join})"
55
+ "part #{polyline.parts.index(self)} (versus=#{@versus} touched=#{@touched}, #{size}x) of #{polyline.named} (#{name}) (#{to_a.map { |e| "[#{e[:x]},#{e[:y]}]" }.join})"
66
56
  end
67
57
 
68
58
  def innerable?
@@ -70,80 +60,17 @@ module Contrek
70
60
  end
71
61
 
72
62
  def orient!
73
- @versus = if size <= 1 || (size == 2 && @inverts)
63
+ @versus = if size <= 1
74
64
  0
75
65
  else
76
66
  diff = tail.payload[:y] - head.payload[:y]
77
67
  if diff == 0
78
- @mirror = true
79
68
  0
80
69
  else
81
70
  diff.positive? ? 1 : -1
82
71
  end
83
72
  end
84
73
  end
85
-
86
- def try_transmutation!
87
- head_queues = head.end_point.queues
88
- return if head_queues.size == 1
89
- other_head_part = head_queues.find { |part| part.polyline.tile == polyline.tile && part != self }
90
- if other_head_part
91
- tail_queues = tail.end_point.queues
92
- if tail_queues.find { |part| part == other_head_part }
93
- if (other_head_part.tail.payload[:y] == tail.payload[:y] && other_head_part.head.payload[:y] == head.payload[:y]) ||
94
- (other_head_part.tail.payload[:y] == head.payload[:y] && other_head_part.head.payload[:y] == tail.payload[:y])
95
- if self.next.nil? && other_head_part.prev.nil?
96
- self.mirror = true
97
- end
98
- else
99
- self.type = Part::EXCLUSIVE
100
- self.trasmuted = true
101
- other_head_part.transmutation_skip = true
102
- end
103
- end
104
- end
105
- end
106
-
107
- def within?(other)
108
- self_min, self_max = [head.payload[:y], tail.payload[:y]].minmax
109
- other_min, other_max = [other.head.payload[:y], other.tail.payload[:y]].minmax
110
- self_min >= other_min && self_max <= other_max
111
- end
112
-
113
- def same_length?(other)
114
- (head.payload[:y] - tail.payload[:y]).abs ==
115
- (other.head.payload[:y] - other.tail.payload[:y]).abs
116
- end
117
-
118
- def continuum_to?(other)
119
- return [] if size <= 2 && inverts && other.size <= 2 && other.inverts
120
- return [] if other.head.nil?
121
-
122
- target = other.head.payload
123
- cursor = tail
124
- while cursor
125
- if cursor.payload == target
126
- s = cursor
127
- o = other.head
128
- match = true
129
- nodes = []
130
- while s && o
131
- if s.payload != o.payload
132
- match = false
133
- break
134
- end
135
- nodes << s.end_point
136
- s = s.next
137
- o = o.next
138
- end
139
- if match && s.nil?
140
- return nodes
141
- end
142
- end
143
- cursor = cursor.prev
144
- end
145
- []
146
- end
147
74
  end
148
75
  end
149
76
  end
@@ -8,8 +8,6 @@ module Contrek
8
8
  def initialize(*args, **kwargs, &block)
9
9
  super
10
10
  @parts = []
11
- @first_seam = nil
12
- @last_seam = nil
13
11
  end
14
12
 
15
13
  def add_part(new_part)
@@ -17,15 +15,7 @@ module Contrek
17
15
  @parts << new_part
18
16
  last.next = last.circular_next = new_part if last
19
17
  new_part.circular_next = @parts.first
20
- new_part.prev = last
21
- if new_part.is?(Part::SEAM)
22
- @first_seam ||= new_part
23
- if !@last_seam.nil?
24
- @last_seam.next_seam = new_part
25
- end
26
- @last_seam = new_part
27
- new_part.orient!
28
- end
18
+ new_part.orient! if new_part.is?(Part::SEAM)
29
19
  end
30
20
 
31
21
  def inspect_parts
@@ -35,8 +25,6 @@ module Contrek
35
25
  def partition!
36
26
  current_part = nil
37
27
  @parts = []
38
- @first_seam = nil
39
- @last_seam = nil
40
28
 
41
29
  @raw.each_with_index do |position, n|
42
30
  if @tile.tg_border?(position)
@@ -52,54 +40,9 @@ module Contrek
52
40
  add_part(current_part)
53
41
  current_part = Part.new(Part::EXCLUSIVE, self)
54
42
  end
55
- if n > 0 && @raw[n - 1] == position
56
- current_part.inverts = true
57
- end
58
43
  current_part.add_position(position)
59
44
  end
60
45
  add_part(current_part)
61
-
62
- transmute_parts!
63
- end
64
-
65
- private
66
-
67
- # If there are SEAM parts and one is canceled out by another within the same polyline,
68
- # meaning that all its points are repeated in another, longer sequence,
69
- # then the shorter one is converted to EXCLUSIVE and marked as transmuted
70
- def transmute_parts!
71
- transpose = tile.cluster.finder.transpose?
72
- if (current_seam = @first_seam)
73
- loop do
74
- if transpose
75
- transmute_transposed_part(current_seam)
76
- elsif !current_seam.transmutation_skip
77
- current_seam.try_transmutation!
78
- end
79
- current_seam = current_seam.next_seam
80
- break if current_seam.nil?
81
- end
82
- end
83
- end
84
-
85
- def transmute_transposed_part(part)
86
- if (current_seam = @first_seam)
87
- loop do
88
- if current_seam != part
89
- if part.within?(current_seam)
90
- if !part.same_length?(current_seam)
91
- part.type = Part::EXCLUSIVE
92
- part.trasmuted = true
93
- part.head.end_point.queues.delete(part)
94
- part.tail.end_point.queues.delete(part)
95
- return
96
- end
97
- end
98
- end
99
- current_seam = current_seam.next_seam
100
- break if current_seam.nil?
101
- end
102
- end
103
46
  end
104
47
  end
105
48
  end
@@ -47,12 +47,30 @@ module Contrek
47
47
  node.after_add(self)
48
48
  end
49
49
 
50
- def move_from(queueable, &block)
51
- queueable.rewind!
52
- while (node = queueable.iterator)
53
- queueable.forward!
54
- add(node) if yield(node)
50
+ def append(queueable)
51
+ return if queueable.size.zero?
52
+ queueable.each do |node|
53
+ node.before_rem(queueable)
54
+ node.owner = self
55
55
  end
56
+ if @tail
57
+ @tail.next = queueable.head
58
+ queueable.head.prev = @tail
59
+ else
60
+ @head = queueable.head
61
+ end
62
+ @tail = queueable.tail
63
+ @size += queueable.size
64
+ queueable.reset!
65
+
66
+ each { |node| node.after_add(self) }
67
+ end
68
+
69
+ def reset!
70
+ @head = nil
71
+ @tail = nil
72
+ @size = 0
73
+ @iterator = 0
56
74
  end
57
75
 
58
76
  # from yield: false => stop, true => continue
@@ -5,21 +5,6 @@ module Contrek
5
5
  class Sequence
6
6
  attr_accessor :shape
7
7
  prepend Queueable
8
-
9
- def is_not_vertical
10
- return false if size < 2
11
- x0 = head.payload[:x]
12
- rewind!
13
- while (position = iterator)
14
- return true if position.payload[:x] != x0
15
- forward!
16
- end
17
- false
18
- end
19
-
20
- def get_vector_cache
21
- @vector_cache ||= to_a
22
- end
23
8
  end
24
9
  end
25
10
  end
@@ -84,7 +84,7 @@ module Contrek
84
84
  end
85
85
 
86
86
  def tg_border?(coord)
87
- coord[:x] == (@next.nil? ? @start_x : (@end_x - 1))
87
+ coord[:x] == (@next.nil? ? @start_x : (@end_x))
88
88
  end
89
89
 
90
90
  def inspect
@@ -6,7 +6,7 @@ module Contrek
6
6
  include Listable
7
7
 
8
8
  attr_reader :min_x, :max_x, :y, :name, :tangs_sequence, :tangs_count, :data_pointer,
9
- :upper_start, :upper_end, :lower_start, :lower_end, :start_point, :end_point
9
+ :upper_start, :upper_end, :lower_start, :lower_end
10
10
  attr_accessor :track, :abs_x_index, :outer_index, :inner_index, :inner_left_index, :inner_right_index
11
11
 
12
12
  T_UP = -1
@@ -30,7 +30,7 @@ module Contrek
30
30
  def initialize(cluster, min_x, max_x, y, name, connectivity_offset = 0)
31
31
  @name = name
32
32
  @min_x = min_x
33
- @max_x = max_x
33
+ @max_x = max_x + 1
34
34
  @y = y
35
35
  @tangs_sequence = nil
36
36
  @tangs_count = 0
@@ -47,12 +47,14 @@ module Contrek
47
47
  @upper_end = -1
48
48
  @lower_start = Float::INFINITY
49
49
  @lower_end = -1
50
- @start_point = {x: min_x, y: y}
51
- @end_point = {x: max_x, y: y}
52
50
  @cluster = cluster
53
51
  cluster.add_node(self, connectivity_offset)
54
52
  end
55
53
 
54
+ def inspect
55
+ "#<#{self.class} id:#{@id} name:\"#{@name}\">"
56
+ end
57
+
56
58
  def get_tangent_node_by_virtual_index(virtual_index)
57
59
  return nil if virtual_index.nil?
58
60
  if virtual_index < 0
@@ -62,6 +64,22 @@ module Contrek
62
64
  end
63
65
  end
64
66
 
67
+ def nw_point
68
+ {x: min_x, y: y}
69
+ end
70
+
71
+ def ne_point
72
+ {x: max_x, y: y}
73
+ end
74
+
75
+ def se_point
76
+ {x: max_x, y: y + 1}
77
+ end
78
+
79
+ def sw_point
80
+ {x: min_x, y: y + 1}
81
+ end
82
+
65
83
  def my_next(last, versus, mode)
66
84
  last_node_index = if last.y < y
67
85
  last.abs_x_index + @up_indexer
@@ -99,19 +117,19 @@ module Contrek
99
117
  node_up = @cluster.vert_nodes[y + T_UP][-(tg_index + 1)]
100
118
  if enter_mode == :a
101
119
  enter_to.track |= TURNER[tracking][OMAX - 1]
102
- point = node_up.end_point
120
+ point = node_up.se_point
103
121
  else
104
122
  enter_to.track |= TURNER[tracking][OMIN - 1]
105
- point = node_up.start_point
123
+ point = node_up.sw_point
106
124
  end
107
125
  else
108
126
  node_down = @cluster.vert_nodes[y + T_DOWN][tg_index]
109
127
  if enter_mode == :a
110
128
  enter_to.track |= TURNER[tracking][OMIN - 1]
111
- point = node_down.start_point
129
+ point = node_down.nw_point
112
130
  else
113
131
  enter_to.track |= TURNER[tracking][OMAX - 1]
114
- point = node_down.end_point
132
+ point = node_down.ne_point
115
133
  end
116
134
  end
117
135
  point