1 #include "polygon.hpp"
2 #include "lut.hpp"
3 #include "nlohmann/json.hpp"
4 #include "util/geom_util.hpp"
5 #include "util/bbox_accumulator.hpp"
6 #include "util/polygon_arc_removal_proxy.hpp"
7
8 namespace horizon {
9
10 static const LutEnumStr<Polygon::Vertex::Type> type_lut = {{"line", Polygon::Vertex::Type::LINE},
11 {"arc", Polygon::Vertex::Type::ARC}};
12
Vertex(const json & j)13 Polygon::Vertex::Vertex(const json &j)
14 : type(type_lut.lookup(j.at("type").get<std::string>())), position(j.at("position").get<std::vector<int64_t>>()),
15 arc_center(j.at("arc_center").get<std::vector<int64_t>>()), arc_reverse(j.value("arc_reverse", false))
16 {
17 }
18
Vertex(const Coordi & c)19 Polygon::Vertex::Vertex(const Coordi &c) : position(c)
20 {
21 }
22
serialize() const23 json Polygon::Vertex::serialize() const
24 {
25 json j;
26 j["type"] = type_lut.lookup_reverse(type);
27 j["position"] = position.as_array();
28 j["arc_center"] = arc_center.as_array();
29 j["arc_reverse"] = arc_reverse;
30 return j;
31 }
32
Polygon(const UUID & uu,const json & j)33 Polygon::Polygon(const UUID &uu, const json &j)
34 : uuid(uu), layer(j.value("layer", 0)), parameter_class(j.value("parameter_class", ""))
35 {
36 {
37 const json &o = j["vertices"];
38 for (auto it = o.cbegin(); it != o.cend(); ++it) {
39 vertices.emplace_back(it.value());
40 }
41 }
42 }
43
Polygon(const UUID & uu)44 Polygon::Polygon(const UUID &uu) : uuid(uu)
45 {
46 }
47
get_uuid() const48 UUID Polygon::get_uuid() const
49 {
50 return uuid;
51 }
52
remove_arcs(unsigned int precision) const53 Polygon Polygon::remove_arcs(unsigned int precision) const
54 {
55 Polygon out(uuid);
56 out.layer = layer;
57 out.usage = usage;
58 if (!has_arcs()) {
59 out.vertices = vertices;
60 return out;
61 }
62
63 for (auto it = vertices.cbegin(); it < vertices.cend(); it++) {
64 if (it->type == Polygon::Vertex::Type::LINE) {
65 out.vertices.emplace_back(*it);
66 }
67 else {
68 out.append_vertex(it->position);
69 auto it_next = it + 1;
70 if (it_next == vertices.cend()) {
71 it_next = vertices.cbegin();
72 }
73 const Coordd a(it->position);
74 const Coordd b(it_next->position);
75 const Coordd c = project_onto_perp_bisector(a, b, it->arc_center);
76 double radius0 = (a - c).mag();
77 double radius1 = (b - c).mag();
78 Color co(1, 1, 0);
79 double a0 = atan2(a.y - c.y, a.x - c.x);
80 double a1 = atan2(b.y - c.y, b.x - c.x);
81
82 unsigned int segments = precision;
83 if (a0 < 0) {
84 a0 += 2 * M_PI;
85 }
86 if (a1 < 0) {
87 a1 += 2 * M_PI;
88 }
89 double dphi = a1 - a0;
90 if (dphi < 0) {
91 dphi += 2 * M_PI;
92 }
93 if (it->arc_reverse) {
94 dphi -= 2 * M_PI;
95 }
96 dphi /= segments;
97
98 float dr = radius1 - radius0;
99 dr /= segments;
100 segments--;
101 while (segments--) {
102 a0 += dphi;
103 auto p1f = c + Coordd::euler(radius0, a0);
104 Coordi p1(p1f.x, p1f.y);
105 out.append_vertex(p1);
106 radius0 += dr;
107 }
108 }
109 }
110
111 return out;
112 }
113
has_arcs() const114 bool Polygon::has_arcs() const
115 {
116 for (const auto &it : vertices) {
117 if (it.type == Polygon::Vertex::Type::ARC)
118 return true;
119 }
120 return false;
121 }
122
is_valid() const123 bool Polygon::is_valid() const
124 {
125 if (has_arcs())
126 return vertices.size() >= 2;
127 else
128 return vertices.size() >= 3;
129 }
130
append_vertex(const Coordi & pos)131 Polygon::Vertex *Polygon::append_vertex(const Coordi &pos)
132 {
133 vertices.emplace_back();
134 vertices.back().position = pos;
135 return &vertices.back();
136 }
137
get_vertices_for_edge(unsigned int edge)138 std::pair<unsigned int, unsigned int> Polygon::get_vertices_for_edge(unsigned int edge)
139 {
140 return {edge, (edge + 1) % vertices.size()};
141 }
142
get_vertex(int edge) const143 const Polygon::Vertex &Polygon::get_vertex(int edge) const
144 {
145 while (edge < 0)
146 edge += vertices.size();
147 return vertices.at(edge % vertices.size());
148 }
149
get_vertex(int edge)150 Polygon::Vertex &Polygon::get_vertex(int edge)
151 {
152 return const_cast<Polygon::Vertex &>(const_cast<const Polygon *>(this)->get_vertex(edge));
153 }
154
get_bbox() const155 std::pair<Coordi, Coordi> Polygon::get_bbox() const
156 {
157 PolygonArcRemovalProxy proxy(*this, 8);
158 const auto &poly = proxy.get();
159 BBoxAccumulator<Coordi::type> acc;
160 for (const auto &v : poly.vertices) {
161 acc.accumulate(v.position);
162 }
163 return acc.get();
164 }
165
serialize() const166 json Polygon::serialize() const
167 {
168 json j;
169 j["layer"] = layer;
170 j["parameter_class"] = parameter_class;
171 j["vertices"] = json::array();
172 for (const auto &it : vertices) {
173 j["vertices"].push_back(it.serialize());
174 }
175
176 return j;
177 }
178 } // namespace horizon
179