void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aShape, const SHAPE_POLY_SET& aOtherShape, bool aFastMode ) { Clipper c; if( !aFastMode ) c.StrictlySimple( true ); BOOST_FOREACH( const POLYGON& poly, aShape.m_polys ) { for( unsigned int i = 0; i < poly.size(); i++ ) c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptSubject, true ); } BOOST_FOREACH( const POLYGON& poly, aOtherShape.m_polys ) { for( unsigned int i = 0; i < poly.size(); i++ ) c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptClip, true ); } PolyTree solution; c.Execute( aType, solution, pftNonZero, pftNonZero ); importTree( &solution ); }
void Cold::growFast(const Climber& climber, Clipper& clipper) { const Id& chunkId(climber.chunkId()); const std::size_t chunkNum(climber.chunkNum()); if (clipper.insert(chunkId, chunkNum)) { FastSlot& slot(m_chunkVec[chunkNum]); while (slot.flag.test_and_set()) ; const bool exists(slot.mark.load()); slot.mark.store(true); auto& countedChunk(slot.chunk); if (!countedChunk) countedChunk.reset(new CountedChunk()); std::lock_guard<std::mutex> chunkLock(countedChunk->mutex); slot.flag.clear(); if (!countedChunk->refs.count(clipper.id())) { countedChunk->refs[clipper.id()] = 1; } else { ++countedChunk->refs[clipper.id()]; } ensureChunk(climber, countedChunk->chunk, exists); } }
void Cold::growSlow(const Climber& climber, Clipper& clipper) { const Id& chunkId(climber.chunkId()); if (clipper.insert(chunkId, climber.chunkNum())) { std::unique_lock<std::mutex> mapLock(m_mapMutex); const bool exists(m_chunkMap.count(chunkId)); auto& countedChunk(m_chunkMap[chunkId]); if (!exists) countedChunk.reset(new CountedChunk()); std::lock_guard<std::mutex> chunkLock(countedChunk->mutex); mapLock.unlock(); if (!countedChunk->refs.count(clipper.id())) { countedChunk->refs[clipper.id()] = 1; } else { ++countedChunk->refs[clipper.id()]; } ensureChunk(climber, countedChunk->chunk, exists); } }
void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType aType, const SHAPE_POLY_SET& aShape, const SHAPE_POLY_SET& aOtherShape, POLYGON_MODE aFastMode ) { Clipper c; if( aFastMode == PM_STRICTLY_SIMPLE ) c.StrictlySimple( true ); for( const POLYGON& poly : aShape.m_polys ) { for( unsigned int i = 0; i < poly.size(); i++ ) c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptSubject, true ); } for( const POLYGON& poly : aOtherShape.m_polys ) { for( unsigned int i = 0; i < poly.size(); i++ ) c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), ptClip, true ); } PolyTree solution; c.Execute( aType, solution, pftNonZero, pftNonZero ); importTree( &solution ); }
bool SubtractFrom(const Paths &a, Paths *b) { if (a.empty() || b->empty()) return true; Clipper c; return c.AddPaths(*b, ptSubject, true) && c.AddPaths(a, ptClip, true) && c.Execute(ctDifference, *b); }
void SHAPE_POLY_SET::booleanOp( ClipperLib::ClipType type, const SHAPE_POLY_SET& b ) { Clipper c; c.StrictlySimple( true ); BOOST_FOREACH ( Paths& subject, m_polys ) { c.AddPaths(subject, ptSubject, true); }
bool CopyAndForceOrientation(const Paths &paths, bool orientation, Paths *out) { // Use Clipper to convert paths to a PolyTree. Clipper c; PolyTree solution; if (!c.AddPaths(paths, ptSubject, true) || !c.Execute(ctUnion, solution)) return false; out->clear(); CopyAndForceOrientation(solution, orientation, out); return true; }
void CArea::Xor(const CArea& a2) { Clipper c; TPolyPolygon pp1, pp2; MakePolyPoly(*this, pp1); MakePolyPoly(a2, pp2); c.AddPaths(pp1, ptSubject, true); c.AddPaths(pp2, ptClip, true); TPolyPolygon solution; c.Execute(ctXor, solution); SetFromResult(*this, solution); }
void TerraGenerator::buildFromRegions(const Regions& regions, const RegionContext& regionContext) { // merge all regions together Clipper clipper; for (const Region& region : regions) clipper.AddPaths(region.points, ptSubject, true); Paths result; clipper.Execute(ctUnion, result, pftNonZero, pftNonZero); buildFromPaths(result, regionContext); }
void SoftwareGraphicsDevice::Render(const Mesh &M) { //uses AliasRender to render the provided polygon. MeshVertex Polygon[10]; int i,i2,i2p1,ic=M.IndexCount(),LocalVC; const MeshVertex *V = M.Vertices(); const DWORD *I = M.Indices(); Clipper Clip; Clip.Init(float(Bmp.Width()-1),float(Bmp.Height()-1)); //prepare for clipping Matrix4 VTranslate = Matrix4::Translation(Vec3f(1.0f,1.0f,0.0f)); Matrix4 VScale = Matrix4::Scaling(Vec3f(Bmp.Width()/2.0f,Bmp.Height()/2.0f,1.0f)); Matrix4 Viewport = VTranslate * VScale; Matrix4 TotalViewport = Total * Viewport; //get the total transform for(i=0; i<ic; i+=3) { LocalVC = 3; Polygon[0] = V[I[i+0]]; Polygon[1] = V[I[i+1]]; Polygon[2] = V[I[i+2]]; //load the current triangle // // Transform into screen space // Polygon[0].Pos = TotalViewport.TransformPoint(Polygon[0].Pos); Polygon[1].Pos = TotalViewport.TransformPoint(Polygon[1].Pos); Polygon[2].Pos = TotalViewport.TransformPoint(Polygon[2].Pos); Clip.Clip(Polygon, LocalVC); //clip if(_Wireframe) { for(i2=0; i2<LocalVC; i2++) { i2p1 = i2 + 1; if(i2p1 == LocalVC) i2p1 = 0; //if we're in _Wireframe, draw lines representing the polygon if(Polygon[i2].Pos.z >= 0.0f && Polygon[i2].Pos.z <= 1.0f && Polygon[i2p1].Pos.z >= 0.0f && Polygon[i2p1].Pos.z <= 1.0f) PR.DrawLine(Bmp, int(Polygon[i2].Pos.x), int(Polygon[i2].Pos.y), int(Polygon[i2p1].Pos.x), int(Polygon[i2p1].Pos.y), Polygon[i2].Color); } } else { //if we're not in _Wireframe, draw the polygon directly PR.DrawPolygon(Bmp, Z, Polygon, LocalVC); } } }
Vector<Vector<Point2> > Geometry::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open) { using namespace ClipperLib; ClipType op = ctUnion; switch (p_op) { case OPERATION_UNION: op = ctUnion; break; case OPERATION_DIFFERENCE: op = ctDifference; break; case OPERATION_INTERSECTION: op = ctIntersection; break; case OPERATION_XOR: op = ctXor; break; } Path path_a, path_b; // Need to scale points (Clipper's requirement for robust computation) for (int i = 0; i != p_polypath_a.size(); ++i) { path_a << IntPoint(p_polypath_a[i].x * SCALE_FACTOR, p_polypath_a[i].y * SCALE_FACTOR); } for (int i = 0; i != p_polypath_b.size(); ++i) { path_b << IntPoint(p_polypath_b[i].x * SCALE_FACTOR, p_polypath_b[i].y * SCALE_FACTOR); } Clipper clp; clp.AddPath(path_a, ptSubject, !is_a_open); // forward compatible with Clipper 10.0.0 clp.AddPath(path_b, ptClip, true); // polylines cannot be set as clip Paths paths; if (is_a_open) { PolyTree tree; // needed to populate polylines clp.Execute(op, tree); OpenPathsFromPolyTree(tree, paths); } else { clp.Execute(op, paths); // works on closed polygons only } // Have to scale points down now Vector<Vector<Point2> > polypaths; for (Paths::size_type i = 0; i < paths.size(); ++i) { Vector<Vector2> polypath; const Path &scaled_path = paths[i]; for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { polypath.push_back(Point2( static_cast<real_t>(scaled_path[j].X) / SCALE_FACTOR, static_cast<real_t>(scaled_path[j].Y) / SCALE_FACTOR)); } polypaths.push_back(polypath); } return polypaths; }
int main(int argc, char * argv[]) { printf("hello\n"); Polygon p1; Polygon p2; Polygons ps1; Polygons ps2; IntPoint i1(0, 0); IntPoint i2(0, 100); IntPoint i3(100, 100); IntPoint i4(100, 0); IntPoint j1(0, 0); IntPoint j2(50, 200); IntPoint j3(100, 0); p1.push_back(i1); p1.push_back(i2); p1.push_back(i3); p1.push_back(i4); p2.push_back(j1); p2.push_back(j2); p2.push_back(j3); ps1.push_back(p1); ps2.push_back(p2); Clipper clipper; clipper.AddPolygons(ps1, ptSubject); clipper.AddPolygons(ps2, ptClip); Polygons soln; clipper.Execute(ctIntersection, soln); for(int i = 0; i < soln.size(); i++) { Polygon& p = soln[i]; for(int j = 0; j < p.size(); j++) { printf("Point:(%lld,%lld)\n", p[j].X, p[j].Y); } } printf("hehe\n"); return 0; }
void gl_RenderBSPNode (void *node) { if (numnodes == 0) { DoSubsector (subsectors); return; } while (!((size_t)node & 1)) // Keep going until found a subsector { node_t *bsp = (node_t *)node; // Decide which side the view point is on. int side = R_PointOnSide(viewx, viewy, bsp); // Recursively divide front space (toward the viewer). gl_RenderBSPNode (bsp->children[side]); // Possibly divide back space (away from the viewer). side ^= 1; if (!clipper.CheckBox(bsp->bbox[side])) { return; } node = bsp->children[side]; } DoSubsector ((subsector_t *)((BYTE *)node - 1)); }
static void OffsetSpansWithObrounds(const CArea& area, TPolyPolygon &pp_new, double radius) { Clipper c; for(std::list<CCurve>::const_iterator It = area.m_curves.begin(); It != area.m_curves.end(); It++) { pts_for_AddVertex.clear(); const CCurve& curve = *It; const CVertex* prev_vertex = NULL; for(std::list<CVertex>::const_iterator It2 = curve.m_vertices.begin(); It2 != curve.m_vertices.end(); It2++) { const CVertex& vertex = *It2; if(prev_vertex) { MakeObround(prev_vertex->m_p, vertex, radius); TPolygon loopy_polygon; loopy_polygon.reserve(pts_for_AddVertex.size()); for(std::list<DoubleAreaPoint>::iterator It = pts_for_AddVertex.begin(); It != pts_for_AddVertex.end(); It++) { loopy_polygon.push_back(It->int_point()); } c.AddPath(loopy_polygon, ptSubject, true); pts_for_AddVertex.clear(); } prev_vertex = &vertex; } } pp_new.clear(); c.Execute(ctUnion, pp_new, pftNonZero, pftNonZero); // reverse all the resulting polygons TPolyPolygon copy = pp_new; pp_new.clear(); pp_new.resize(copy.size()); for(unsigned int i = 0; i < copy.size(); i++) { const TPolygon& p = copy[i]; TPolygon p_new; p_new.resize(p.size()); std::size_t size_minus_one = p.size() - 1; for(unsigned int j = 0; j < p.size(); j++)p_new[j] = p[size_minus_one - j]; pp_new[i] = p_new; } }
static void DoSubsector(subsector_t * sub) { int i; sector_t * sector; sector_t * fakesector; sector_t fake; GLFlat glflat; GLSprite glsprite; // check for visibility of this entire subsector! This requires GL nodes! if (!clipper.CheckBox(sub->bbox)) return; #ifdef _MSC_VER #ifdef _DEBUG if (sub->sector-sectors==931) { __asm nop } #endif #endif sector=sub->sector; if (!sector) return; sector->MoreFlags |= SECF_DRAWN; fakesector=gl_FakeFlat(sector, &fake, false); // [RH] Add particles //int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight); for (i = ParticlesInSubsec[sub-subsectors]; i != NO_PARTICLE; i = Particles[i].snext) { glsprite.ProcessParticle(Particles + i, fakesector);//, 0, 0); } AddLines(sub, fakesector); RenderThings(sub, fakesector); // Subsectors with only 2 lines cannot have any area! if (sub->numlines>2 || (sub->hacked&1)) { // Exclude the case when it tries to render a sector with a heightsec // but undetermined heightsec state. This can only happen if the // subsector is obstructed but not excluded due to a large bounding box. // Due to the way a BSP works such a subsector can never be visible if (!sector->heightsec || sector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || in_area!=area_default) { if (sector != sub->render_sector) { sector = sub->render_sector; // the planes of this subsector are faked to belong to another sector // This means we need the heightsec parts and light info of the render sector, not the actual one! fakesector = gl_FakeFlat(sector, &fake, false); } SetupFlat.Clock(); glflat.ProcessSector(fakesector, sub); SetupFlat.Unclock(); } } }
bool UnionInto(const Paths &paths, Paths *result) { if (paths.empty()) return true; if (result->empty()) { *result = paths; return true; } Clipper c; if (!c.AddPaths(*result, ptSubject, true) || !c.AddPaths(paths, ptClip, true)) { return false; } Paths solution; if (!c.Execute(ctUnion, solution)) { return false; } result->swap(solution); return true; }
void UpdatePolygons(bool updateSolutionOnly) { if (VertCount < 0) VertCount = -VertCount; if (VertCount > 50) VertCount = 50; if (VertCount < 3) VertCount = 3; Clipper c; if (!updateSolutionOnly) { delta = 0.0; RECT r; GetWindowRect(hStatus, &r); int statusHeight = r.bottom - r.top; GetClientRect(hWnd, &r); sub.resize(1); clp.resize(1); //int ints[] = {0,0,0, -100,100, -100,100, 0}; //int ints2[] = {0, 100, 100, -200,0, -200,100, 100}; //MakePolygonFromInts(ints, 8, sub[0]); //TranslatePolygon(sub[0], 100,220); //MakePolygonFromInts(ints2, 8, clp[0]); //TranslatePolygon(sub[1], 100,220); MakeRandomPoly(sub[0], r.right, r.bottom - statusHeight, VertCount); MakeRandomPoly(clp[0], r.right, r.bottom - statusHeight, VertCount); //SaveToFile("subj.txt", sub); //SaveToFile("clip.txt", clp); } c.AddPolygons(sub, ptSubject); c.AddPolygons(clp, ptClip); c.Execute(ct, sol, pft, pft); if (delta != 0.0) OffsetPolygons(sol,sol,delta,jt); InvalidateRect(hWnd, NULL, false); }
FDrawInfo *FDrawInfo::StartDrawInfo(FRenderViewpoint &parentvp, HWViewpointUniforms *uniforms) { FDrawInfo *di=di_list.GetNew(); di->mVBO = GLRenderer->mVBO; di->mClipper = &staticClipper; di->Viewpoint = parentvp; if (uniforms) { di->VPUniforms = *uniforms; // The clip planes will never be inherited from the parent drawinfo. di->VPUniforms.mClipLine.X = -1000001.f; di->VPUniforms.mClipHeight = 0; } else di->VPUniforms.SetDefaults(); di->mClipper->SetViewpoint(di->Viewpoint); staticClipper.Clear(); di->StartScene(); return di; }
int main(int argc, char* argv[]) { ////quick test with random paths ... //Paths ss, cc, sss; //PolyFillType pft = pftNonZero;//pftEvenOdd;// //srand((int)time(0)); //MakeRandomPoly(100, 400, 400, ss); //MakeRandomPoly(100, 400, 400, cc); //Clipper cpr; //cpr.AddPaths(ss, ptSubject, true); //cpr.AddPaths(cc, ptClip, true); //cpr.Execute(ctIntersection, sss, pft, pft); ////sss = Clipper.OffsetPolygons(sss, -5.0 * scale, JoinType.jtMiter, 4); //SVGBuilder svg1; //svg1.style.pft = pft; //svg1.style.brushClr = 0x2000009c; //svg1.style.penClr = 0xFFd3d3da; //svg1.AddPaths(ss); //svg1.style.brushClr = 0x209c0000; //svg1.style.penClr = 0xFFFFa07a; //svg1.AddPaths(cc); //svg1.style.brushClr = 0xAA80ff9c; //svg1.style.penClr = 0xFF003300; //svg1.AddPaths(sss); //svg1.SaveToFile("solution.svg", 1.0); //return 0; if (argc > 1 && (strcmp(argv[1], "-b") == 0 || strcmp(argv[1], "--benchmark") == 0)) { //do a benchmark test that creates a subject and a clip polygon both with //100 vertices randomly placed in a 400 * 400 space. Then perform an //intersection operation based on even-odd filling. Repeat all this X times. int loop_cnt = 100; char * dummy; if (argc > 2) loop_cnt = strtol(argv[2], &dummy, 10); if (loop_cnt == 0) loop_cnt = 100; cout << "\nPerforming " << loop_cnt << " random intersection operations ... "; srand((int)time(0)); int error_cnt = 0; Paths subject, clip, solution; Clipper clpr; time_t time_start = clock(); for (int i = 0; i < loop_cnt; i++) { MakeRandomPoly(100, 400, 400, subject); MakeRandomPoly(100, 400, 400, clip); clpr.Clear(); clpr.AddPaths(subject, ptSubject, true); clpr.AddPaths(clip, ptClip, true); if (!clpr.Execute(ctIntersection, solution, pftEvenOdd, pftEvenOdd)) error_cnt++; } double time_elapsed = double(clock() - time_start)/CLOCKS_PER_SEC; cout << "\nFinished in " << time_elapsed << " secs with "; cout << error_cnt << " errors.\n\n"; //let's save the very last result ... SaveToFile("Subject.txt", subject); SaveToFile("Clip.txt", clip); SaveToFile("Solution.txt", solution); //and see it as an image too ... SVGBuilder svg; svg.style.penWidth = 0.8; svg.style.pft = pftEvenOdd; svg.style.brushClr = 0x1200009C; svg.style.penClr = 0xCCD3D3DA; svg.AddPaths(subject); svg.style.brushClr = 0x129C0000; svg.style.penClr = 0xCCFFA07A; svg.AddPaths(clip); svg.style.brushClr = 0x6080ff9C; svg.style.penClr = 0xFF003300; svg.style.pft = pftNonZero; svg.AddPaths(solution); svg.SaveToFile("solution.svg"); return 0; } if (argc < 3) { cout << "\nUSAGE:\n" << "clipper --benchmark [LOOP_COUNT (default = 100)]\n" << "or\n" << "clipper sub_file clp_file CLIPTYPE [SUB_FILL CLP_FILL] [PRECISION] [SVG_SCALE]\n" << "where ...\n" << " CLIPTYPE = INTERSECTION or UNION or DIFFERENCE or XOR, and\n" << " ???_FILL = EVENODD or NONZERO (default = NONZERO)\n" << " PRECISION = in decimal places (default = 0)\n" << " SVG_SCALE = SVG output scale (default = 1.0)\n\n"; cout << "\nINPUT AND OUTPUT FILE FORMAT ([optional] {comments}):\n" << "Polygon Count\n" << "Vertex Count {first polygon}\n" << "X, Y[,] {first vertex}\n" << "X, Y[,] {next vertex}\n" << "{etc.}\n" << "Vertex Count {second polygon, if there is one}\n" << "X, Y[,] {first vertex of second polygon}\n" << "{etc.}\n\n"; return 1; } int scale_log10 = 0; char * dummy; if (argc > 6) scale_log10 = strtol(argv[6], &dummy, 10); double scale = std::pow(double(10), scale_log10); double svg_scale = 1.0; if (argc > 7) svg_scale = strtod(argv[7], &dummy); svg_scale /= scale; Paths subject, clip; if (!LoadFromFile(subject, argv[1], scale)) { cerr << "\nCan't open the file " << argv[1] << " or the file format is invalid.\n"; return 1; } if (!LoadFromFile(clip, argv[2], scale)) { cerr << "\nCan't open the file " << argv[2] << " or the file format is invalid.\n"; return 1; } ClipType clipType = ctIntersection; const string sClipType[] = {"INTERSECTION", "UNION", "DIFFERENCE", "XOR"}; if (argc > 3) { if (_stricmp(argv[3], "XOR") == 0) clipType = ctXor; else if (_stricmp(argv[3], "UNION") == 0) clipType = ctUnion; else if (_stricmp(argv[3], "DIFFERENCE") == 0) clipType = ctDifference; else clipType = ctIntersection; } PolyFillType subj_pft = pftNonZero, clip_pft = pftNonZero; if (argc > 5) { if (_stricmp(argv[4], "EVENODD") == 0) subj_pft = pftEvenOdd; if (_stricmp(argv[5], "EVENODD") == 0) clip_pft = pftEvenOdd; } Clipper c; c.AddPaths(subject, ptSubject, true); c.AddPaths(clip, ptClip, true); Paths solution; bool succeeded = c.Execute(clipType, solution, subj_pft, clip_pft); string s = "Subjects ("; s += (subj_pft == pftEvenOdd ? "EVENODD)" : "NONZERO)"); //ie don't change the paths back to the original size if we've //just down-sized them to a manageable (all-in-one-screen) size ... //if (scale < 1) scale = 1; SaveToConsole(s, subject, scale); s = "Clips ("; s += (clip_pft == pftEvenOdd ? "EVENODD)" : "NONZERO)"); SaveToConsole(s, clip, scale); if (succeeded) { s = "Solution (using " + sClipType[clipType] + ")"; //SaveToConsole(s, solution, scale); SaveToFile("solution.txt", solution, scale); //OffsetPaths(solution, solution, -5.0 *scale, jtRound, etClosed); //let's see the result too ... SVGBuilder svg; svg.style.penWidth = 0.8; svg.style.brushClr = 0x1200009C; svg.style.penClr = 0xCCD3D3DA; svg.style.pft = subj_pft; svg.AddPaths(subject); svg.style.brushClr = 0x129C0000; svg.style.penClr = 0xCCFFA07A; svg.style.pft = clip_pft; svg.AddPaths(clip); svg.style.brushClr = 0x6080ff9C; svg.style.penClr = 0xFF003300; svg.style.pft = pftNonZero; svg.AddPaths(solution); svg.SaveToFile("solution.svg", svg_scale); } else cout << (sClipType[clipType] + " failed!\n\n"); return 0; }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { //Input: operation, fillType, subj, (subjclosed), clip1, (clip1closed), clip2, ... if (nrhs < 3) mexWarnMsgTxt("mexPolygonExecute: 3 input arguments expected: operation, fillType, subj, (subjclosed), (clip1), (clip1closed), (clip2), ...!"); //Output: solultion (tree) if (nlhs != 1 && nlhs !=2) mexWarnMsgTxt("mexPolygonExecute: 1-2 output arguments expected!"); //Clipper Clipper c; //Operation ClipType clipT = (ClipType) (int) mxGetScalar(prhs[0]); //PolyFillType //see http://glprogramming.com/red/chapter11.html //PolyFillType {pftEvenOdd, pftNonZero, pftPositive, pftNegative }; PolyFillType subjFillType = pftEvenOdd; PolyFillType clipFillType = pftEvenOdd; int nf = mxGetNumberOfElements(prhs[1]); double* type = mxGetPr(prhs[1]); if (nf > 0) { subjFillType = (PolyFillType) int(*type); } if (nf > 1) { type++; clipFillType = (PolyFillType) int(*type); } //cout << "fill types: " << (int) subjFillType << " " << (int) clipFillType << endl; cout.flush(); //Polygon Paths poly; int n = 2; bool closed = true; //Subject Poly toPolygon(prhs[n], poly); n++; if (n < nrhs && !mxIsCell(prhs[n])) { closed = mxGetScalar(prhs[n]) > 0; n++; } c.AddPaths(poly, ptSubject, closed); //Clipping Polys for(; n < nrhs; n++) { //cout << "clipping poly: " << n << endl; cout.flush(); if (mxIsCell(prhs[n])) { toPolygon(prhs[n], poly); if (n + 1 < nrhs && !mxIsCell(prhs[n+1])) { n++; closed = mxGetScalar(prhs[n]) > 0; } else { closed = true; } c.AddPaths(poly, ptClip, closed); } else { break; } } if (n < nrhs) { mexWarnMsgTxt("mexPolygonExecute: inconsistent input arguments in polygons!"); } //Execute //cout << "execute: " << n << endl; cout.flush(); if (nlhs < 2) { Paths solution; c.Execute(clipT, solution, subjFillType, clipFillType); plhs[0] = fromPolygon(solution); } else { //poly + tree PolyTree polytree; c.Execute(clipT, polytree, subjFillType, clipFillType); fromPolygonTree(&polytree, plhs[0], plhs[1]); } return; };
static AS3_Val clipPolygon(void* self, AS3_Val args) { AS3_Val asSubjectVertices; AS3_Val asClipVertices; int subjectVerticeCount, clipVerticeCount, clipTypeArg, subjectFillTypeArg, clipFillTypeArg; // Get the function arguments (subjectVertices:Array, subjectVerticeCount:int, extractVertices:Array, // extractVerticeCount:int, clipType:int, subjectFillType:int, clipFillType:int) AS3_ArrayValue( args, "AS3ValType, IntType, AS3ValType, IntType, IntType, IntType, IntType", &asSubjectVertices, &subjectVerticeCount, &asClipVertices, &clipVerticeCount, &clipTypeArg, &subjectFillTypeArg, &clipFillTypeArg ); Polygon subjectPolygon(subjectVerticeCount / 2), clipPolygon(clipVerticeCount / 2); Polygons solution; // Populate the subject polygon for (int i = 0; i < subjectVerticeCount; i += 2) { subjectPolygon[i / 2] = IntPoint( AS3_IntValue(AS3_Get( asSubjectVertices, AS3_Int(i) )), AS3_IntValue(AS3_Get( asSubjectVertices, AS3_Int(i+1) )) ); } // Populate the clip polygon for (int i = 0; i < clipVerticeCount; i += 2) { clipPolygon[i / 2] = IntPoint( AS3_IntValue(AS3_Get( asClipVertices, AS3_Int(i) )), AS3_IntValue(AS3_Get( asClipVertices, AS3_Int(i+1) )) ); } // Create the AS3 return array AS3_Val returnArray = AS3_Array(""); ClipType clipType; switch (clipTypeArg) { default: case 0: clipType = ctIntersection; break; case 1: clipType = ctUnion; break; case 2: clipType = ctDifference; break; case 3: clipType = ctXor; break; } PolyFillType subjectFillType, clipFillType; switch (subjectFillTypeArg) { default: case 0: subjectFillType = pftEvenOdd; break; case 1: subjectFillType = pftNonZero; break; } switch (clipFillTypeArg) { default: case 0: clipFillType = pftEvenOdd; break; case 1: clipFillType = pftNonZero; break; } Clipper c; c.AddPolygon(subjectPolygon, ptSubject); c.AddPolygon(clipPolygon, ptClip); if (c.Execute(clipType, solution, subjectFillType, clipFillType)) { for (int i = 0; i < (int)solution.size(); i++) { // Create a new AS3 array AS3_Val verticeArray = AS3_Array(""); for (int j = 0; j < (int)solution[i].size(); j++) { // Push all the vertices into the array AS3_Set(verticeArray, AS3_Int(j * 2), AS3_Int(solution[i][j].X)); AS3_Set(verticeArray, AS3_Int(j * 2 + 1), AS3_Int(solution[i][j].Y)); } // Insert the array into the returnArray AS3_Set(returnArray, AS3_Int(i), verticeArray); } } // Cleanup AS3_Release(asSubjectVertices); AS3_Release(asClipVertices); return returnArray; }
static void OffsetWithLoops(const TPolyPolygon &pp, TPolyPolygon &pp_new, double inwards_value) { Clipper c; bool inwards = (inwards_value > 0); bool reverse = false; double radius = -fabs(inwards_value); if(inwards) { // add a large square on the outside, to be removed later TPolygon p; p.push_back(DoubleAreaPoint(-10000.0, -10000.0).int_point()); p.push_back(DoubleAreaPoint(-10000.0, 10000.0).int_point()); p.push_back(DoubleAreaPoint(10000.0, 10000.0).int_point()); p.push_back(DoubleAreaPoint(10000.0, -10000.0).int_point()); c.AddPath(p, ptSubject, true); } else { reverse = true; } for(unsigned int i = 0; i < pp.size(); i++) { const TPolygon& p = pp[i]; pts_for_AddVertex.clear(); if(p.size() > 2) { if(reverse) { for(std::size_t j = p.size()-1; j > 1; j--)MakeLoop(p[j], p[j-1], p[j-2], radius); MakeLoop(p[1], p[0], p[p.size()-1], radius); MakeLoop(p[0], p[p.size()-1], p[p.size()-2], radius); } else { MakeLoop(p[p.size()-2], p[p.size()-1], p[0], radius); MakeLoop(p[p.size()-1], p[0], p[1], radius); for(unsigned int j = 2; j < p.size(); j++)MakeLoop(p[j-2], p[j-1], p[j], radius); } TPolygon loopy_polygon; loopy_polygon.reserve(pts_for_AddVertex.size()); for(std::list<DoubleAreaPoint>::iterator It = pts_for_AddVertex.begin(); It != pts_for_AddVertex.end(); It++) { loopy_polygon.push_back(It->int_point()); } c.AddPath(loopy_polygon, ptSubject, true); pts_for_AddVertex.clear(); } } //c.ForceOrientation(false); c.Execute(ctUnion, pp_new, pftNonZero, pftNonZero); if(inwards) { // remove the large square if(pp_new.size() > 0) { pp_new.erase(pp_new.begin()); } } else { // reverse all the resulting polygons TPolyPolygon copy = pp_new; pp_new.clear(); pp_new.resize(copy.size()); for(unsigned int i = 0; i < copy.size(); i++) { const TPolygon& p = copy[i]; TPolygon p_new; p_new.resize(p.size()); std::size_t size_minus_one = p.size() - 1; for(unsigned int j = 0; j < p.size(); j++)p_new[j] = p[size_minus_one - j]; pp_new[i] = p_new; } } }
static void AddLine (seg_t *seg,sector_t * sector,subsector_t * polysub) { angle_t startAngle, endAngle; sector_t * backsector = NULL; sector_t bs; ClipWall.Clock(); if (GLPortal::mirrorline) { // this seg is completely behind the mirror! if (P_PointOnLineSide(seg->v1->x, seg->v1->y, GLPortal::mirrorline) && P_PointOnLineSide(seg->v2->x, seg->v2->y, GLPortal::mirrorline)) { ClipWall.Unclock(); return; } } startAngle = seg->v2->GetViewAngle(); endAngle = seg->v1->GetViewAngle(); // Back side, i.e. backface culling - read: endAngle >= startAngle! if (startAngle-endAngle<ANGLE_180 || !seg->linedef) { ClipWall.Unclock(); return; } if (!clipper.SafeCheckRange(startAngle, endAngle)) { ClipWall.Unclock(); return; } if (!seg->backsector) { clipper.SafeAddClipRange(startAngle, endAngle); } else if (!polysub) // Two-sided polyobjects never obstruct the view { if (sector->sectornum == seg->backsector->sectornum) { FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::mid)); if (!tex || tex->UseType==FTexture::TEX_Null) { // nothing to do here! ClipWall.Unclock(); seg->linedef->validcount=validcount; return; } backsector=sector; } else { // clipping checks are only needed when the backsector is not the same as the front sector gl_CheckViewArea(seg->v1, seg->v2, seg->frontsector, seg->backsector); backsector = gl_FakeFlat(seg->backsector, &bs, true); if (gl_CheckClip(seg->sidedef, sector, backsector)) { clipper.SafeAddClipRange(startAngle, endAngle); } } } else { // Backsector for polyobj segs is always the containing sector itself backsector = sector; } seg->linedef->flags |= ML_MAPPED; ClipWall.Unclock(); if (!gl_render_segs) { // rendering per linedef as opposed per seg is significantly more efficient // so mark the linedef as rendered here and render it completely. if (seg->linedef->validcount!=validcount) seg->linedef->validcount=validcount; else return; } GLWall wall; SetupWall.Clock(); wall.Process(seg, sector, backsector, polysub, gl_render_segs); rendered_lines++; SetupWall.Unclock(); }
void OnPaint(HWND hWnd, HDC dc) { RECT rec; GetClientRect(hWnd, &rec); cairo_surface_t* surface = cairo_win32_surface_create(dc); cairo_t* cr = cairo_create(surface); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); cairo_set_line_width (cr, 2.0); //fill background with white ... cairo_rectangle(cr, 0, 0, rec.right, rec.bottom); cairo_set_source_rgba(cr, 1, 1, 1, 1); cairo_fill(cr); using namespace ClipperLib; const int scaling = 2; Clipper clpr; //clipper class Paths pg; //std::vector for polygon(s) storage //create a circular pattern, add the path to clipper and then draw it ... cairo_arc(cr, 170,110,70,0,2*3.1415926); cairo_close_path(cr); cairo::cairo_to_clipper(cr, pg, scaling); clpr.AddPaths(pg, ptSubject, true); cairo_set_source_rgba(cr, 0, 0, 1, 0.25); cairo_fill_preserve (cr); cairo_set_source_rgba(cr, 0, 0, 0, 0.5); cairo_stroke (cr); //draw a star and another circle, add them to clipper and draw ... cairo_move_to(cr, 60,110); cairo_line_to (cr, 240,70); cairo_line_to (cr, 110,210); cairo_line_to (cr, 140,25); cairo_line_to (cr, 230,200); cairo_close_path(cr); cairo_new_sub_path(cr); cairo_arc(cr, 190,50,20,0,2*3.1415926); cairo_close_path(cr); cairo::cairo_to_clipper(cr, pg, scaling); clpr.AddPaths(pg, ptClip, true); cairo_set_source_rgba(cr, 1, 0, 0, 0.25); cairo_fill_preserve (cr); cairo_set_source_rgba(cr, 0, 0, 0, 0.5); cairo_stroke (cr); clpr.Execute(ctIntersection, pg, pftNonZero, pftNonZero); //now do something fancy with the returned polygons ... OffsetPaths(pg, pg, offsetVal * std::pow((double)10,scaling), jtMiter, etClosed); //finally copy the clipped path back to the cairo context and draw it ... cairo::clipper_to_cairo(pg, cr, scaling); cairo_set_source_rgba(cr, 1, 1, 0, 1); cairo_fill_preserve (cr); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_stroke (cr); cairo_text_extents_t extent; cairo_set_font_size(cr,11); std::stringstream ss; ss << "Polygon offset = " << offsetVal << ". (Adjust with arrow keys)"; std::string s = ss.str(); cairo_text_extents(cr, s.c_str(), &extent); cairo_move_to(cr, 10, rec.bottom - extent.height); cairo_show_text(cr, s.c_str()); cairo_destroy (cr); cairo_surface_destroy (surface); }
void triangulate(const Polygon& inputPoly, std::vector<Mesh>& outputMeshes) { // Use Clipper to ensure strictly simple polygons using namespace ClipperLib; Clipper clipper; clipper.StrictlySimple(true); try { clipper.AddPaths(polyToClipperPaths(inputPoly), ptSubject, true); } catch (...) { std::cerr << "Error in Clipper::AddPaths" << std::endl; return; } PolyTree polyTree; clipper.Execute(ctUnion, polyTree, pftNonZero, pftNonZero); // Traverse the PolyTree nodes and triangulate them with only their children holes PolyNode *currentNode = polyTree.GetFirst(); while(currentNode != NULL) { // The holes are only used as the children of the contours if (currentNode->IsHole()) { currentNode = currentNode->GetNext(); continue; } // Convert to poly2tri's format std::vector<p2t::Point> allPoints; std::vector<size_t> linesSizes; // Contour for (const auto& pt : currentNode->Contour) allPoints.emplace_back(static_cast<double>(pt.X), static_cast<double>(pt.Y)); linesSizes.push_back(allPoints.size()); // Holes for(const auto childNode : currentNode->Childs) { // Slightly modify the polygon to guarantee no duplicate points edgeShrink(childNode->Contour); for (const auto& pt : childNode->Contour) allPoints.emplace_back(static_cast<double>(pt.X), static_cast<double>(pt.Y)); linesSizes.push_back(allPoints.size()); } // Poly2Tri uses pointers to points std::vector<p2t::Point*> contourLine; std::vector<std::vector<p2t::Point*>> holes; auto nbLines = linesSizes.size(); size_t start = 0; for (size_t i = 0; i < nbLines; ++i) { size_t end = linesSizes[i]; std::vector<p2t::Point*> line; line.reserve(end - start); for (size_t j = start; j < end; ++j) line.push_back(&allPoints[j]); start = end; if (!i) contourLine = std::move(line); else holes.push_back(std::move(line)); } // Set the contour in poly2tri p2t::CDT cdt(contourLine); // Add the holes for(auto& hole : holes) cdt.AddHole(hole); // Do the actual triangulation cdt.Triangulate(); // Downscale the points and add them to the mesh Mesh mesh; for (const auto pt : allPoints) mesh.addPoint(convert(pt)); // Convert the triangles auto triangles = cdt.GetTriangles(); auto firstPt = allPoints.data(); for (const auto triangle : triangles) { int ptId1 = std::distance(firstPt, triangle->GetPoint(0)); int ptId2 = std::distance(firstPt, triangle->GetPoint(1)); int ptId3 = std::distance(firstPt, triangle->GetPoint(2)); mesh.addTriangle(ptId1, ptId2, ptId3); } outputMeshes.push_back(mesh); currentNode = currentNode->GetNext(); } }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { mxArray *par; // ptr to mxArray structure double *pda; // ptr to polynomial data double *pud; // pointer to unit conversion factor mxLogical *ph; // pointer to hole flags double ud, iud; unsigned int Na, Nb, vnu; unsigned int k, m; ClipType pop; char ostr[STR_LEN]; //string with polygon operation ////////////////// // check arguments // // argument number if (nrhs != 4) { mexErrMsgTxt("polyboolmex : expected 4 input arguments."); } // argument pa if ( !mxIsCell(prhs[0]) ) { mexErrMsgTxt("polyboolmex : argument pa must be a cell array."); } Na = mxGetM(prhs[0])*mxGetN(prhs[0]); if (!Na) { mexErrMsgTxt("polyboolmex : no input polygons pa."); } // argument pb if ( !mxIsCell(prhs[1]) ) { mexErrMsgTxt("polyboolmex : argument pb must be a cell array."); } Nb = mxGetM(prhs[1])*mxGetN(prhs[1]); if (!Nb) { mexErrMsgTxt("polyboolmex : no input polygons pb."); } // get operation argument mxGetString(prhs[2], ostr, STR_LEN); if ( !strncmp(ostr, "or", 2) ) pop = ctUnion; else if ( !strncmp(ostr, "and", 3) ) pop = ctIntersection; else if ( !strncmp(ostr, "notb", 4) ) pop = ctDifference; else if ( !strncmp(ostr, "diff", 4) ) pop = ctDifference; else if ( !strncmp(ostr, "xor", 3) ) pop = ctXor; else { mexErrMsgTxt("polyboolmex : unknown boolean set algebra operation."); } // conversion factor argument pud = (double*)mxGetData(prhs[3]); ud = *pud; iud = 1.0/ud; //////////////////////// // copy and prepare data // // pa pa.resize(Na); for (k=0; k<Na; k++) { // get the next polygon from the cell array par = mxGetCell(prhs[0], k); // ptr to mxArray if ( mxIsEmpty(par) ) { mexErrMsgTxt("poly_boolmex : empty polygon in pa."); } pda = (double*)mxGetData(par); // ptr to a data vnu = mxGetM(par); // rows = vertex number // copy polygon and transpose, scale pa[k].resize(vnu); for (m=0; m<vnu; m++) { pa[k][m].X = (cInt)(ud * pda[m] + 0.5); pa[k][m].Y = (cInt)(ud * pda[m+vnu] + 0.5); } // make sure polygons have positive orientation if ( !Orientation(pa[k]) ) ReversePath(pa[k]); } // pb pb.resize(Nb); for (k=0; k<Nb; k++) { // get the next polygon par = mxGetCell(prhs[1], k); // ptr to mxArray if ( mxIsEmpty(par) ) { mexErrMsgTxt("poly_boolmex : empty polygon in pb."); } pda = (double*)mxGetData(par); // ptr to a data vnu = mxGetM(par); // rows = vertex number // copy polygon and transpose, scale pb[k].resize(vnu); for (m=0; m<vnu; m++) { pb[k][m].X = (cInt)(ud * pda[m] + 0.5); pb[k][m].Y = (cInt)(ud * pda[m+vnu] + 0.5); } // make sure polygons have positive orientation if ( !Orientation(pb[k]) ) ReversePath(pb[k]); } //////////////////// // clip the polygons // C.AddPaths(pa, ptSubject, true); C.AddPaths(pb, ptClip, true); if ( !C.Execute(pop, pc, pftEvenOdd, pftEvenOdd) ) mexErrMsgTxt("polyboolmex : Clipper library error."); ////////////////////////////////////////// // create a cell array for output argument // plhs[0] = mxCreateCellMatrix(1, pc.size()); ////////////////////////// // return clipping results // for (k=0; k<pc.size(); k++) { // allocate matrix for boundary vnu = pc[k].size(); par = mxCreateDoubleMatrix(vnu, 2, mxREAL); pda = (double*)mxGetData(par); // copy vertex array, transpose, and scale back to user units for (m=0; m<vnu; m++) { pda[m] = iud * pc[k][m].X; pda[vnu+m] = iud * pc[k][m].Y; } // store in cell array mxSetCell(plhs[0], k, par); } /////////////////// // return hole flags // plhs[1] = mxCreateLogicalMatrix(1, pc.size()); ph = (mxLogical*)mxGetData(plhs[1]); for (k=0; k<pc.size(); k++) ph[k] = !Orientation(pc[k]); // same as input == no hole /////////////////// // clean up // C.Clear(); pa.resize(0); pb.resize(0); pc.resize(0); }
bool toolpath::cToolpathIntersects(QList<netPath> nPList,QList<collisionToolpath> &cTList) { for(int i=0;i<nPList.size();i++) { netPath tNetPath=nPList.at(i); Path tPath=tNetPath.toolpath.at(0); collisionToolpath tcTList; tcTList.list.append(i); for(int j=i+1;j<nPList.size();j++) { netPath tNetPath1=nPList.at(j); Path tPath1=tNetPath1.toolpath.at(0); Paths tPaths; Clipper c; c.AddPath(tPath,ptSubject , true); c.AddPath(tPath1,ptClip , true); c.Execute(ctIntersection,tPaths,pftNonZero,pftNonZero); if(tPaths.size()>0)//collided { tcTList.list.append(j); collisionPair p; p.p1=i; p.p2=j; tcTList.pair.append(p); } } if(tcTList.list.size()>1) { bool collisionFlag=false; int toolpathNum=0; for(int l=0;l<cTList.size();l++) { collisionToolpath tcTList1=cTList.at(l); for(int k=0;k<tcTList.list.size();k++) { int toopathIndex=tcTList.list.at(k); for(int m=0;m<tcTList1.list.size();m++) { int toopathIndex1=tcTList1.list.at(m); if(toopathIndex==toopathIndex1) { collisionFlag=true; break; } } if(collisionFlag==true) { toolpathNum=l; break; } } if(collisionFlag==true)//collided with existed toolpath,merge { //merge two list collisionToolpath tcTList1=cTList.at(toolpathNum); for(int n=0;n<tcTList1.list.size();n++) { bool sameFlag=false; int num=0; for(int o=0;o<tcTList.list.size();o++) { if(tcTList.list.at(o)==tcTList1.list.at(n)) { sameFlag=true; num=o; break; } } if(sameFlag==true) continue; tcTList1.list.append(tcTList.list.at(num)); } //and save cTList.replace(l,tcTList1); break; } } if(collisionFlag==false) { cTList.append(tcTList); } } } }