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<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 ); }