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 );
}
Esempio n. 2
0
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);
    }
}
Esempio n. 3
0
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 );
}
Esempio n. 5
0
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);
    }
Esempio n. 7
0
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;
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
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);
        }
    }
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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;
}
Esempio n. 13
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));
}
Esempio n. 14
0
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;
	}
}
Esempio n. 15
0
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();
		}
	}
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
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); 
}
Esempio n. 18
0
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;
}
Esempio n. 19
0
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;
};
Esempio n. 21
0
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;
}
Esempio n. 22
0
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;
		}
	}
}
Esempio n. 23
0
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();
}
Esempio n. 24
0
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);
}
Esempio n. 25
0
    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();
        }
    }
Esempio n. 26
0
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);
}
Esempio n. 27
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);
            }
        }
    }

}