Exemplo n.º 1
0
vector<ofVec3f> ofApp::offsetCell(list<int> & crv, float amt) {
	float scaling = 10;
	ClipperOffset co;
	Path P;
	Paths offsetP;
	float offset = amt;

	for (auto index : crv) {
		ofVec3f v = linesMesh.getVertex(index);
		P.push_back(IntPoint(v.x*scaling, v.y*scaling));
	}
	co.AddPath(P, jtRound, etClosedPolygon);
	co.Execute(offsetP, -offset*scaling);

	vector<ofVec3f> offsetPts;
	if (offsetP.size() > 0) {
		//visual offset for etching
		CleanPolygons(offsetP);

		if (doEtchOffset) {
			co.Clear();
			co.AddPaths(offsetP, jtRound, etClosedPolygon);
			co.Execute(offsetP, -etchOffset*scaling);
		}

		Path & oP = offsetP[0];
		for (int i = 0; i < oP.size(); i++) {
			ofVec3f pt3D(oP[i].X / scaling, oP[i].Y / scaling);
			offsetPts.push_back(pt3D);
		}
	}
	return offsetPts;
}
Exemplo n.º 2
0
Vector<Vector<Point2> > Geometry::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {

	using namespace ClipperLib;

	JoinType jt = jtSquare;

	switch (p_join_type) {
		case JOIN_SQUARE: jt = jtSquare; break;
		case JOIN_ROUND: jt = jtRound; break;
		case JOIN_MITER: jt = jtMiter; break;
	}

	EndType et = etClosedPolygon;

	switch (p_end_type) {
		case END_POLYGON: et = etClosedPolygon; break;
		case END_JOINED: et = etClosedLine; break;
		case END_BUTT: et = etOpenButt; break;
		case END_SQUARE: et = etOpenSquare; break;
		case END_ROUND: et = etOpenRound; break;
	}
	ClipperOffset co;
	Path path;

	// Need to scale points (Clipper's requirement for robust computation)
	for (int i = 0; i != p_polypath.size(); ++i) {
		path << IntPoint(p_polypath[i].x * SCALE_FACTOR, p_polypath[i].y * SCALE_FACTOR);
	}
	co.AddPath(path, jt, et);

	Paths paths;
	co.Execute(paths, p_delta * SCALE_FACTOR); // inflate/deflate

	// 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;
}
void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
{
    ClipperOffset c;

    BOOST_FOREACH( const POLYGON& poly, m_polys )
    {
        for( unsigned int i = 0; i < poly.size(); i++ )
            c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), jtRound, etClosedPolygon );
    }

    PolyTree solution;

    c.ArcTolerance = fabs( (double) aFactor ) / M_PI / aCircleSegmentsCount;

    c.Execute( solution, aFactor );

    importTree( &solution );
}
void SHAPE_POLY_SET::Inflate( int aFactor, int aCircleSegmentsCount )
{
    // A static table to avoid repetitive calculations of the coefficient
    // 1.0 - cos( M_PI/aCircleSegmentsCount)
    // aCircleSegmentsCount is most of time <= 64 and usually 8, 12, 16, 32
    #define SEG_CNT_MAX 64
    static double arc_tolerance_factor[SEG_CNT_MAX+1];

    ClipperOffset c;

    for( const POLYGON& poly : m_polys )
    {
        for( unsigned int i = 0; i < poly.size(); i++ )
            c.AddPath( convertToClipper( poly[i], i > 0 ? false : true ), jtRound, etClosedPolygon );
    }

    PolyTree solution;

    // Calculate the arc tolerance (arc error) from the seg count by circle.
    // the seg count is nn = M_PI / acos(1.0 - c.ArcTolerance / abs(aFactor))
    // see:
    // www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/ClipperOffset/Properties/ArcTolerance.htm

    if( aCircleSegmentsCount < 6 )  // avoid incorrect aCircleSegmentsCount values
        aCircleSegmentsCount = 6;

    double coeff;

    if( aCircleSegmentsCount > SEG_CNT_MAX || arc_tolerance_factor[aCircleSegmentsCount] == 0 )
    {
        coeff = 1.0 - cos( M_PI/aCircleSegmentsCount);

        if( aCircleSegmentsCount <= SEG_CNT_MAX )
            arc_tolerance_factor[aCircleSegmentsCount] = coeff;
    }
    else
        coeff = arc_tolerance_factor[aCircleSegmentsCount];

    c.ArcTolerance = std::abs( aFactor ) * coeff;

    c.Execute( solution, aFactor );

    importTree( &solution );
}
Exemplo n.º 5
0
vector<ofVec3f> ofApp::offsetCell(list<int> & crv, AnisoPoint2f & pt) {
	float scaling = 1000;
	ClipperOffset co;
	co.ArcTolerance = 1;
	Path P;
	Paths offsetP;
	float offset = ofClamp(offsetPercent / sqrt(pt.jacobian->determinant()), minThick*0.5, maxThick*0.5);

	if (doSmooth) {
		
		for (auto index : crv) {
			ofVec3f v = linesMesh.getVertex(index);
			IntPoint iPt(v.x * scaling, v.y * scaling);
			P.push_back(iPt);
		}
		co.AddPath(P, jtRound, etClosedPolygon);
		co.Execute(offsetP, -offset*scaling);
		if(offsetP.size() == 0) return vector<ofVec3f>();
		P.clear();
		ofVec2f center;
		for (auto & v : offsetP[0]) {
			//ofVec3f v = linesMesh.getVertex(index);
			Vector2f p(v.X, v.Y);
			p = (*pt.jacobian)*p;
			IntPoint iPt(p.coeff(0), p.coeff(1));
			P.push_back(iPt);
			center += ofVec2f(iPt.X, iPt.Y);
		}
		center /= crv.size();
		CleanPolygon(P);
		
		co.Clear();
		co.AddPath(P, jtRound, etClosedPolygon);
		float radius = 9e20;

		//get exact radius from straight skeleton
		Polygon_2 poly;
		for (auto & pt : P) {
			poly.push_back(Point_2(pt.X, pt.Y));
		}
		boost::shared_ptr<Ss> iss = CGAL::create_interior_straight_skeleton_2(poly.vertices_begin(), poly.vertices_end());
		radius = 0;
		for (Ss::Vertex_handle vh = iss->vertices_begin(); vh != iss->vertices_end(); vh++) {
			if (!vh->has_infinite_time()) {
				radius = max(radius, (float)vh->time());
			}
		}

		//estimate radius
		//for (auto & iPt : P) {
		//	radius = min(radius, (iPt.X - center.x)*(iPt.X - center.x) + (iPt.Y - center.y)*(iPt.Y - center.y));
		//}
		//radius = sqrt(radius);
		//co.Execute(offsetP, -radius);
		//int tries = 0;
		//while (offsetP.size() == 0 && tries < 50) {
		//	radius *= .95;
		//	co.Execute(offsetP, -radius);
		//	tries++;
		//}
		//cout << tries << endl;
		radius *= filletPercent;
		co.Execute(offsetP, -radius);
		//radius = min(radius,(radius - offset*scaling)*filletPercent + offset*scaling);
		
		//co.Execute(offsetP, -offset*scaling);
		vector<ofVec3f> offsetPts;
		if (offsetP.size() > 0) {
			//visual offset for etching
			co.Clear();
			CleanPolygons(offsetP);
			co.AddPaths(offsetP, jtRound, etClosedPolygon);
			co.Execute(offsetP, radius);
			CleanPolygons(offsetP);
			Path longestP;
			int pLen = 0;
			for (auto & oP : offsetP) {
				if (oP.size() > pLen) {
					pLen = oP.size();
					longestP = oP;
				}
			}
			Matrix2f inverse = pt.jacobian->inverse();
			if (doEtchOffset) {
				co.Clear();
				for (auto & lPt : longestP) {
					Vector2f anisoPt(lPt.X, lPt.Y);
					anisoPt = inverse*anisoPt;
					lPt.X = anisoPt[0];
					lPt.Y = anisoPt[1];
				}
				co.AddPath(longestP, jtRound, etClosedPolygon);
				co.Execute(offsetP, etchOffset*scaling);
				longestP = offsetP[0];
			}
			for (int i = 0; i < longestP.size(); i++) {
				//ofVec3f pt3D(oP[i].X / scaling, oP[i].Y/ scaling);
				Vector2f anisoPt(longestP[i].X / scaling, longestP[i].Y / scaling);
				if(!doEtchOffset)anisoPt = inverse*anisoPt;
				offsetPts.push_back(ofVec3f(anisoPt.coeff(0), anisoPt.coeff(1)));
			}
		}
		return offsetPts;
	}
	else {
		for (auto index : crv) {
			ofVec3f v = linesMesh.getVertex(index);
			IntPoint iPt(v.x * scaling, v.y * scaling);
			P.push_back(iPt);
		}
		CleanPolygon(P);
		//Paths simplerP;
		//SimplifyPolygon(P, simplerP);
		//CleanPolygons(simplerP);
		//P = simplerP[0];
		//CleanPolygon(P);
		//Polygon_2 poly;
		//for (auto & pt : P) {
		//	poly.push_back(Point_2(pt.X, pt.Y));
		//}
		//boost::shared_ptr<Ss> iss = CGAL::create_interior_straight_skeleton_2(poly.vertices_begin(), poly.vertices_end());
		//float radius = 0;
		//for (Ss::Vertex_handle vh = iss->vertices_begin(); vh != iss->vertices_end(); vh++) {
		//	if (!vh->has_infinite_time()) {
		//		radius = max(radius, (float)vh->time());
		//	}
		//}
		
		//Paths simplerP;
		//SimplifyPolygon(P, simplerP);
		//co.AddPaths(simplerP, jtRound, etClosedPolygon);
		//radius = ofClamp(radius*offsetPercent, minThick*0.5*scaling, maxThick*0.5*scaling);
		co.AddPath(P, jtRound, etClosedPolygon);
		co.Execute(offsetP, -offset*scaling);
		vector<ofVec3f> offsetPts;
		if (offsetP.size() > 0) {
			CleanPolygons(offsetP);
			if (doEtchOffset) {
				co.Clear();
				co.AddPaths(offsetP, jtRound, etClosedPolygon);
				co.Execute(offsetP, etchOffset*scaling);
			}
			else {
				co.Clear();
				co.AddPaths(offsetP, jtRound, etClosedPolygon);
				co.Execute(offsetP, 1);
			}
			Path longestP;
			int pLen = 0;
			for (auto & oP : offsetP) {
				if (oP.size() > pLen) {
					pLen = oP.size();
					longestP = oP;
				}
			}
			Path & oP = longestP;
			for (int i = 0; i < oP.size(); i++) {
				ofVec3f pt3D(oP[i].X / scaling, oP[i].Y/ scaling);
				offsetPts.push_back(pt3D);
			}
		}
		return offsetPts;
	}

}
Exemplo n.º 6
0
float Polygon3D::computeInset(std::vector<float> &offsetDistances, Loop3D &pgonInset, bool computeArea)
{
	Loop3D cleanPgon; 
	double tol = 0.01f;

	cleanPgon = this->contour;

	int prev, next;
	int cSz = cleanPgon.size();

	if(cSz < 3){
		return 0.0f;
	}

	if(reorientFace(cleanPgon)){				
		std::reverse(offsetDistances.begin(), offsetDistances.end() - 1);
	}

	//if offsets are zero, add a small epsilon just to avoid division by zero
	for(size_t i=0; i<offsetDistances.size(); ++i){
		if(fabs(offsetDistances[i]) < tol){
			offsetDistances[i] = tol;
		}
	}

	//pgonInset.resize(cSz);

	QVector3D intPt;


	/*
	// GEN CODE--> It leads to self-intersection very often with non-convex polygons
	for(int cur=0; cur<cSz; ++cur){
		//Some geometry and trigonometry

		//point p1 is the point with index cur
		prev = (cur-1+cSz)%cSz; //point p0
		next = (cur+1)%cSz;	  //point p2

		if (Util::diffAngle(cleanPgon[prev] - cleanPgon[cur], cleanPgon[next] - cleanPgon[cur]) < 0.1f) {
			// For deanend edge
			QVector3D vec = cleanPgon[cur] - cleanPgon[prev];
			QVector3D vec2(-vec.y(), vec.x(), 0);

			float angle = atan2f(vec2.y(), vec2.x());
			for (int i = 0; i <= 10; ++i) {
				float a = angle - (float)i * M_PI / 10.0f;
				intPt = QVector3D(cleanPgon[cur].x() + cosf(a) * offsetDistances[cur], cleanPgon[cur].y() + sinf(a) * offsetDistances[cur], cleanPgon[cur].z());
				pgonInset.push_back(intPt);
			}
		} else {
			Util::getIrregularBisector(cleanPgon[prev], cleanPgon[cur], cleanPgon[next], offsetDistances[prev], offsetDistances[cur], intPt);
			
			// For acute angle
			if (pgonInset.size() >= 2) {
				if (Util::diffAngle(pgonInset[pgonInset.size() - 2] - pgonInset[pgonInset.size() - 1], intPt - pgonInset[pgonInset.size() - 1]) < 0.1f) {
					pgonInset.erase(pgonInset.begin() + pgonInset.size() - 1);
				}
			}

			pgonInset.push_back(intPt);
		}
	}*/
	
	// Old Code
	pgonInset.resize(cSz);
	for(int cur=0; cur<cSz; ++cur){
		//Some geometry and trigonometry

		//point p1 is the point with index cur
		prev = (cur-1+cSz)%cSz; //point p0
		next = (cur+1)%cSz;	  //point p2

		getIrregularBisector(cleanPgon[prev], cleanPgon[cur], cleanPgon[next],
			offsetDistances[prev], offsetDistances[cur], intPt);

		pgonInset[cur] = intPt;
	}



	//temp
	

	//Compute inset area
	if(computeArea){

		boost::geometry::ring_type<Polygon3D>::type bg_contour;
		boost::geometry::ring_type<Polygon3D>::type bg_contour_inset;
		float contArea;
		float contInsetArea;

		if(pgonInset.size()>0){
			boost::geometry::assign(bg_contour_inset, pgonInset);
			boost::geometry::correct(bg_contour_inset);

			if(boost::geometry::intersects(bg_contour_inset)){
				//printf("INSET: intersects\n");
				pgonInset.clear();
				//return 0.0f;
			} else {

				boost::geometry::assign(bg_contour, cleanPgon);
				boost::geometry::correct(bg_contour);
				//if inset is not within polygon
				if( !is2DRingWithin2DRing(bg_contour_inset, bg_contour) ){
					pgonInset.clear();
					//printf("INSET: ringWithRing\n");
					//return 0.0f;
				} else {
					contArea = fabs(boost::geometry::area(bg_contour));
					contInsetArea = fabs(boost::geometry::area(bg_contour_inset));

					if(contInsetArea < contArea){// OK EXIT
						//return boost::geometry::area(bg_contour_inset);
						return contInsetArea;
					} else {
						//printf("INSET: contInsetArea < contArea\n");
						pgonInset.clear();
						//return 0.0f;
					}
				}
			}
		} else {
			//printf("INSET: sides <0\n");
			pgonInset.clear();
			//return 0.0f;
		}
		// IT FAILED TRY SECOND METHOD
		{
			Path subj;
			Paths solution;
			for(int cur=0; cur<cSz; ++cur){
				subj << IntPoint(cleanPgon[cur].x()*1000,cleanPgon[cur].y()*1000);
			}
			/*subj << 
				ClipperLib::IntPoint(348,257) << IntPoint(364,148) << IntPoint(362,148) << 
				IntPoint(326,241) << IntPoint(295,219) << IntPoint(258,88) << 
				IntPoint(440,129) << IntPoint(370,196) << IntPoint(372,275);*/
			ClipperOffset co;
			co.AddPath(subj, jtSquare, etClosedPolygon);
			co.Execute(solution, -1000*7.5);
			pgonInset.resize(solution[0].size());
			for(int sN=0;sN<solution[0].size();sN++){
				pgonInset[sN]=QVector3D(solution[0][sN].X/1000.0f,solution[0][sN].Y/1000.0f,0);
			}
			//printf("Solutions %d\n",solution.size());
			return Area(solution[0]);
		}

	}
	return 0.0f;

}