PCB Environment 2
Loading...
Searching...
No Matches
Geometry.hpp
1
2#ifndef GYM_PCB_GEOMETRY_H
3#define GYM_PCB_GEOMETRY_H
4
5#define CGAL_DISABLE_ROUNDING_MATH_CHECK
6
7#include <iostream>
8#include "Defs.hpp"
9
10//
11// CGAL configuration and type shorthands.
12//
13#include <CGAL/Bbox_2.h>
14#include <CGAL/Polygon_2.h>
15#include <CGAL/Simple_cartesian.h>
16typedef CGAL::Simple_cartesian<Real> Kernel;
17
18#if CGAL_VERSION_MAJOR >= 6
19#define std_get_for_cgal std::get_if
20#else
21#define std_get_for_cgal boost::get
22#endif
23
24using Vector_2 = Kernel::Vector_2;
25using Vector_3 = Kernel::Vector_3;
26using Point_2 = Kernel::Point_2;
27using Point_3 = Kernel::Point_3;
28using Direction_2 = Kernel::Direction_2;
29using Ray_2 = Kernel::Ray_2;
30using Ray_3 = Kernel::Ray_3;
31using Line_2 = Kernel::Line_2;
32using Segment_2 = Kernel::Segment_2;
33using Segment_3 = Kernel::Segment_3;
34using Triangle_2 = Kernel::Triangle_2;
35using Triangle_3 = Kernel::Triangle_3;
36using Circle_2 = Kernel::Circle_2;
37
38using Bbox_2 = CGAL::Bbox_2;
39using Iso_rectangle_2 = CGAL::Iso_rectangle_2<Kernel>;
40using Polygon_2 = CGAL::Polygon_2<Kernel>;
41
42using Aff_transformation_2 = CGAL::Aff_transformation_2<Kernel>;
43
44#include "Math/IPoint2.hpp"
45#include "Math/IPoint3.hpp"
46
47namespace geo
48{
49
53inline Real cosine(const Vector_2 &v1, const Vector_2 &v2)
54{
55 return CGAL::scalar_product(v1, v2) / std::sqrt(v1.squared_length() *
56 v2.squared_length());
57}
58
63inline float distance45(const Point_2 &A, const Point_2 &B)
64{
65 const Real dx = std::abs(A.x() - B.x());
66 const Real dy = std::abs(A.y() - B.y());
67 return dx + dy - std::min(dx, dy) * (2.0 - std::sqrt(2.0));
68 // return std::max(dx, dy) - std::min(dx, dy) + std::min(dx, dy) * std::sqrt(2.0);
69 // return std::max(dx, dy) - std::min(dx, dy) * (1.0 - std::sqrt(2.0));
70}
71
75inline Bbox_2 bbox_expanded_abs(const Bbox_2 &box, Real m)
76{
77 return Bbox_2(box.xmin() - m, box.ymin() - m, box.xmax() + m, box.ymax() + m);
78}
82inline Bbox_2 bbox_expanded_rel(const Bbox_2 &box, Real r)
83{
84 return bbox_expanded_abs(box, std::max(box.xmax() - box.xmin(), box.ymax() - box.ymin()) * r);
85}
86
87inline Bbox_2 bbox_intersection(const Bbox_2 &box1, const Bbox_2 &box2)
88{
89 return Bbox_2(std::max(box1.xmin(), box2.xmin()),
90 std::max(box1.ymin(), box2.ymin()),
91 std::min(box1.xmax(), box2.xmax()),
92 std::min(box1.ymax(), box2.ymax()));
93}
94
95inline Real bbox_area(const Bbox_2 &box)
96{
97 return (box.xmax() - box.xmin()) * (box.ymax() - box.ymin());
98}
99
100inline Real bbox_diameter(const Bbox_2 &box)
101{
102 auto dx = box.xmax() - box.xmin();
103 auto dy = box.ymax() - box.ymin();
104 return std::sqrt(dx * dx + dy * dy);
105}
106
107inline std::string to_string(const Bbox_2 &box)
108{
109 return fmt::format("{:f} {:f} {:f} {:f}", box.xmin(), box.ymin(), box.xmax(), box.ymax());
110}
111
115inline Point_2 closest_on(const Segment_2 &s, const Point_2 &o)
116{
117 auto x = s.supporting_line().projection(o);
118 if (s.has_on(x))
119 return x;
120 return (CGAL::squared_distance(o, s.source()) <
121 CGAL::squared_distance(o, s.target())) ? s.source() : s.target();
122}
123
124} // namespace geo
125
126
130class Point_25
131{
132public:
133 Point_25() { }
134 Point_25(const Point_2 &x, int z) : _xy(x), _z(z) { }
135 Point_25(Real x, Real y, int z) : _xy(x,y), _z(z) { }
136 const Point_2& xy() const { return _xy; }
137 Real x() const { return _xy.x(); }
138 Real y() const { return _xy.y(); }
139 int z() const { return _z; }
140 Point_25 withZ(int z) const { return Point_25(_xy, z); }
141 Bbox_2 bbox() const { return _xy.bbox(); }
142 Point_25& operator=(const Point_25 &v) { _xy = v._xy; _z = v._z; return *this; }
143 bool operator<(const Point_25 &v) const { return (_z < v._z) || (_z == v._z && _xy < v._xy); }
144 bool operator==(const Point_25 &v) const { return _xy == v._xy && _z == v._z; }
145 Point_25 operator+(const Vector_2 &v) const { return Point_25(_xy + v, _z); }
146private:
147 Point_2 _xy;
148 int _z;
149};
150
154class Segment_25
155{
156public:
157 Segment_25() { }
158 Segment_25(const Segment_2 &s, int layer = 0) : mS2(s), mLayer(layer) {
159 }
160 Segment_25(const ::Point_2 &p, const ::Point_2 &q, int layer = 0) : mS2(p, q), mLayer(layer) {
161 }
162 const Segment_2& s2() const { return mS2; }
163 int z() const { return mLayer; }
164 void setLayer(int z) { mLayer = z; }
165 Point_25 source() const { return Point_25(mS2.source(), mLayer); }
166 Point_25 target() const { return Point_25(mS2.target(), mLayer); }
167 const Point_2& source_2() const { return mS2.source(); }
168 const Point_2& target_2() const { return mS2.target(); }
169 Real squared_length() const { return mS2.squared_length(); }
170 Real length() const { return std::sqrt(squared_length()); }
171 bool is_horizontal() const { return mS2.is_horizontal(); }
172 bool is_vertical() const { return mS2.is_vertical(); }
173 ::Vector_2 getDirection(Real s = 1.0) const;
174 ::Vector_2 getPerpendicularCCW(Real s = 1.0) const;
175 int angle45() const;
176 Real anglePi2() const { const auto v = mS2.to_vector(); return std::atan(v.y() / v.x()); }
177 Segment_25& rectify(Real angleTolerance);
178 int majorAxis() const { const auto v = mS2.to_vector(); return std::abs(v.y()) > std::abs(v.x()) ? 1 : 0; }
179 Segment_25 opposite() const { return Segment_25(mS2.opposite(), z()); }
180 bool isXOrdered() const { return mS2.source().x() <= mS2.target().x(); }
181 bool isYOrdered() const { return mS2.source().y() <= mS2.target().y(); }
182 Segment_25 orderedX() const { return isXOrdered() ? *this : opposite(); }
183 Segment_25 orderedY() const { return isYOrdered() ? *this : opposite(); }
184 bool operator<(const Segment_25 &s) const { return (source() < s.source()) || (source() == s.source() && target() < s.target()); }
185 bool operator==(const Segment_25 &s) const { return mLayer == s.mLayer && mS2 == s.mS2; }
186 int equals(const Segment_25 &s) const;
187 Real maxNorm() const { return std::max(std::abs(mS2.to_vector().x()), std::abs(mS2.to_vector().y())); }
188 Real angleWith(const Segment_25&) const;
189private:
190 Segment_2 mS2;
191 int mLayer;
192};
193
197inline int Segment_25::equals(const Segment_25 &s) const
198{
199 if (mLayer != s.mLayer)
200 return 0;
201 if (mS2 == s.mS2)
202 return 1;
203 return (mS2 == s.mS2.opposite()) ? -1 : 0;
204}
205
208inline ::Vector_2 Segment_25::getDirection(Real s) const
209{
210 const auto v = mS2.to_vector();
211 auto s0 = std::sqrt(v.squared_length());
212 return v * (s / s0);
213}
214inline ::Vector_2 Segment_25::getPerpendicularCCW(Real s) const
215{
216 auto vd = getDirection(s); return ::Vector_2(-vd.y(), vd.x());
217}
218inline Segment_25& Segment_25::rectify(Real angleTolerance)
219{
220 const auto v0 = mS2.source();
221 const auto v1 = mS2.target();
222 const auto A = std::abs(anglePi2());
223 if (std::abs(A) < angleTolerance)
224 mS2 = Segment_2(v0, Point_2(v1.x(), v0.y()));
225 else if (std::abs(A - M_PI_2) < angleTolerance)
226 mS2 = Segment_2(v0, Point_2(v0.x(), v1.y()));
227 return *this;
228}
229inline int Segment_25::angle45() const
230{
231 const auto dx = std::abs(source_2().x() - target_2().x());
232 const auto dy = std::abs(source_2().y() - target_2().y());
233 const auto t225 = std::sqrt(2.0) - 1.0;
234 const auto t675 = std::sqrt(2.0) + 1.0;
235 if (dy < t225 * dx)
236 return 0;
237 if (dy > t675 * dx)
238 return 90;
239 return 45;
240}
241inline Real Segment_25::angleWith(const Segment_25 &s) const
242{
243 const auto u = s2().to_vector();
244 const auto v = s.s2().to_vector();
245 const auto d = u.x() * v.x() + u.y() * v.y();
246 const auto x = u.x() * v.y() - u.y() * v.x();
247 return std::atan2(x, d);
248}
249
250
251//
252// Stream printing operators.
253//
254
255inline std::ostream& operator<<(std::ostream &os, const Point_2 &v)
256{
257 return os << '(' << v.x() << ',' << v.y() << ')';
258}
259
260inline std::ostream& operator<<(std::ostream &os, const Point_25 &v)
261{
262 return os << '(' << v.x() << ',' << v.y() << ',' << v.z() << ')';
263}
264
265inline std::ostream& operator<<(std::ostream &os, const Vector_2 &v)
266{
267 return os << '(' << v.x() << ',' << v.y() << ')';
268}
269
270inline std::ostream& operator<<(std::ostream &os, const Triangle_2 &A)
271{
272 return os << '<' << A.vertex(0) << ' ' << A.vertex(1) << ' ' << A.vertex(2) << '>';
273}
274
275inline std::ostream& operator<<(std::ostream &os, const Segment_2 &s)
276{
277 return os << '[' << s.source() << '_' << s.target() << ']';
278}
279
280inline std::ostream& operator<<(std::ostream &os, const Segment_25 &s)
281{
282 return os << '[' << s.source() << '_' << s.target() << "|z=" << s.z() << ']';
283}
284
285#endif // GYM_PCB_GEOMETRY_H
Definition Geometry.hpp:131
Definition Geometry.hpp:155
::Vector_2 getDirection(Real s=1.0) const
Definition Geometry.hpp:208
int equals(const Segment_25 &s) const
Definition Geometry.hpp:197