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