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; }
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; }
bool ComputeOffset(const Paths &paths, double amount, Paths *result) { // Previous operations can leave small artifacts (e.g. self-intersecting // polygons) which ClipperOffset cannot handle. CleanPolygons fixes at least // some of these cases. Paths cleaned(paths.size()); // CleanPolygons does not resize 'cleaned'. CleanPolygons(paths, cleaned); Paths tmp_paths; if (!CopyAndForceOrientation(cleaned, true, &tmp_paths)) return false; ClipperOffset co; co.ArcTolerance = kQuantaPerInch / 1000; co.AddPaths(tmp_paths, jtRound, etClosedPolygon); co.Execute(*result, InchesToQuanta(amount)); return true; }
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 ); }
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; } }
void Boundary::Draw( ODDC& dc, PlugIn_ViewPort &piVP ) { //ODPath::Draw( dc, piVP ); if ( m_bVisible && m_pODPointList->GetCount() > 2) { int l_iBoundaryPointCount = 0; m_bpts = new wxPoint[ m_pODPointList->GetCount() ]; wxPoint r; for(wxODPointListNode *node = m_pODPointList->GetFirst(); node; node = node->GetNext()) { ODPoint *pOp = node->GetData(); GetCanvasPixLL( &piVP, &r, pOp->m_lat, pOp->m_lon ); m_bpts[ l_iBoundaryPointCount++ ] = r; } if( m_bExclusionBoundary && !m_bInclusionBoundary ) { // fill boundary with hatching wxGraphicsContext *wxGC = NULL; wxMemoryDC *pmdc = wxDynamicCast(dc.GetDC(), wxMemoryDC); if( pmdc ) wxGC = wxGraphicsContext::Create( *pmdc ); else { wxClientDC *pcdc = wxDynamicCast(dc.GetDC(), wxClientDC); if( pcdc ) wxGC = wxGraphicsContext::Create( *pcdc ); } wxGC->SetPen(*wxTRANSPARENT_PEN); wxColour tCol; tCol.Set(m_fillcol.Red(), m_fillcol.Green(), m_fillcol.Blue(), m_uiFillTransparency); wxGC->SetBrush( *wxTheBrushList->FindOrCreateBrush( tCol, wxBRUSHSTYLE_CROSSDIAG_HATCH ) ); wxGraphicsPath path = wxGC->CreatePath(); path.MoveToPoint(m_bpts[0].x, m_bpts[0].y); for( size_t i = 1; i < m_pODPointList->GetCount(); i++ ) { path.AddLineToPoint(m_bpts[i].x, m_bpts[i].y); } path.CloseSubpath(); wxGC->StrokePath(path); wxGC->FillPath( path ); delete wxGC; } else if( !m_bExclusionBoundary && m_bInclusionBoundary && m_pODPointList->GetCount() > 3 ) { // surround boundary with hatching if there is more than 10 pixels different between points int l_imaxpointdiffX = 0; int l_imaxpointdiffY = 0; for( size_t i = 1; i < m_pODPointList->GetCount(); i++ ) { int l_ipointdiffX = abs(m_bpts[0].x - m_bpts[i].x); int l_ipointdiffY = abs(m_bpts[0].y - m_bpts[i].y); if(l_ipointdiffX > l_imaxpointdiffX) l_imaxpointdiffX = l_ipointdiffX; if(l_ipointdiffY > l_imaxpointdiffY) l_imaxpointdiffY = l_ipointdiffY; } if(l_imaxpointdiffX < 10 && l_imaxpointdiffY < 10 ) return; // Use ClipperLib to manage Polygon // If needed simplify polygons to make shading stay outside Paths poly(1); for( size_t i = 0; i < m_pODPointList->GetCount(); i++ ) { poly[0] << IntPoint( m_bpts[i].x, m_bpts[i].y ); } Paths polys; SimplifyPolygons( poly, polys ); ClipperOffset co; Paths ExpandedBoundaries; co.AddPaths( polys, jtSquare, etClosedPolygon ); co.Execute( ExpandedBoundaries, m_iInclusionBoundarySize ); wxPoint *l_InclusionBoundary = new wxPoint[ ExpandedBoundaries[0].size() + 1 ]; for( size_t i = 0; i < ExpandedBoundaries[0].size(); i++ ) { l_InclusionBoundary[i].x = ExpandedBoundaries[0][i].X; l_InclusionBoundary[i].y = ExpandedBoundaries[0][i].Y; } // need to add first point to end to ensure the polygon is closed l_InclusionBoundary[ ExpandedBoundaries[0].size()].x = ExpandedBoundaries[0][0].X; l_InclusionBoundary[ ExpandedBoundaries[0].size()].y = ExpandedBoundaries[0][0].Y; int *l_iPolygonPointCount = new int[2]; l_iPolygonPointCount[0] = m_pODPointList->GetCount(); l_iPolygonPointCount[1] = ExpandedBoundaries[0].size() + 1; wxGraphicsContext *wxGC = NULL; wxMemoryDC *pmdc = wxDynamicCast(dc.GetDC(), wxMemoryDC); if( pmdc ) wxGC = wxGraphicsContext::Create( *pmdc ); else { wxClientDC *pcdc = wxDynamicCast(dc.GetDC(), wxClientDC); if( pcdc ) wxGC = wxGraphicsContext::Create( *pcdc ); } wxGC->SetPen(*wxTRANSPARENT_PEN); wxColour tCol; tCol.Set(m_fillcol.Red(), m_fillcol.Green(), m_fillcol.Blue(), m_uiFillTransparency); wxGC->SetBrush( *wxTheBrushList->FindOrCreateBrush( tCol, wxBRUSHSTYLE_CROSSDIAG_HATCH ) ); wxGraphicsPath path = wxGC->CreatePath(); path.MoveToPoint(m_bpts[0].x, m_bpts[0].y); for( int i = 0; i < l_iPolygonPointCount[0]; i++ ) { path.AddLineToPoint(m_bpts[i].x, m_bpts[i].y); } path.MoveToPoint(l_InclusionBoundary[0].x, l_InclusionBoundary[0].y); for( int i = 1; i < l_iPolygonPointCount[1]; i++ ) { path.AddLineToPoint(l_InclusionBoundary[i].x, l_InclusionBoundary[i].y); } path.CloseSubpath(); wxGC->StrokePath(path); wxGC->FillPath( path ); delete wxGC; ExpandedBoundaries.clear(); polys.clear(); poly.clear(); co.Clear(); } wxDELETEA( m_bpts ); } ODPath::Draw( dc, piVP ); }
void Boundary::DrawGL( PlugIn_ViewPort &piVP ) { #ifdef ocpnUSE_GL if ( !m_bVisible ) return; ODDC dc; if(m_pODPointList->GetCount() > 2 ) { if( m_bExclusionBoundary || m_bInclusionBoundary ) { wxPoint *l_AllPoints; int l_iAllPointsSizes[2]; wxPoint *l_InclusionBoundary; int l_iBoundaryPointCount = 0; m_bpts = new wxPoint[ m_pODPointList->GetCount() ]; wxPoint r; for(wxODPointListNode *node = m_pODPointList->GetFirst(); node; node = node->GetNext()) { ODPoint *pOp = node->GetData(); GetCanvasPixLL( &piVP, &r, pOp->m_lat, pOp->m_lon ); m_bpts[ l_iBoundaryPointCount++ ] = r; } if( !m_bExclusionBoundary && m_bInclusionBoundary ) { // surround boundary with hatching if there is more than 10 pixels different between points int l_imaxpointdiffX = 0; int l_imaxpointdiffY = 0; for( size_t i = 1; i < m_pODPointList->GetCount(); i++ ) { int l_ipointdiffX = abs(m_bpts[0].x - m_bpts[i].x); int l_ipointdiffY = abs(m_bpts[0].y - m_bpts[i].y); if(l_ipointdiffX > l_imaxpointdiffX) l_imaxpointdiffX = l_ipointdiffX; if(l_ipointdiffY > l_imaxpointdiffY) l_imaxpointdiffY = l_ipointdiffY; } if(l_imaxpointdiffX < 10 && l_imaxpointdiffY < 10 ) return; // Use ClipperLib to manage Polygon // If needed simplify polygons to make shading stay outside Paths poly(1); for( int i = 0; i < l_iBoundaryPointCount; i++ ) { poly[0] << IntPoint( m_bpts[i].x, m_bpts[i].y ); } Paths simplePolys; SimplifyPolygons( poly, simplePolys ); ClipperOffset co; Paths ExpandedBoundaries; co.AddPaths( simplePolys, jtSquare, etClosedPolygon ); co.Execute( ExpandedBoundaries, m_iInclusionBoundarySize ); int l_iInclusionBoundarySize = ExpandedBoundaries[0].size(); l_InclusionBoundary = new wxPoint[ l_iInclusionBoundarySize + 1 ]; for( int i = 0; i < l_iInclusionBoundarySize; i++ ) { l_InclusionBoundary[i].x = ExpandedBoundaries[0][i].X; l_InclusionBoundary[i].y = ExpandedBoundaries[0][i].Y; } // need to add first point to end to ensure the polygon is closed l_InclusionBoundary[ l_iInclusionBoundarySize ].x = ExpandedBoundaries[0][0].X; l_InclusionBoundary[ l_iInclusionBoundarySize ].y = ExpandedBoundaries[0][0].Y; // Create one array containing the original polygon joined to the expanded polygon to allow filling l_iAllPointsSizes[0] = l_iBoundaryPointCount; l_iAllPointsSizes[1] = l_iInclusionBoundarySize; l_AllPoints = new wxPoint[ l_iBoundaryPointCount + l_iInclusionBoundarySize + 1 ]; for( int i = 0; i < l_iBoundaryPointCount; i++ ) { l_AllPoints[i] = m_bpts[ i ]; } for( int i = 0; i < l_iInclusionBoundarySize; i++ ) { l_AllPoints[ i + l_iBoundaryPointCount ] = l_InclusionBoundary[i]; } ExpandedBoundaries.clear(); } // Each byte represents a single pixel for Alpha. This provides a cross hatch in a 16x16 pixel square GLubyte slope_cross_hatch[] = { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }; GLuint textureID; glGenTextures(1, &textureID); glBindTexture( GL_TEXTURE_2D, textureID ); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, 16, 16, 0, GL_ALPHA, GL_UNSIGNED_BYTE, slope_cross_hatch ); dc.SetTextureSize( 16, 16 ); glEnable( GL_TEXTURE_2D ); glEnable( GL_BLEND ); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); wxColour tCol; tCol.Set(m_fillcol.Red(), m_fillcol.Green(), m_fillcol.Blue(), m_uiFillTransparency); dc.SetBrush( *wxTheBrushList->FindOrCreateBrush( tCol, wxPENSTYLE_SOLID ) ); if( m_bExclusionBoundary ) { if(m_bIsBeingCreated) dc.DrawPolygonTessellated( m_pODPointList->GetCount(), m_bpts, 0, 0); else dc.DrawPolygonTessellated( m_pODPointList->GetCount() - 1, m_bpts, 0, 0); } else if( m_bInclusionBoundary ) { dc.DrawPolygonsTessellated( 2, l_iAllPointsSizes, l_AllPoints, 0, 0); } glDisable( GL_BLEND ); glDisable( GL_TEXTURE_2D ); glDeleteTextures(1, &textureID); wxDELETEA( m_bpts ); } } ODPath::DrawGL( piVP ); #endif }
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; }