Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
testPolygonClipping.cpp
Go to the documentation of this file.
1#include <SutherlandHodgman.h>
3#include <Polygon2D.h>
4#include <filesystem>
5#include <fstream>
6#include <iostream>
7#include <stdexcept>
8
9using V=Eigen::Vector2d;
10void require(bool condition,const char* message)
11{
12 if(!condition)
13 {
14 throw std::runtime_error(message);
15 }
16}
17void check(const std::vector<V>& subject,const std::vector<V>& boundary)
18{
19 const auto clipped=model::SutherlandHodgman::clip(subject,boundary);
20 V low=subject.front(),high=low;
21 for(const auto& p : subject)
22 {
23 low=low.cwiseMin(p);
24 high=high.cwiseMax(p);
25 }
26 const double tolerance=1.e-8*std::max(1.0,(high-low).norm());
27 const auto bounded=[&](const V& p)
28 {
29 require(p.allFinite(),"Clipping produced a nonfinite point");
30 require((low-p).maxCoeff()<=tolerance && (p-high).maxCoeff()<=tolerance,
31 "Clipping extrapolated outside the subject bounds");
32 for(size_t k=0;k<boundary.size();++k)
33 {
34 const V edge=boundary[(k+1)%boundary.size()]-boundary[k];
35 const V relative=p-boundary[k];
36 require(edge.x()*relative.y()-edge.y()*relative.x()>=-tolerance*edge.norm(),
37 "Clipped point lies outside its grain patch");
38 }
39 };
40 for(const auto& p : clipped)
41 {
42 bounded(p);
43 }
44 const auto triangles=model::triangulateLoopArea(clipped);
45 for(const auto& t : triangles)
46 {
47 for(const auto& p : t)
48 {
49 bounded(p);
50 }
51 }
52 // Check rendered coverage against the original polygon and grain patch,
53 // independently of the clipped contour supplied to the triangulator.
54 for(int i=0;i<29;++i)
55 {
56 for(int j=0;j<29;++j)
57 {
58 const V p=low+(high-low).cwiseProduct(V((i+.371)/29,(j+.613)/29));
59 const bool expected=model::Polygon2D::windingNumber(p,subject)!=0 &&
61 size_t hits=0;
62 for(const auto& t : triangles)
63 {
64 hits+=model::Polygon2D::windingNumber(p,std::vector<V>{t[0],t[1],t[2]})!=0;
65 }
66 require(hits==size_t(expected),"Shaded coverage disagrees with polygon/patch intersection");
67 }
68 }
69}
70int main(int argc,char** argv)
71{
72 try
73 {
74 require(argc==2,"Expected repository root");
75 const std::vector<V> square{{0,0},{1,0},{1,1},{0,1}};
76 require(model::SutherlandHodgman::clip(std::vector<V>{{-3,0},{-2,0},{-2,1},{-3,1}},square).empty(),
77 "Disjoint clipping should remain empty through subsequent edges");
78 require(model::SutherlandHodgman::clip(std::vector<V>{},square).empty(),"Empty subject was not retained");
79 check(square,square);
80 check({{-.2,.2},{1.2,.2},{1.2,.8},{-.2,.8}},square);
81 check({{0,0},{1,1},{0,1},{1,0}},square);
82 std::ifstream in(std::filesystem::path(argv[1])/"tests/data/polycrystalClipSpikes.txt");
83 size_t cases=0;
84 in>>cases;
85 require(cases==9,"Missing saved spike contours");
86 for(size_t k=0;k<cases;++k)
87 {
88 size_t n,m;
89 in>>n>>m;
90 std::vector<V> subject(n),boundary(m);
91 for(auto& p : subject)
92 {
93 in>>p.x()>>p.y();
94 }
95 for(auto& p : boundary)
96 {
97 in>>p.x()>>p.y();
98 }
99 require(bool(in),"Incomplete saved spike contour");
100 for(int direction=0;direction<2;++direction)
101 {
102 for(size_t start=0;start<subject.size();++start)
103 {
104 check(subject,boundary);
105 std::rotate(subject.begin(),subject.begin()+1,subject.end());
106 }
107 std::reverse(subject.begin(),subject.end());
108 }
109 }
110 std::cout<<"PASS: bounded clipping and spike-free loop-area coverage\n";
111 return 0;
112 }
113 catch(const std::exception& error)
114 {
115 std::cerr<<error.what()<<'\n';
116 return 1;
117 }
118}
Eigen::Vector3d V
static constexpr std::vector< PointType > clip(const std::vector< PointType > &subject, const std::vector< PointType > &boundary)
final point of the source segment t
std::vector< std::array< Eigen::Vector2d, 3 > > triangulateLoopArea(const std::vector< Eigen::Vector2d > &contour)
static int windingNumber(const PointType &P, const std::vector< PointType > &V)
Definition Polygon2D.h:56
void require(bool condition, const char *message)
Eigen::Vector2d V
void check(const std::vector< V > &subject, const std::vector< V > &boundary)
int j
void argv
void in
void b int argc
vertex p[3]
int k
int i
void t struct mesh * m