chem_scanner 0.1.3
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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.rubocop.yml +604 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +20 -0
- data/LICENSE.txt +661 -0
- data/README.md +177 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/chem_scanner.gemspec +43 -0
- data/lib/chem_scanner.rb +79 -0
- data/lib/chem_scanner/cdx.rb +67 -0
- data/lib/chem_scanner/cdxml.rb +72 -0
- data/lib/chem_scanner/chem_draw/cdx_reader.rb +101 -0
- data/lib/chem_scanner/chem_draw/node/base_node.rb +123 -0
- data/lib/chem_scanner/chem_draw/node/base_value.rb +257 -0
- data/lib/chem_scanner/chem_draw/node/bond.rb +100 -0
- data/lib/chem_scanner/chem_draw/node/bracket_attachment.rb +17 -0
- data/lib/chem_scanner/chem_draw/node/bracket_group.rb +32 -0
- data/lib/chem_scanner/chem_draw/node/chem_geometry.rb +58 -0
- data/lib/chem_scanner/chem_draw/node/color_table.rb +46 -0
- data/lib/chem_scanner/chem_draw/node/font_table.rb +54 -0
- data/lib/chem_scanner/chem_draw/node/fragment.rb +149 -0
- data/lib/chem_scanner/chem_draw/node/fragment_node.rb +145 -0
- data/lib/chem_scanner/chem_draw/node/graphic.rb +94 -0
- data/lib/chem_scanner/chem_draw/node/text.rb +242 -0
- data/lib/chem_scanner/chem_draw/parser.rb +214 -0
- data/lib/chem_scanner/chem_draw/yaml/cdx_objects.yaml +32 -0
- data/lib/chem_scanner/chem_draw/yaml/cdx_props.yaml +263 -0
- data/lib/chem_scanner/chem_draw/yaml/cdxml_objects.yaml +36 -0
- data/lib/chem_scanner/chem_draw/yaml/cdxml_props.yaml +263 -0
- data/lib/chem_scanner/chem_draw/yaml/props_data_type.yaml +263 -0
- data/lib/chem_scanner/configuration/abbreviation.rb +76 -0
- data/lib/chem_scanner/configuration/superatom.rb +76 -0
- data/lib/chem_scanner/configuration/superatom.txt +2874 -0
- data/lib/chem_scanner/configuration/util.rb +40 -0
- data/lib/chem_scanner/configuration/yaml/abbreviations.yaml +6399 -0
- data/lib/chem_scanner/configuration/yaml/elements.yaml +115 -0
- data/lib/chem_scanner/configuration/yaml/solvents.yaml +16 -0
- data/lib/chem_scanner/doc.rb +56 -0
- data/lib/chem_scanner/docx.rb +86 -0
- data/lib/chem_scanner/export/cml.rb +176 -0
- data/lib/chem_scanner/extension/element_map.rb +9 -0
- data/lib/chem_scanner/extension/geometry/bounding_box.rb +84 -0
- data/lib/chem_scanner/extension/geometry/line.rb +123 -0
- data/lib/chem_scanner/extension/geometry/point.rb +18 -0
- data/lib/chem_scanner/extension/geometry/polygon.rb +115 -0
- data/lib/chem_scanner/extension/geometry/segment.rb +196 -0
- data/lib/chem_scanner/extension/passthrough.rb +7 -0
- data/lib/chem_scanner/interpreter/element/arrow.rb +298 -0
- data/lib/chem_scanner/interpreter/element/atom.rb +134 -0
- data/lib/chem_scanner/interpreter/element/fragment.rb +59 -0
- data/lib/chem_scanner/interpreter/element/molecule.rb +473 -0
- data/lib/chem_scanner/interpreter/element/molecule_group.rb +34 -0
- data/lib/chem_scanner/interpreter/element/reaction.rb +186 -0
- data/lib/chem_scanner/interpreter/element/reaction_step.rb +39 -0
- data/lib/chem_scanner/interpreter/formula_to_mol.rb +75 -0
- data/lib/chem_scanner/interpreter/post_process/assemble.rb +38 -0
- data/lib/chem_scanner/interpreter/post_process/label_by_molecule.rb +37 -0
- data/lib/chem_scanner/interpreter/post_process/reaction_info.rb +225 -0
- data/lib/chem_scanner/interpreter/post_process/reaction_step.rb +95 -0
- data/lib/chem_scanner/interpreter/post_process/reagent_label.rb +46 -0
- data/lib/chem_scanner/interpreter/post_process/text_as_molecule.rb +52 -0
- data/lib/chem_scanner/interpreter/post_process/text_label.rb +40 -0
- data/lib/chem_scanner/interpreter/pre_process/arrow.rb +197 -0
- data/lib/chem_scanner/interpreter/pre_process/graphic.rb +41 -0
- data/lib/chem_scanner/interpreter/pre_process/molecule.rb +150 -0
- data/lib/chem_scanner/interpreter/reaction_detection/assign_to_reaction.rb +129 -0
- data/lib/chem_scanner/interpreter/reaction_detection/duplicate_reagents.rb +50 -0
- data/lib/chem_scanner/interpreter/reaction_detection/molecule_group.rb +55 -0
- data/lib/chem_scanner/interpreter/reaction_detection/multi_line_chain_reaction.rb +85 -0
- data/lib/chem_scanner/interpreter/reaction_detection/remove_separated_mol.rb +115 -0
- data/lib/chem_scanner/interpreter/reaction_detection/text_assignment.rb +166 -0
- data/lib/chem_scanner/interpreter/scheme.rb +173 -0
- data/lib/chem_scanner/interpreter/scheme_base.rb +64 -0
- data/lib/chem_scanner/interpreter/text_group/bold_groups.rb +183 -0
- data/lib/chem_scanner/interpreter/text_group/molecule_text_group.rb +138 -0
- data/lib/chem_scanner/interpreter/text_group/reaction_text_groups.rb +221 -0
- data/lib/chem_scanner/interpreter/text_group/retrieve_alias_info.rb +41 -0
- data/lib/chem_scanner/interpreter/text_group/retrieve_n_atoms.rb +106 -0
- data/lib/chem_scanner/interpreter/text_group/text_group_interpreter.rb +92 -0
- data/lib/chem_scanner/perkin_eln.rb +287 -0
- data/lib/chem_scanner/version.rb +5 -0
- data/lib/rubygems_plugin.rb +5 -0
- metadata +244 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "geometry"
|
|
4
|
+
|
|
5
|
+
module ChemScanner
|
|
6
|
+
# Extension module
|
|
7
|
+
module Extension
|
|
8
|
+
include Geometry
|
|
9
|
+
|
|
10
|
+
# Monkey path BoundingBox class from ruby-geometry
|
|
11
|
+
refine Geometry::BoundingBox do
|
|
12
|
+
def lefttop
|
|
13
|
+
Point.new(leftbottom.x, righttop.y)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def rightbottom
|
|
17
|
+
Point.new(righttop.x, leftbottom.y)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def center
|
|
21
|
+
lb = leftbottom
|
|
22
|
+
rt = righttop
|
|
23
|
+
|
|
24
|
+
Point.new((lb.x + rt.x) / 2, (lb.y + rt.y) / 2)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def edges
|
|
28
|
+
[
|
|
29
|
+
Segment.new(leftbottom, lefttop),
|
|
30
|
+
Segment.new(leftbottom, rightbottom),
|
|
31
|
+
Segment.new(lefttop, righttop),
|
|
32
|
+
Segment.new(rightbottom, righttop),
|
|
33
|
+
]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def points
|
|
37
|
+
[leftbottom, lefttop, righttop, rightbottom]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def euclid_distance_to(other)
|
|
41
|
+
distance_list = []
|
|
42
|
+
|
|
43
|
+
edges.each do |edge|
|
|
44
|
+
other.edges.each do |oedge|
|
|
45
|
+
distance_list.push(edge.euclid_distance_to(oedge))
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
distance_list.min
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def distance_to_point(point)
|
|
53
|
+
distance_list = []
|
|
54
|
+
|
|
55
|
+
edges.each do |edge|
|
|
56
|
+
distance_list.push(edge.distance_to(point))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
distance_list.min
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def euclid_distance_to_point(point)
|
|
63
|
+
point.distance_to(center)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def area
|
|
67
|
+
Segment.new(leftbottom, lefttop).length *
|
|
68
|
+
Segment.new(lefttop, righttop).length
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def to_gis
|
|
72
|
+
coords = points.map { |point| "(#{point.x}, #{point.y})" }.join(",")
|
|
73
|
+
"POLYGON(#{coords})"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def contains_point?(point)
|
|
77
|
+
(
|
|
78
|
+
point.x <= righttop.x && point.x >= leftbottom.x &&
|
|
79
|
+
point.y <= righttop.y && point.y >= leftbottom.y
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "geometry"
|
|
4
|
+
|
|
5
|
+
module ChemScanner
|
|
6
|
+
# Monkey path Line class from ruby-geometry
|
|
7
|
+
module Extension
|
|
8
|
+
include Geometry
|
|
9
|
+
|
|
10
|
+
# Monkey patch Line class
|
|
11
|
+
refine Geometry::Line do
|
|
12
|
+
def angle
|
|
13
|
+
return 90 if vertical?
|
|
14
|
+
return 0 if horizontal?
|
|
15
|
+
|
|
16
|
+
p1, p2 = [point1, point2].sort_by(&:x)
|
|
17
|
+
delta_x = p1.x - p2.x
|
|
18
|
+
delta_y = p1.y - p2.y
|
|
19
|
+
|
|
20
|
+
arc = if point1.y > point2.y # inverted axis/origin
|
|
21
|
+
Math.atan(delta_y / delta_x)
|
|
22
|
+
else
|
|
23
|
+
Math.atan(delta_x / delta_y)
|
|
24
|
+
end
|
|
25
|
+
(arc.positive? ? arc : (2 * Math::PI + arc)) * 360 / (2 * Math::PI)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_segment
|
|
29
|
+
Segment.new(point1, point2)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def abc_coeff
|
|
33
|
+
a = point2.y - point1.y
|
|
34
|
+
b = point1.x - point2.x
|
|
35
|
+
c = a * point1.x + b * point1.y
|
|
36
|
+
|
|
37
|
+
[a, b, c]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Get point belong to the line, give x or y
|
|
41
|
+
def get_point(value, is_y = false)
|
|
42
|
+
if is_y
|
|
43
|
+
x = x_from_y(value)
|
|
44
|
+
Point.new(x, Float(value))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
y = y_from_x(value)
|
|
48
|
+
Point.new(Float(value), y)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def x_from_y(point_y)
|
|
52
|
+
b = point1.y - point2.y
|
|
53
|
+
return nil if b.zero?
|
|
54
|
+
|
|
55
|
+
Float(point1.x - ((point1.y - point_y) * (point1.x - point2.x) / b))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def y_from_x(point_x)
|
|
59
|
+
b = point1.x - point2.x
|
|
60
|
+
return nil if b.zero?
|
|
61
|
+
|
|
62
|
+
Float(point1.y - ((point1.x - point_x) * (point1.y - point2.y)) / b)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def intersects_with_segment?(segment)
|
|
66
|
+
segment.intersects_with_line?(self)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def intersects_with_polygon?(polygon)
|
|
70
|
+
polygon.edges.each do |edge|
|
|
71
|
+
return true if intersects_with_segment?(edge)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
false
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def intersection_points_with_polygon(polygon)
|
|
78
|
+
polygon.intersection_points_with_line(self)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def intersection_points_with(line)
|
|
82
|
+
return nil if parallel_to?(line)
|
|
83
|
+
|
|
84
|
+
# Ax + By = C
|
|
85
|
+
a1, b1, c1 = abc_coeff
|
|
86
|
+
a2, b2, c2 = line.abc_coeff
|
|
87
|
+
|
|
88
|
+
determinant = a1 * b2 - a2 * b1
|
|
89
|
+
|
|
90
|
+
x = (b2 * c1 - b1 * c2) / determinant
|
|
91
|
+
y = (a1 * c2 - a2 * c1) / determinant
|
|
92
|
+
|
|
93
|
+
Point.new(x, y)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# positive: same side with point2
|
|
97
|
+
# negative: same side with point1
|
|
98
|
+
def point_side(point)
|
|
99
|
+
v = Segment.new(point1, point).to_vector
|
|
100
|
+
to_segment.to_vector.cross_product(v)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def perpen_line_via_point(point)
|
|
104
|
+
if vertical?
|
|
105
|
+
Line.new(point, Point.new(point.x + 5, point.y))
|
|
106
|
+
elsif horizontal?
|
|
107
|
+
Line.new(point, Point.new(point.x, point.y + 5))
|
|
108
|
+
else
|
|
109
|
+
m2 = (-1 / slope)
|
|
110
|
+
x2 = point.x + 5
|
|
111
|
+
y2 = m2 * x2 + (point.y - m2 * point.x)
|
|
112
|
+
|
|
113
|
+
Line.new(point, Point.new(x2, y2))
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def point_projection(point)
|
|
118
|
+
pline = perpen_line_via_point(point)
|
|
119
|
+
pline.intersection_points_with(self)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "geometry"
|
|
4
|
+
|
|
5
|
+
module ChemScanner
|
|
6
|
+
# Monkey patch Point class from ruby-geometry
|
|
7
|
+
module Extension
|
|
8
|
+
refine Geometry::Point do
|
|
9
|
+
def euclid_distance_to_polygon(polygon)
|
|
10
|
+
polygon.euclid_distance_to_point(self)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def distance_to(other)
|
|
14
|
+
Geometry.distance(self, other)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "geometry"
|
|
4
|
+
|
|
5
|
+
module ChemScanner
|
|
6
|
+
include Geometry
|
|
7
|
+
|
|
8
|
+
# Extension module
|
|
9
|
+
module Extension
|
|
10
|
+
# Monkey path Polygon class from ruby-geometry
|
|
11
|
+
refine Geometry::Polygon do
|
|
12
|
+
def center
|
|
13
|
+
lb = bounding_box.leftbottom
|
|
14
|
+
rt = bounding_box.righttop
|
|
15
|
+
|
|
16
|
+
Point.new((lb.x + rt.x) / 2, (lb.y + rt.y) / 2)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def height
|
|
20
|
+
lb = bounding_box.leftbottom
|
|
21
|
+
lb.distance_to(bounding_box.lefttop)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def width
|
|
25
|
+
lb = bounding_box.leftbottom
|
|
26
|
+
lb.distance_to(bounding_box.rightbottom)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def intersects_with_polygon?(other)
|
|
30
|
+
edges.each do |e1|
|
|
31
|
+
other.edges.each do |e2|
|
|
32
|
+
return true if e1.intersects_with?(e2)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def contains_polygon?(other)
|
|
40
|
+
other.vertices.each do |v1|
|
|
41
|
+
return false unless contains?(v1)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def around_polygon?(other)
|
|
48
|
+
(
|
|
49
|
+
contains_polygon?(other) || other.contains_polygon?(self) ||
|
|
50
|
+
contains?(other.center) || other.contains?(center)
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def merge_polygon(another)
|
|
55
|
+
lb = bounding_box.leftbottom
|
|
56
|
+
rt = bounding_box.righttop
|
|
57
|
+
|
|
58
|
+
alb = another.bounding_box.leftbottom
|
|
59
|
+
art = another.bounding_box.righttop
|
|
60
|
+
|
|
61
|
+
left = [lb.x, alb.x].min
|
|
62
|
+
bottom = [lb.y, alb.y].min
|
|
63
|
+
right = [rt.x, art.x].max
|
|
64
|
+
top = [rt.y, art.y].max
|
|
65
|
+
|
|
66
|
+
p1 = Point.new(left, bottom)
|
|
67
|
+
p2 = Point.new(left, top)
|
|
68
|
+
p3 = Point.new(right, top)
|
|
69
|
+
p4 = Point.new(right, bottom)
|
|
70
|
+
|
|
71
|
+
Polygon.new([p1, p2, p3, p4])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def distance_to_point(point)
|
|
75
|
+
min_dist = 9_999_999
|
|
76
|
+
|
|
77
|
+
edges.each do |edge|
|
|
78
|
+
dist = edge.distance_to(point)
|
|
79
|
+
min_dist = dist if dist < min_dist
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
min_dist
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def euclid_distance_to_point(point)
|
|
86
|
+
min_dist = 9_999_999
|
|
87
|
+
|
|
88
|
+
edges.each do |edge|
|
|
89
|
+
dist = edge.euclid_distance_to_point(point)
|
|
90
|
+
min_dist = dist if dist < min_dist
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
min_dist
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def intersection_points_with_line(line)
|
|
97
|
+
points = []
|
|
98
|
+
|
|
99
|
+
edges.each do |edge|
|
|
100
|
+
eline = edge.to_line
|
|
101
|
+
inter_x = eline.intersect_x(line)
|
|
102
|
+
next if inter_x.nil?
|
|
103
|
+
|
|
104
|
+
inter_y = line.y_from_x(inter_x)
|
|
105
|
+
inter_y = edge.to_line.y_from_x(inter_x) if inter_y.nil?
|
|
106
|
+
|
|
107
|
+
point = Point.new(inter_x, inter_y)
|
|
108
|
+
points.push(point) if edge.contains_point?(point)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
points
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "geometry"
|
|
4
|
+
|
|
5
|
+
module ChemScanner
|
|
6
|
+
include Geometry
|
|
7
|
+
|
|
8
|
+
# Monkey patch ruby-geometry class
|
|
9
|
+
module Extension
|
|
10
|
+
# Monkey patch Segment class
|
|
11
|
+
refine Geometry::Segment do
|
|
12
|
+
def points
|
|
13
|
+
[point1, point2]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def contains_point?(point)
|
|
17
|
+
l1 = Geometry.distance(point1, point)
|
|
18
|
+
l2 = Geometry.distance(point, point2)
|
|
19
|
+
|
|
20
|
+
length.round(2) === (l1 + l2).round(2)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def contains_segment?(other)
|
|
24
|
+
contains_point?(other.point1) && contains_point?(other.point2)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def center
|
|
28
|
+
Point.new((point1.x + point2.x) / 2, (point1.y + point2.y) / 2)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_line
|
|
32
|
+
Line.new(point1, point2)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def intersects_with_polygon?(polygon)
|
|
36
|
+
count = 0
|
|
37
|
+
polygon.edges.each do |edge|
|
|
38
|
+
count += 1 if edge.intersects_with?(self)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
count > 1
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def intersects_with_line?(line)
|
|
45
|
+
sline = to_line
|
|
46
|
+
inter_x = sline.intersect_x(line)
|
|
47
|
+
return false if inter_x.nil?
|
|
48
|
+
|
|
49
|
+
inter_y = line.y_from_x(inter_x)
|
|
50
|
+
inter_y = to_line.y_from_x(inter_x) if inter_y.nil?
|
|
51
|
+
return false if inter_y.nil?
|
|
52
|
+
|
|
53
|
+
point = Point.new(inter_x, inter_y)
|
|
54
|
+
contains_point?(point)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def head_perpen_points_dist(distance)
|
|
58
|
+
dx = point2.x - point1.x
|
|
59
|
+
dy = point2.y - point1.y
|
|
60
|
+
dist = Math.sqrt((dx * dx) + (dy * dy))
|
|
61
|
+
dx /= dist
|
|
62
|
+
dy /= dist
|
|
63
|
+
x3 = point2.x + (distance * dy)
|
|
64
|
+
y3 = point2.y - (distance * dx)
|
|
65
|
+
x4 = point2.x - (distance * dy)
|
|
66
|
+
y4 = point2.y + (distance * dx)
|
|
67
|
+
[Point.new(x3, y3), Point.new(x4, y4)]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def tail_perpen_points_dist(distance)
|
|
71
|
+
dx = point1.x - point2.x
|
|
72
|
+
dy = point1.y - point2.y
|
|
73
|
+
dist = Math.sqrt((dx * dx) + (dy * dy))
|
|
74
|
+
dx /= dist
|
|
75
|
+
dy /= dist
|
|
76
|
+
x3 = point1.x + (distance * dy)
|
|
77
|
+
y3 = point1.y - (distance * dx)
|
|
78
|
+
x4 = point1.x - (distance * dy)
|
|
79
|
+
y4 = point1.y + (distance * dx)
|
|
80
|
+
[Point.new(x4, y4), Point.new(x3, y3)]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def parallel_at(point)
|
|
84
|
+
x4 = point.x + point2.x - point1.x
|
|
85
|
+
y4 = point.y + point2.y - point1.y
|
|
86
|
+
Point.new(x4, y4)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def euclid_distance_to(other)
|
|
90
|
+
l1 = point1.distance_to(other.point1)
|
|
91
|
+
l2 = point2.distance_to(other.point1)
|
|
92
|
+
l3 = point1.distance_to(other.point2)
|
|
93
|
+
l4 = point2.distance_to(other.point2)
|
|
94
|
+
|
|
95
|
+
[l1, l2, l3, l4].min
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def euclid_distance_to_point(point)
|
|
99
|
+
l1 = point1.distance_to(point)
|
|
100
|
+
l2 = point2.distance_to(point)
|
|
101
|
+
|
|
102
|
+
[l1, l2].min
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def euclid_distance_to_polygon(poly)
|
|
106
|
+
dist = []
|
|
107
|
+
|
|
108
|
+
poly.bounding_box.edges.each do |edge|
|
|
109
|
+
min_dist = euclid_distance_to(edge)
|
|
110
|
+
dist.push(min_dist)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
dist.min
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def distance_to_boundingbox(bbox)
|
|
117
|
+
dists = []
|
|
118
|
+
|
|
119
|
+
bbox.edges.each do |edge|
|
|
120
|
+
dist = distance_to_segment(edge)
|
|
121
|
+
dists.push(dist)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
dists.min
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def distance_to_segment(other)
|
|
128
|
+
[
|
|
129
|
+
other.distance_to(point1),
|
|
130
|
+
other.distance_to(point2),
|
|
131
|
+
distance_to(other.point1),
|
|
132
|
+
distance_to(other.point2),
|
|
133
|
+
].min
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def perpen_segment_via_point(point)
|
|
137
|
+
sline = to_line
|
|
138
|
+
pline = sline.perpen_line_via_point(point)
|
|
139
|
+
|
|
140
|
+
inter_point = pline.intersection_points_with(sline)
|
|
141
|
+
return nil if inter_point.nil?
|
|
142
|
+
|
|
143
|
+
Segment.new(point, inter_point)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def point_in_range(point, range, from_head = nil)
|
|
147
|
+
return false unless contains_point?(point)
|
|
148
|
+
|
|
149
|
+
dist1 = point1.distance_to(point)
|
|
150
|
+
dist2 = point2.distance_to(point)
|
|
151
|
+
|
|
152
|
+
dist = case from_head
|
|
153
|
+
when true then dist1
|
|
154
|
+
when false then dist2
|
|
155
|
+
when nil then [dist1, dist2].max
|
|
156
|
+
else return false
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
(dist / length) < range
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def polygon_in_range(polygon)
|
|
163
|
+
line = to_line
|
|
164
|
+
|
|
165
|
+
polygon.vertices.each do |vertex|
|
|
166
|
+
ppoint = line.point_projection(vertex)
|
|
167
|
+
return true if contains_point?(ppoint)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
false
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def slice_to_many_points(num)
|
|
174
|
+
return [] if num < 2
|
|
175
|
+
|
|
176
|
+
delta_x = (point1.x - point2.x).abs
|
|
177
|
+
delta_y = (point1.y - point2.y).abs
|
|
178
|
+
|
|
179
|
+
avg_x = delta_x / (num + 1)
|
|
180
|
+
avg_y = delta_y / (num + 1)
|
|
181
|
+
default = OpenStruct.new(
|
|
182
|
+
x: [point1.x, point2.x].min, y: [point1.y, point2.y].min,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
(1..num).to_a.reduce([]) do |arr, _|
|
|
186
|
+
prev = arr.last || default
|
|
187
|
+
arr.push(Point.new(prev.x + avg_x, prev.y + avg_y))
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def to_gis
|
|
192
|
+
"SEGMENT((#{point1.x}, #{point1.y}), (#{point2.x}, #{point2.y}))"
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|