bool MaskPolygon::clipPolygon(const FDiff2D center,const double radius) { if(radius<=0 || m_polygon.size()<3) { return false; }; FDiff2D s=m_polygon[m_polygon.size()-1]; bool s_inside=clip_insideCircle(s,center,radius); FDiff2D p; VectorPolygon newPolygon; bool needsFinalArc=false; double angleCovered=0; double angleCoveredOffset=0; for(unsigned int i=0;i<m_polygon.size();i++) { p=m_polygon[i]; bool p_inside=clip_insideCircle(p,center,radius); if(p_inside) { if(s_inside) { //both points inside newPolygon.push_back(p); } else { //line crosses circles from outside std::vector<FDiff2D> points=clip_getIntersectionCircle(p,s,center,radius); DEBUG_ASSERT(points.size()==1); angleCovered+=angle_between(s-center,points[0]-center); if(newPolygon.size()==0) { needsFinalArc=true; angleCoveredOffset=angleCovered; } else { generateArc(newPolygon,points[0],center,radius,angleCovered<0); }; newPolygon.push_back(points[0]); newPolygon.push_back(p); }; } else { if(!s_inside) { //both points outside of circle std::vector<FDiff2D> points=clip_getIntersectionCircle(s,p,center,radius); //intersection can only be zero points or 2 points if(points.size()>1) { angleCovered+=angle_between(s-center,points[0]-center); if(newPolygon.size()==0) { needsFinalArc=true; angleCoveredOffset=angleCovered; } else { generateArc(newPolygon,points[0],center,radius,angleCovered<0); }; newPolygon.push_back(points[0]); newPolygon.push_back(points[1]); angleCovered=angle_between(points[1]-center,p-center); } else { angleCovered+=angle_between(s-center,p-center); }; } else { //line segment intersects circle from inside std::vector<FDiff2D> points=clip_getIntersectionCircle(s,p,center,radius); angleCovered=0; DEBUG_ASSERT(points.size()==1); newPolygon.push_back(points[0]); }; }; s=p; s_inside=p_inside; }; if(needsFinalArc && newPolygon.size()>1) { generateArc(newPolygon,newPolygon[0],center,radius,(angleCovered+angleCoveredOffset)<0); }; m_polygon=newPolygon; return (m_polygon.size()>2); };
// Make one closed path by adding the points of the inner path void Stroker::endStroke() { switch(endType_) { // Simplest case, just add the inner points case cButtEnd: { for(vplUint i = innerPoints_.getItemCount(); i > 0;i-=2) { outerPoints_.add(innerPoints_[i - 2]); outerPoints_.add(innerPoints_[i - 1]); } // Close the path outerPoints_.add(outerPoints_[0]); outerPoints_.add(outerPoints_[1]); } break; // End outer path with an arc, then add the inner points. // Finalize with a closing arc to the first point case cRoundEnd: { Winding winding = determineWinding(normal_,invert(normal_)); generateArc(currentPoint_,normal_,invert(normal_), winding,&outerPoints_); for(vplUint i = innerPoints_.getItemCount(); i > 0;i-=2) { outerPoints_.add(innerPoints_[i - 2]); outerPoints_.add(innerPoints_[i - 1]); } winding = determineWinding(invert(firstNormal_),firstNormal_); generateArc(firstPoint_,invert(firstNormal_),firstNormal_, winding,&outerPoints_); // Close the path outerPoints_.add(outerPoints_[0]); outerPoints_.add(outerPoints_[1]); } break; // Add a rectangle with sides stroke width/2 x stroke width case cSquareEnd: { // Use the normals for calculation of the ends Vector dir(-normal_.y_,normal_.x_); Vector firstDir(-firstNormal_.y_,firstNormal_.x_); dir.normalize(); firstDir.normalize(); scale_.transform(dir); scale_.transform(firstDir); dir *= size_ / 2; firstDir *= size_ / 2; Vector v1 = currentPoint_ + normal_ + dir; Vector v2 = currentPoint_ - normal_ + dir; addPoint(&outerPoints_,v1); addPoint(&outerPoints_,v2); for(vplUint i = innerPoints_.getItemCount(); i > 0;i-=2) { outerPoints_.add(innerPoints_[i - 2]); outerPoints_.add(innerPoints_[i - 1]); } v1 = firstPoint_ - firstNormal_ - firstDir; v2 = firstPoint_ + firstNormal_ - firstDir; addPoint(&outerPoints_,v1); addPoint(&outerPoints_,v2); // Close the path outerPoints_.add(outerPoints_[0]); outerPoints_.add(outerPoints_[1]); } break; } innerPoints_.clear(); }