19 #include <boost/unordered_set.hpp> 45 virtual bool Offset(
const std::vector<Pt3d>& a_input,
48 double a_xyTol)
override;
50 bool Offset(
const std::vector<Pt3d>& a_input,
52 std::vector<std::vector<Pt3d>>& a_output,
53 std::vector<MePolyOffsetter::polytype>& a_outPolyType);
54 bool DoOffset(
const std::vector<Pt3d>& a_input);
64 std::vector<Pt3d>& a_result);
65 void SpecialRejection(
const std::vector<Pt3d>& a_input, std::vector<Pt3d>& a_output);
81 #define TWOPI 6.28318530717958647692528 82 #define PIOVER6 0.523598775598299 83 #define SEVENPIOVER3 7.330382858376180 84 #define FOURPIOVER3 4.188790204786390 85 #define SIN60 0.866025403784 86 #define TWOPIOVER3 2.094395102393200 87 #define PIOVER3 1.047197551196600 110 , m_setOffsetToZero(false)
112 , m_pType(OUTSIDE_POLY)
132 std::vector<Pt3d> input(a_input);
151 std::vector<std::vector<Pt3d>>& a_output,
152 std::vector<MePolyOffsetter::polytype>& a_outPolyType)
157 std::vector<Pt3d> input(a_input);
188 std::vector<Pt3d> result;
190 const Pt3d* pts(&a_input[0]);
191 int numpts = (int)a_input.size();
196 int in1 = numpts - 3;
197 int in2 = numpts - 2;
198 int in3 = numpts - 1;
199 double dx1 = pts[in1].
x - pts[in2].
x;
200 double dy1 = pts[in1].
y - pts[in2].
y;
201 double dx2 = pts[in3].
x - pts[in2].
x;
202 double dy2 = pts[in3].
y - pts[in2].
y;
204 if (
EQ_TOL(ang_beg, 0.0, 0.00001))
219 for (in3 = 0, num = 0; in3 < numpts; in3++)
222 dx1 = pts[in1].
x - pts[in2].
x;
223 dy1 = pts[in1].
y - pts[in2].
y;
224 dx2 = pts[in3].
x - pts[in2].
x;
225 dy2 = pts[in3].
y - pts[in2].
y;
227 if (
EQ_TOL(ang_end, 0.0, 0.00001))
232 if (npt_beg > -2 && npt_end > -2 && (ang_beg + ang_end >
FOURPIOVER3))
235 newpt.
x = (pts[in2].
x + pts[in1].
x) / 2.0 + (pts[in2].y - pts[in1].y) *
SIN60;
236 newpt.
y = (pts[in2].
y + pts[in1].
y) / 2.0 + (pts[in1].x - pts[in2].x) *
SIN60;
237 newpt.
z = (pts[in2].
z + pts[in1].
z) / 2.0;
251 if (result.size() < 3)
264 a_result.push_back(a_pt);
286 std::vector<Pt3d>& a_result)
289 double l1, l2, dl, offset, ptx, pty, ctheta, stheta, alpha;
294 l1 =
Mdist(pts[in1].x, pts[in1].y, pts[in2].x, pts[in2].y);
295 l2 =
Mdist(pts[in3].x, pts[in3].y, pts[in2].x, pts[in2].y);
296 offset = (l1 + l2) * 0.4330127019 / l1;
297 ptx = pts[in2].
x + offset * dx1;
298 pty = pts[in2].
y + offset * dy1;
299 ctheta = cos(ang_end / 2);
300 stheta = sin(ang_end / 2);
301 newpt.
x = ptx * ctheta - pty * stheta + (1.0 - ctheta) * pts[in2].x + stheta * pts[in2].y;
302 newpt.
y = ptx * stheta + pty * ctheta + (1.0 - ctheta) * pts[in2].y - stheta * pts[in2].x;
303 newpt.
z = (pts[in2].
z + pts[in1].
z) / 2.0;
307 l1 =
Mdist(pts[in1].x, pts[in1].y, pts[in2].x, pts[in2].y);
308 l2 =
Mdist(pts[in3].x, pts[in3].y, pts[in2].x, pts[in2].y);
314 ptx = pts[in2].
x + offset * dx1;
315 pty = pts[in2].
y + offset * dy1;
318 newpt.
x = ptx * ctheta - pty * stheta + (1.0 - ctheta) * pts[in2].x + stheta * pts[in2].y;
319 newpt.
y = ptx * stheta + pty * ctheta + (1.0 - ctheta) * pts[in2].y - stheta * pts[in2].x;
320 newpt.
z = (pts[in2].
z + pts[in1].
z) / 2.0;
324 ptx = pts[in2].
x + offset * dx1;
325 pty = pts[in2].
y + offset * dy1;
326 ctheta = cos(2 * alpha +
PIOVER3);
327 stheta = sin(2 * alpha +
PIOVER3);
328 newpt.
x = ptx * ctheta - pty * stheta + (1.0 - ctheta) * pts[in2].x + stheta * pts[in2].y;
329 newpt.
y = ptx * stheta + pty * ctheta + (1.0 - ctheta) * pts[in2].y - stheta * pts[in2].x;
330 newpt.
z = (pts[in2].
z + pts[in1].
z) / 2.0;
334 l1 =
Mdist(pts[in1].x, pts[in1].y, pts[in2].x, pts[in2].y);
335 l2 =
Mdist(pts[in3].x, pts[in3].y, pts[in2].x, pts[in2].y);
341 ptx = pts[in2].
x + offset * dx1;
342 pty = pts[in2].
y + offset * dy1;
345 newpt.
x = ptx * ctheta - pty * stheta + (1.0 - ctheta) * pts[in2].x + stheta * pts[in2].y;
346 newpt.
y = ptx * stheta + pty * ctheta + (1.0 - ctheta) * pts[in2].y - stheta * pts[in2].x;
347 newpt.
z = (pts[in2].
z + pts[in1].
z) / 2.0;
351 ptx = pts[in2].
x + offset * dx1;
352 pty = pts[in2].
y + offset * dy1;
353 ctheta = cos(2 * alpha +
PIOVER3);
354 stheta = sin(2 * alpha +
PIOVER3);
355 newpt.
x = ptx * ctheta - pty * stheta + (1.0 - ctheta) * pts[in2].x + stheta * pts[in2].y;
356 newpt.
y = ptx * stheta + pty * ctheta + (1.0 - ctheta) * pts[in2].y - stheta * pts[in2].x;
357 newpt.
z = (pts[in2].
z + pts[in1].
z) / 2.0;
361 ptx = pts[in2].
x + offset * dx1;
362 pty = pts[in2].
y + offset * dy1;
363 ctheta = cos(3 * alpha +
PIOVER3);
364 stheta = sin(3 * alpha +
PIOVER3);
365 newpt.
x = ptx * ctheta - pty * stheta + (1.0 - ctheta) * pts[in2].x + stheta * pts[in2].y;
366 newpt.
y = ptx * stheta + pty * ctheta + (1.0 - ctheta) * pts[in2].y - stheta * pts[in2].x;
367 newpt.
z = (pts[in2].
z + pts[in1].
z) / 2.0;
378 std::vector<Pt3d>& a_out)
390 const Pt3d* pts(&a_input[0]);
392 if (a_input.size() == 3 && a_out.size() == 3)
425 boost::unordered_set<size_t> setIdx;
426 for (
size_t i = 0; i < vCnt.size(); ++i)
434 for (
size_t i = a_input.size(); i <
m_output.
m_pts.size(); ++i)
436 if (setIdx.find(i) == setIdx.end() && vCnt[i] > 0)
473 while (cnt < l.size())
478 if (start >= l.size())
537 std::vector<Pt3d> input = {{0, 4, 0}, {0, 8, 0}, {0, 12, 0}, {4, 12, 0},
538 {8, 12, 0}, {12, 12, 0}, {12, 8, 0}, {12, 4, 0},
539 {12, 0, 0}, {8, 0, 0}, {4, 0, 0}, {0, 0, 0}};
540 std::vector<std::vector<Pt3d>> output;
541 std::vector<MePolyOffsetter::polytype> outPolyTypes;
542 pl.
Offset(input, ptype, output, outPolyTypes);
543 std::vector<Pt3d> base = {{3.4641, 3.4641, 0.0}, {3.4641, 6.0, 0.0}, {3.4641, 8.5359, 0.0},
544 {6.0, 8.5359, 0.0}, {8.5359, 8.5359, 0.0}, {8.5359, 6.0, 0.0},
545 {8.5359, 3.4641, 0.0}, {6.0, 3.4641, 0.0}};
574 std::vector<Pt3d> input = {{0, 4, 0}, {0, 8, 0}, {0, 12, 0}, {4, 12, 0}, {8, 12, 0},
575 {12, 12, 0}, {12, 8, 0}, {8, 6, 0}, {12, 4, 0}, {12, 0, 0},
576 {8, 0, 0}, {4, 0, 0}, {0, 0, 0}};
577 std::vector<std::vector<Pt3d>> output;
578 std::vector<MePolyOffsetter::polytype> outPolyTypes;
579 pl.
Offset(input, ptype, output, outPolyTypes);
580 std::vector<Pt3d> base = {{3.4641, 3.4641, 0.0}, {3.4641, 6.0, 0.0}, {3.4641, 8.5359, 0.0},
581 {5.4609, 8.5359, 0.0}, {4.6853, 8.0031, 0.0}, {4.6853, 3.9969, 0.0},
582 {5.4609, 3.4641, 0.0}};
609 std::vector<Pt3d> input = {{0, 4, 0}, {0, 0, 0}, {4, 0, 0}, {8, 0, 0}, {12, 0, 0},
610 {12, 4, 0}, {8, 6, 0}, {12, 8, 0}, {12, 12, 0}, {8, 12, 0},
611 {4, 12, 0}, {0, 12, 0}, {0, 8, 0}};
612 std::vector<std::vector<Pt3d>> output;
613 std::vector<MePolyOffsetter::polytype> outPolyTypes;
614 pl.
Offset(input, ptype, output, outPolyTypes);
615 std::vector<Pt3d> base = {{-3.4641, 10, 0}, {-3.4641, 6, 0}, {-3.4641, 2, 0},
616 {-3.2551, -1.1847, 0}, {-1.1847, -3.2551, 0}, {2, -3.4641, 0},
617 {6, -3.4641, 0}, {10, -3.4641, 0}, {13.1847, -3.2551, 0},
618 {15.2551, -1.1847, 0}, {15.4641, 2, 0}, {15.1206, 5.9286, 0},
619 {15.1206, 6.0713, 0}, {15.4641, 10, 0}, {15.2551, 13.1847, 0},
620 {13.1847, 15.2551, 0}, {10, 15.4641, 0}, {6, 15.4641, 0},
621 {2, 15.4641, 0}, {-1.18479, 15.2551, 0}, {-3.2551, 13.1847, 0}};
654 std::vector<Pt3d> input{{0, 4, 0}, {0, 0, 0}, {4, 0, 0},
655 {8, 0, 0}, {12, 0, 0}, {12, 4, 0},
656 {10, 4, 0}, {8, 4, 0}, {6, 4, 0},
657 {6, 5.33, 0}, {6, 6.66, 0}, {6, 8, 0},
658 {8, 8, 0}, {10, 8, 0}, {12, 8, 0},
659 {12, 12, 0}, {8, 12, 0}, {4, 12, 0},
660 {0, 12, 0}, {0, 8, 0}};
661 std::vector<std::vector<Pt3d>> output;
662 std::vector<MePolyOffsetter::polytype> outPolyTypes;
663 pl.
Offset(input, ptype, output, outPolyTypes);
664 std::vector<Pt3d> base{{7.1518, 5.7321, 0.0}, {7.1518, 5.9950, 0.0}, {7.1536, 6.2679, 0.0},
665 {9.0, 6.2679, 0.0}, {11.0, 6.2679, 0.0}, {12.7240, 6.0107, 0.0},
666 {14.8935, 6.9469, 0.0}, {15.4641, 10.0, 0.0}, {15.2552, 13.1848, 0.0},
667 {13.1848, 15.2552, 0.0}, {10.0, 15.4641, 0.0}, {6.0, 15.4641, 0.0},
668 {2.0, 15.4641, 0.0}, {-1.1848, 15.2552, 0.0}, {-3.2552, 13.1848, 0.0},
669 {-3.4641, 10.0, 0.0}, {-3.4641, 6.0, 0.0}, {-3.4641, 2.0, 0.0},
670 {-3.2552, -1.1848, 0.0}, {-1.1848, -3.2552, 0.0}, {2.0, -3.4641, 0.0},
671 {6.0, -3.4641, 0.0}, {10.0, -3.4641, 0.0}, {13.1848, -3.2552, 0.0},
672 {15.2552, -1.1848, 0.0}, {15.4641, 2.0, 0.0}, {14.8935, 5.0531, 0.0},
673 {12.7240, 5.9893, 0.0}, {11.0000, 5.7321, 0.0}, {9.0000, 5.7321, 0.0}};
706 std::vector<Pt3d> input{{0, 4, 0}, {0, 0, 0}, {4, 0, 0},
707 {8, 0, 0}, {12, 0, 0}, {12, 5, 0},
708 {10, 4, 0}, {8, 4, 0}, {6, 4, 0},
709 {6, 5.33, 0}, {6, 6.66, 0}, {6, 8, 0},
710 {8, 8, 0}, {10, 8, 0}, {12, 7, 0},
711 {12, 12, 0}, {8, 12, 0}, {4, 12, 0},
712 {0, 12, 0}, {0, 8, 0}};
713 std::vector<std::vector<Pt3d>> output;
714 std::vector<MePolyOffsetter::polytype> outPolyTypes;
715 pl.
Offset(input, ptype, output, outPolyTypes);
716 TS_ASSERT_EQUALS(2, output.size());
717 if (2 != output.size())
719 std::vector<Pt3d> base{{9.6076, 6.0, 0.0}, {9, 5.7320, 0.0}, {7.1518, 5.7320, 0.0},
720 {7.1518, 5.995, 0.0}, {7.1535, 6.2679, 0.0}, {9, 6.2679, 0.0}};
722 base = {{15.4709, 6.0, 0.0}, {16.3301, 9.5, 0.0}, {15.8881, 13.4151, 0.0},
723 {13.2506, 15.4360, 0.0}, {10.0, 15.4641, 0.0}, {6.0, 15.4641, 0.0},
724 {2.0, 15.4641, 0.0}, {-1.1848, 15.2551, 0.0}, {-3.2552, 13.1847, 0.0},
725 {-3.4641, 10.0, 0.0}, {-3.4641, 6.0, 0.0}, {-3.4641, 2.0, 0.0},
726 {-3.2552, -1.1847, 0.0}, {-1.1848, -3.2551, 0.0}, {2.0, -3.4641, 0.0},
727 {6.0, -3.4641, 0.0}, {10.0, -3.4641, 0.0}, {13.2506, -3.4360, 0.0},
728 {15.8881, -1.4151, 0.0}, {16.3301, 2.5, 0.0}};
730 std::vector<MePolyOffsetter::polytype> basePolyTypes = {MePolyOffsetter::NEWOUT_POLY,
731 MePolyOffsetter::INSIDE_POLY};
764 std::vector<Pt3d> input{{0, 4, 0}, {0, 0, 0}, {4, 0, 0},
765 {8, 0, 0}, {12, 0, 0}, {12, 5, 0},
766 {10, 4, 0}, {8, 4, 0}, {6, 4, 0},
767 {6, 5.33, 0}, {6, 6.66, 0}, {6, 8, 0},
768 {8, 8, 0}, {10, 8, 0}, {12, 7, 0},
769 {12, 12, 0}, {8, 12, 0}, {4, 12, 0},
770 {0, 12, 0}, {0, 8, 0}};
772 pl.
Offset(input, ptype, out, 1e-9);
773 TS_ASSERT_EQUALS(2, out.
m_loops.size());
776 std::vector<Pt3d> base{{-3.4641, 10, 0.0}, {-3.4641, 6, 0.0}, {-3.4641, 2, 0.0},
777 {-3.2552, -1.1847, 0.0}, {-1.1848, -3.2551, 0.0}, {2.0, -3.4641, 0.0},
778 {6.0, -3.4641, 0.0}, {10.0, -3.4641, 0.0}, {13.2506, -3.4360, 0.0},
779 {15.8881, -1.4151, 0.0}, {16.3301, 2.5, 0.0}, {15.2735, 6.8037, 0.0},
780 {12.1011, 7.5270, 0.0}, {10.1340, 6.2320, 0.0}, {9.0, 5.7320, 0.0},
781 {7.0, 5.7320, 0.0}, {7.1518, 4.665, 0.0}, {7.1518, 5.995, 0.0},
782 {7.1605, 7.33, 0.0}, {7.0, 6.2679, 0.0}, {9.0, 6.2679, 0.0},
783 {10.1340, 5.7679, 0.0}, {12.1011, 4.4730, 0.0}, {15.2735, 5.1963, 0.0},
784 {16.3301, 9.5, 0.0}, {15.8881, 13.4152, 0.0}, {13.2506, 15.4360, 0.0},
785 {10.0, 15.4641, 0.0}, {6.0, 15.4641, 0.0}, {2.0, 15.4641, 0.0},
786 {-1.1847, 15.2552, 0.0}, {-3.2551, 13.1848, 0.0}, {15.4709, 6.0, 0.0},
787 {9.6077, 6.0, 0.0}, {7.1518, 5.7321, 0.0}, {7.1536, 6.2679, 0.0}};
790 std::vector<MePolyOffsetter::polytype> basePolyTypes = {MePolyOffsetter::NEWOUT_POLY,
791 MePolyOffsetter::INSIDE_POLY};
794 std::vector<size_t> baseIdx = {33, 14, 34, 17, 35, 20};
796 baseIdx = {32, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
static BSHP< MePolyOffsetter > New()
Creates a BufferPoly class.
void testCase1()
tests offseting from the shape shown below
bool DoOffset(const std::vector< Pt3d > &a_input)
buffers the polygon
void SpecialRejection(const std::vector< Pt3d > &a_input, std::vector< Pt3d > &a_output)
a special case for removing points.
void testCreateClass()
tests creating the class
#define SIN60
prior calculated constant
bool gmEqualPointsXY(double x1, double y1, double x2, double y2, double tolerance)
bool m_setOffsetToZero
flag used in testing
#define PIOVER3
prior calculated constant
virtual bool Offset(const std::vector< Pt3d > &a_input, MePolyOffsetter::polytype a_pType, MePolyOffsetterOutput &a_output, double a_xyTol) override
Takes an input polyline and offsets it based on the distance of the segments that make up the polylin...
#define TWOPI
prior calculated constant
void testBox0()
test offsetting from a box polygon
bool gmPointInTriangleWithTol(const Pt3d *p1, const Pt3d *p2, const Pt3d *p3, double x, double y, double tol)
convenience class for holding output data from the MePolyOffsetter
std::vector< Pt3d > m_pts
locations used by polygons
#define SEVENPIOVER3
prior calculated constant
MePolyOffsetterOutput m_output
the new polygons created by this class
#define FOURPIOVER3
prior calculated constant
void testBox1()
tests offseting from the shape shown below
polytype
enum to identify types of polygons created by this class
double gmAngleBetween2DVectors(double dxp, double dyp, double dxn, double dyn)
double m_xyTol
tolerance for geometric comparisons
Offsets a polyline (in or out). The polyline forms a closed loop.
Does an internal offset from a polygon outer boundary (shrink) and does an external offset from a pol...
bool EQ_TOL(const _T &A, const _U &B, const _V &tolerance)
#define PIOVER6
prior calculated constant
#define TWOPIOVER3
prior calculated constant
cleans the output produced by MePolyOffsetter
std::vector< int > m_loopTypes
type of loop
void CheckToAddPoint(std::vector< Pt3d > &a_result, const Pt3d &a_pt)
checks to see if a point can be added to the resulting line
void testCase1a()
tests offseting from the shape shown below
double Mdist(_T x1, _U y1, _V x2, _W y2)
MePolyOffsetter::polytype m_pType
the type of polygon being offset
std::vector< std::vector< size_t > > m_loops
indexes of points that define loops
void testBox1a()
tests offseting from the shape shown below
void SelfIntersection(std::vector< Pt3d > &a_pLine)
Self intersection of a polyline.
BSHP< MePolyCleaner > m_intersector
class to clean the offset from the polygon
void FindDuplicatesAndOrderLoops(const std::vector< Pt3d > &a_input)
Finds duplicate points and orders the loops.
void ProcessAngleSegmentEnd(int npt_end, double ang_end, int in1, int in2, int in3, double dx1, double dy1, const Pt3d *pts, std::vector< Pt3d > &a_result)
handles inserting points around the end of a segment.
void testCase1b()
tests offseting from the shape shown below
MePolyOffsetterImpl()
constructor