ClipperLib::PolyTree _clipper_do(const ClipperLib::ClipType clipType, const Polylines &subject, const Polygons &clip, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { // read input ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip); // perform safety offset if (safety_offset_) safety_offset(&input_clip); // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons clipper.AddPaths(input_subject, ClipperLib::ptSubject, false); clipper.AddPaths(input_clip, ClipperLib::ptClip, true); // perform operation ClipperLib::PolyTree retval; clipper.Execute(clipType, retval, fillType, fillType); return retval; }
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, ClipperLib::PolyTree* retval, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { PROFILE_BLOCK(_clipper_do_polylines); // read input ClipperLib::Paths input_subject, input_clip; Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); Slic3rMultiPoints_to_ClipperPaths(clip, &input_clip); // perform safety offset if (safety_offset_) safety_offset(&input_clip); // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons { PROFILE_BLOCK(_clipper_do_polylines_AddPaths); clipper.AddPaths(input_subject, ClipperLib::ptSubject, false); clipper.AddPaths(input_clip, ClipperLib::ptClip, true); } // perform operation { PROFILE_BLOCK(_clipper_do_polylines_Execute); clipper.Execute(clipType, *retval, fillType, fillType); } }
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { // read input ClipperLib::Paths* input_subject = new ClipperLib::Paths(); ClipperLib::Paths* input_clip = new ClipperLib::Paths(); Slic3rMultiPoints_to_ClipperPaths(subject, *input_subject); Slic3rMultiPoints_to_ClipperPaths(clip, *input_clip); // perform safety offset if (safety_offset_) { if (clipType == ClipperLib::ctUnion) { safety_offset(input_subject); } else { safety_offset(input_clip); } } // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons clipper.AddPaths(*input_subject, ClipperLib::ptSubject, true); delete input_subject; clipper.AddPaths(*input_clip, ClipperLib::ptClip, true); delete input_clip; // perform operation clipper.Execute(clipType, retval, fillType, fillType); }
// Fix of #117: A large fractal pyramid takes ages to slice // The Clipper library has difficulties processing overlapping polygons. // Namely, the function Clipper::JoinCommonEdges() has potentially a terrible time complexity if the output // of the operation is of the PolyTree type. // This function implmenets a following workaround: // 1) Peform the Clipper operation with the output to Paths. This method handles overlaps in a reasonable time. // 2) Run Clipper Union once again to extract the PolyTree from the result of 1). inline ClipperLib::PolyTree _clipper_do_polytree2(const ClipperLib::ClipType clipType, const Polygons &subject, const Polygons &clip, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { // read input ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip); // perform safety offset if (safety_offset_) safety_offset((clipType == ClipperLib::ctUnion) ? &input_subject : &input_clip); ClipperLib::Clipper clipper; clipper.AddPaths(input_subject, ClipperLib::ptSubject, true); clipper.AddPaths(input_clip, ClipperLib::ptClip, true); // Perform the operation with the output to input_subject. // This pass does not generate a PolyTree, which is a very expensive operation with the current Clipper library // if there are overapping edges. clipper.Execute(clipType, input_subject, fillType, fillType); // Perform an additional Union operation to generate the PolyTree ordering. clipper.Clear(); clipper.AddPaths(input_subject, ClipperLib::ptSubject, true); ClipperLib::PolyTree retval; clipper.Execute(ClipperLib::ctUnion, retval, fillType, fillType); return retval; }
// This is a safe variant of the polygon offset, tailored for a single ExPolygon: // a single polygon with multiple non-overlapping holes. // Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours. ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType, double miterLimit) { // printf("new ExPolygon offset\n"); // 1) Offset the outer contour. const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); ClipperLib::Paths contours; { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(expolygon.contour); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPath(input, joinType, ClipperLib::etClosedPolygon); co.Execute(contours, delta_scaled); } // 2) Offset the holes one by one, collect the results. ClipperLib::Paths holes; { holes.reserve(expolygon.holes.size()); for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPath(input, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; co.Execute(out, - delta_scaled); holes.insert(holes.end(), out.begin(), out.end()); } } // 3) Subtract holes from the contours. ClipperLib::Paths output; if (holes.empty()) { output = std::move(contours); } else { ClipperLib::Clipper clipper; clipper.Clear(); clipper.AddPaths(contours, ClipperLib::ptSubject, true); clipper.AddPaths(holes, ClipperLib::ptClip, true); clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } // 4) Unscale the output. unscaleClipperPolygons(output); return output; }
bool BooleanTool::executeForObjects(PathObject* subject, PathObjects& in_objects, PathObjects& out_objects) { // Convert the objects to Clipper polygons and // create a hash map, mapping point positions to the PathCoords. // These paths are to be regarded as closed. PolyMap polymap; ClipperLib::Paths subject_polygons; pathObjectToPolygons(subject, subject_polygons, polymap); ClipperLib::Paths clip_polygons; for (PathObject* object : in_objects) { if (object != subject) { pathObjectToPolygons(object, clip_polygons, polymap); } } // Do the operation. ClipperLib::Clipper clipper; clipper.AddPaths(subject_polygons, ClipperLib::ptSubject, true); clipper.AddPaths(clip_polygons, ClipperLib::ptClip, true); ClipperLib::ClipType clip_type; ClipperLib::PolyFillType fill_type = ClipperLib::pftNonZero; switch (op) { case Union: clip_type = ClipperLib::ctUnion; break; case Intersection: clip_type = ClipperLib::ctIntersection; break; case Difference: clip_type = ClipperLib::ctDifference; break; case XOr: clip_type = ClipperLib::ctXor; break; case MergeHoles: clip_type = ClipperLib::ctUnion; fill_type = ClipperLib::pftPositive; break; default: Q_ASSERT(false && "Undefined operation"); return false; } ClipperLib::PolyTree solution; bool success = clipper.Execute(clip_type, solution, fill_type, fill_type); if (success) { // Try to convert the solution polygons to objects again polyTreeToPathObjects(solution, out_objects, subject, polymap); } return success; }
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::ExPolygons* retval, bool preserve_collinear) { PROFILE_FUNC(); if (!preserve_collinear) { Polygons polygons; simplify_polygons(subject, &polygons, preserve_collinear); union_(polygons, retval); return; } // convert into Clipper polygons ClipperLib::Paths input_subject; Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); ClipperLib::PolyTree polytree; ClipperLib::Clipper c; c.PreserveCollinear(true); c.StrictlySimple(true); c.AddPaths(input_subject, ClipperLib::ptSubject, true); c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); // convert into ExPolygons PolyTreeToExPolygons(polytree, retval); }
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T* retval, const ClipperLib::PolyFillType fillType, const bool safety_offset_) { PROFILE_BLOCK(_clipper_do_polygons); // read input ClipperLib::Paths input_subject, input_clip; Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); Slic3rMultiPoints_to_ClipperPaths(clip, &input_clip); // perform safety offset if (safety_offset_) { if (clipType == ClipperLib::ctUnion) { safety_offset(&input_subject); } else { safety_offset(&input_clip); } } // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons { PROFILE_BLOCK(_clipper_do_polygons_AddPaths); clipper.AddPaths(input_subject, ClipperLib::ptSubject, true); clipper.AddPaths(input_clip, ClipperLib::ptClip, true); #ifdef CLIPPER_UTILS_DEBUG if (clipper_export_enabled) { static int iRun = 0; export_clipper_input_polygons_bin(debug_out_path("_clipper_do_polygons_AddPaths-polygons-%d", ++iRun).c_str(), input_subject, input_clip); } #endif /* CLIPPER_UTILS_DEBUG */ } // perform operation { PROFILE_BLOCK(_clipper_do_polygons_Execute); clipper.Execute(clipType, *retval, fillType, fillType); } }
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, ClipperLib::PolyTree &retval, const ClipperLib::PolyFillType fillType) { // read input ClipperLib::Paths* input_subject = new ClipperLib::Paths(); ClipperLib::Paths* input_clip = new ClipperLib::Paths(); Slic3rMultiPoints_to_ClipperPaths(subject, *input_subject); Slic3rMultiPoints_to_ClipperPaths(clip, *input_clip); // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // add polygons clipper.AddPaths(*input_subject, ClipperLib::ptSubject, false); delete input_subject; clipper.AddPaths(*input_clip, ClipperLib::ptClip, true); delete input_clip; // perform operation clipper.Execute(clipType, retval, fillType, fillType); }
ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input) { // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // perform union clipper.AddPaths(input, ClipperLib::ptSubject, true); ClipperLib::PolyTree polytree; clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // offset results work with both EvenOdd and NonZero // write to ExPolygons object return PolyTreeToExPolygons(polytree); }
Polygons top_level_islands(const Slic3r::Polygons &polygons) { // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // perform union clipper.AddPaths(Slic3rMultiPoints_to_ClipperPaths(polygons), ClipperLib::ptSubject, true); ClipperLib::PolyTree polytree; clipper.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // Convert only the top level islands to the output. Polygons out; out.reserve(polytree.ChildCount()); for (int i = 0; i < polytree.ChildCount(); ++i) out.emplace_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour)); return out; }
void ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, Slic3r::ExPolygons &output) { // init Clipper ClipperLib::Clipper clipper; clipper.Clear(); // perform union clipper.AddPaths(input, ClipperLib::ptSubject, true); ClipperLib::PolyTree* polytree = new ClipperLib::PolyTree(); clipper.Execute(ClipperLib::ctUnion, *polytree, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // offset results work with both EvenOdd and NonZero // write to ExPolygons object output.clear(); PolyTreeToExPolygons(*polytree, output); delete polytree; }
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::Polygons* retval, bool preserve_collinear) { // convert into Clipper polygons ClipperLib::Paths input_subject, output; Slic3rMultiPoints_to_ClipperPaths(subject, &input_subject); if (preserve_collinear) { ClipperLib::Clipper c; c.PreserveCollinear(true); c.StrictlySimple(true); c.AddPaths(input_subject, ClipperLib::ptSubject, true); c.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } else { ClipperLib::SimplifyPolygons(input_subject, output, ClipperLib::pftNonZero); } // convert into Slic3r polygons ClipperPaths_to_Slic3rMultiPoints(output, retval); }
ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear) { if (! preserve_collinear) return union_ex(simplify_polygons(subject, false)); // convert into Clipper polygons ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); ClipperLib::PolyTree polytree; ClipperLib::Clipper c; c.PreserveCollinear(true); c.StrictlySimple(true); c.AddPaths(input_subject, ClipperLib::ptSubject, true); c.Execute(ClipperLib::ctUnion, polytree, ClipperLib::pftNonZero, ClipperLib::pftNonZero); // convert into ExPolygons return PolyTreeToExPolygons(polytree); }
double poly_intersection(const ContContainer& poly1, const ContContainer& poly2) { /* ************* TEMPORAL ************ * Conversion, we should remove junctions from container * or define it for our containers */ ClipperLib::Paths paths1(poly1.begin(),poly1.end()); ClipperLib::Paths paths2(poly2.begin(),poly2.end()); /* Get the intersection polygon */ ClipperLib::Clipper clpr; clpr.AddPaths(paths1, ClipperLib::ptSubject, true); clpr.AddPaths(paths2, ClipperLib::ptClip , true); ClipperLib::Paths solution; clpr.Execute(ClipperLib::ctIntersection, solution, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); /* Get its area */ double int_area = 0; for(std::size_t ii=0; ii<solution.size(); ++ii) int_area += std::abs(ClipperLib::Area(solution[ii])); return int_area; }
void World::update(cv::Mat &homography) { this->m_world->Step(dt, 10, 10); //check contacts std::vector<MyContact>::iterator pos; std::map<b2Body*, ClipperLib::Paths*> newBodyMap; std::vector<b2Body*> removeBarrierList; for(pos = this->m_contactListener->m_contacts.begin(); pos != this->m_contactListener->m_contacts.end(); ++pos) { MyContact contact = *pos; if ((contact.fixtureA == this->m_ballFixture || contact.fixtureB == this->m_ballFixture) && (contact.fixtureA->GetBody() != m_groundBody && contact.fixtureB->GetBody() != m_groundBody) && (contact.fixtureA->GetBody() != m_paddlesBody && contact.fixtureB->GetBody() != m_paddlesBody)) { b2Fixture* objectFixture = contact.fixtureA == this->m_ballFixture ? contact.fixtureB : contact.fixtureA; b2Body *objectBody = objectFixture->GetBody(); if (objectFixture->GetType() == b2Shape::e_edge) { cv::Point2f hitPoint = CVUtils::transformPoint(cv::Point2f(contact.contactPoint->x * PTM_RATIO, contact.contactPoint->y * PTM_RATIO), homography); this->notifyBallHitObservers(hitPoint.x, hitPoint.y); // change the shape of the fixture // only go into processing if this body was not processed yet (possible ball hit two fixture of same body) if (newBodyMap.find(objectBody) == newBodyMap.end()) { ClipperLib::Paths* bodyPolygons = (ClipperLib::Paths*)objectBody->GetUserData(); b2Vec2* impactVelocity = contact.fixtureA == m_ballFixture ? contact.impactVelocityA : contact.impactVelocityB; float ballAngle = atan2(impactVelocity->y, impactVelocity->x); // get the angle (in radians) the ball is moving to float ballPower = impactVelocity->Length() * 0.5; // get the "power" of the ball movement vector float openingStepInRadians = 10 * CV_PI / 180; // calculate the opening in radians // create the clipping object/shape - a wedge from ball's center with 30 degree opening over ball direction (angle) ClipperLib::Path clip; clip.push_back(ClipperLib::IntPoint(contact.contactPoint->x * PTM_RATIO, contact.contactPoint->y * PTM_RATIO)); for(int step = 9; step > -10; step--) { float dx = cos(ballAngle + step * openingStepInRadians) * ballPower; float dy = sin(ballAngle + step * openingStepInRadians) * ballPower; clip.push_back(ClipperLib::IntPoint(contact.contactPoint->x * PTM_RATIO + dx, contact.contactPoint->y * PTM_RATIO + dy)); } ClipperLib::Clipper clipper; clipper.AddPaths((*bodyPolygons), ClipperLib::ptSubject, true); clipper.AddPath(clip, ClipperLib::ptClip, true); // the difference is the new polygon formed by the clipping (collision) ClipperLib::Paths* newPolygons = new ClipperLib::Paths(); clipper.Execute(ClipperLib::ctDifference, (*newPolygons), ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // Save the new polygons of this body objectBody->SetUserData(newPolygons); newBodyMap[objectBody] = newPolygons; // now, find the intersection regions - these should be inpainted to the scene ClipperLib::Paths destroyedParts; clipper.Execute(ClipperLib::ctIntersection, destroyedParts, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); // paint the required areas to be coppied for (size_t i = 0; i < destroyedParts.size(); i++) { cv::Point* points = new cv::Point[destroyedParts[i].size()]; for (size_t j = 0; j < destroyedParts[i].size(); j++) { points[j].x = (int)destroyedParts[i][j].X; points[j].y = (int)destroyedParts[i][j].Y; } m_destroyedPolygons.push_back(points); m_destroyedPolygonsPointCount.push_back((int)destroyedParts[i].size()); } } } else if (objectFixture->GetType() == b2Shape::e_circle) { // this is a barrier - add it to the remove list removeBarrierList.push_back(objectBody); } } } std::map<b2Body*, ClipperLib::Paths*>::iterator iter; for(iter = newBodyMap.begin(); iter != newBodyMap.end(); iter++) { b2Body* objectBody = iter->first; ClipperLib::Paths* newPolygons = iter->second; // remove all the current fixtures from this body for (b2Fixture* f = objectBody->GetFixtureList(); f; ) { b2Fixture* fixtureToDestroy = f; f = f->GetNext(); objectBody->DestroyFixture( fixtureToDestroy ); } if(newPolygons->size() == 0) { // there is no more pieces of the object left so remove it from list and world m_objectBodies.erase(std::find(m_objectBodies.begin(), m_objectBodies.end(), objectBody)); m_world->DestroyBody(objectBody); // TODO: better physics world cleanup } else { for (size_t i = 0; i < newPolygons->size(); i++) { b2EdgeShape objectEdgeShape; b2FixtureDef objectShapeDef; objectShapeDef.shape = &objectEdgeShape; ClipperLib::Path polygon = newPolygons->at(i); size_t j; for (j = 0; j < polygon.size() - 1; j++) { objectEdgeShape.Set(b2Vec2(polygon[j].X / PTM_RATIO, polygon[j].Y / PTM_RATIO), b2Vec2(polygon[j+1].X / PTM_RATIO, polygon[j+1].Y / PTM_RATIO)); objectBody->CreateFixture(&objectShapeDef); } objectEdgeShape.Set(b2Vec2(polygon[j].X / PTM_RATIO, polygon[j].Y / PTM_RATIO), b2Vec2(polygon[0].X / PTM_RATIO, polygon[0].Y / PTM_RATIO)); objectBody->CreateFixture(&objectShapeDef); } } } for (size_t i = 0; i < removeBarrierList.size(); i++){ cv::Point2f* p = (cv::Point2f*)removeBarrierList[i]->GetUserData(); std::vector<cv::Point2f*>::iterator position = std::find(m_guardLocations.begin(), m_guardLocations.end(), p); if (position != m_guardLocations.end()){ // == vector.end() means the element was not found m_guardLocations.erase(position); } removeBarrierList[i]->GetWorld()->DestroyBody(removeBarrierList[i]); } }
// This is a safe variant of the polygons offset, tailored for multiple ExPolygons. // It is required, that the input expolygons do not overlap and that the holes of each ExPolygon don't intersect with their respective outer contours. // Each ExPolygon is offsetted separately, then the offsetted ExPolygons are united. ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType, double miterLimit) { const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); // Offsetted ExPolygons before they are united. ClipperLib::Paths contours_cummulative; contours_cummulative.reserve(expolygons.size()); // How many non-empty offsetted expolygons were actually collected into contours_cummulative? // If only one, then there is no need to do a final union. size_t expolygons_collected = 0; for (Slic3r::ExPolygons::const_iterator it_expoly = expolygons.begin(); it_expoly != expolygons.end(); ++ it_expoly) { // 1) Offset the outer contour. ClipperLib::Paths contours; { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(it_expoly->contour); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPath(input, joinType, ClipperLib::etClosedPolygon); co.Execute(contours, delta_scaled); } if (contours.empty()) // No need to try to offset the holes. continue; if (it_expoly->holes.empty()) { // No need to subtract holes from the offsetted expolygon, we are done. contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end()); ++ expolygons_collected; } else { // 2) Offset the holes one by one, collect the offsetted holes. ClipperLib::Paths holes; { for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) { ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR)); co.AddPath(input, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; co.Execute(out, - delta_scaled); holes.insert(holes.end(), out.begin(), out.end()); } } // 3) Subtract holes from the contours. if (holes.empty()) { // No hole remaining after an offset. Just copy the outer contour. contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end()); ++ expolygons_collected; } else if (delta < 0) { // Negative offset. There is a chance, that the offsetted hole intersects the outer contour. // Subtract the offsetted holes from the offsetted contours. ClipperLib::Clipper clipper; clipper.Clear(); clipper.AddPaths(contours, ClipperLib::ptSubject, true); clipper.AddPaths(holes, ClipperLib::ptClip, true); ClipperLib::Paths output; clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); if (! output.empty()) { contours_cummulative.insert(contours_cummulative.end(), output.begin(), output.end()); ++ expolygons_collected; } else { // The offsetted holes have eaten up the offsetted outer contour. } } else { // Positive offset. As long as the Clipper offset does what one expects it to do, the offsetted hole will have a smaller // area than the original hole or even disappear, therefore there will be no new intersections. // Just collect the reversed holes. contours_cummulative.reserve(contours.size() + holes.size()); contours_cummulative.insert(contours_cummulative.end(), contours.begin(), contours.end()); // Reverse the holes in place. for (size_t i = 0; i < holes.size(); ++ i) std::reverse(holes[i].begin(), holes[i].end()); contours_cummulative.insert(contours_cummulative.end(), holes.begin(), holes.end()); ++ expolygons_collected; } } } // 4) Unite the offsetted expolygons. ClipperLib::Paths output; if (expolygons_collected > 1 && delta > 0) { // There is a chance that the outwards offsetted expolygons may intersect. Perform a union. ClipperLib::Clipper clipper; clipper.Clear(); clipper.AddPaths(contours_cummulative, ClipperLib::ptSubject, true); clipper.Execute(ClipperLib::ctUnion, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } else { // Negative offset. The shrunk expolygons shall not mutually intersect. Just copy the output. output = std::move(contours_cummulative); } // 4) Unscale the output. unscaleClipperPolygons(output); return output; }
int Grasp_Calculator::calcMeshGraspPosition(moveit_msgs::CollisionObject co, std::vector<geometry_msgs::PoseStamped> &poses, std::vector<geometry_msgs::PoseStamped> &pre_poses, double gripper_depth) { ros::Time t = ros::Time::now(); string gripper_group = gripper_depth == Gripper::R_GRIPPER_PALM_LENGTH ? Gripper::get_r_group_name() : Gripper::get_l_group_name(); std::vector<geometry_msgs::Point> c; suturo_manipulation::Mesh meshi(co); // 2. search for cluster with opposite normal - O(|Cluster|²) std::vector< std::pair<uint, uint> > opposite_cluster = meshi.get_opposite_cluster(); int h = 0; ROS_INFO_STREAM("opposite cluster size: " << opposite_cluster.size()); for (int i = 0; i < opposite_cluster.size(); i++) { // 3. project both cluster on a plain - o(|vertices|)? suturo_manipulation::Plane plane = meshi.get_plane(opposite_cluster[i].first, opposite_cluster[i].second); plane.orthonormalize(); std::vector<geometry_msgs::Point> p1 = meshi.get_polygon(opposite_cluster[i].first); std::vector<geometry_msgs::Point> p2 = meshi.get_polygon(opposite_cluster[i].second); if (i == 0) { pi_->publishMarkerLine(co.id, p1, 0); pi_->publishMarkerLine(co.id, p2, 1000); } DPolygon2D dpolygon1 = project_polygon_to_plane(plane, p1); DPolygon2D dpolygon2 = project_polygon_to_plane(plane, p2); ClipperLib::Paths polygon1(1); ClipperLib::Paths polygon2(1); double_polygon_to_path(dpolygon1, polygon1); double_polygon_to_path(dpolygon2, polygon2); // 4. calc polygon intersection - O(|vertices|²)? // http://www.integis.ch/documents/ISem_Opprecht_Overlay_2002-02-28.pdf // http://www.cs.man.ac.uk/~toby/alan/software/gpc.html ClipperLib::Clipper clpr; clpr.AddPaths(polygon1, ClipperLib::ptSubject, true); clpr.AddPaths(polygon2, ClipperLib::ptClip, true); ClipperLib::Paths solution; clpr.Execute(ClipperLib::ctIntersection, solution, ClipperLib::pftNonZero, ClipperLib::pftNonZero); // 5. calc centriod - O(|vertices|) Path int_centroids = calc_poly_centroid(solution); DPolygon2D double_centroids; path_to_double_polygon(double_centroids, int_centroids); std::vector<geometry_msgs::Point> centroids = d2d_points_to_d3d_points(plane, double_centroids); for (std::vector<geometry_msgs::Point>::iterator i = centroids.begin(); i != centroids.end(); ++i) { c.push_back(*i); } //ggf 5.2 check dist to cluster // http://www.uninformativ.de/bin/RaytracingSchnitttests-76a577a-CC-BY.pdf // 6. add grasppose pointing towards centriod with differen angles - const for (std::vector<geometry_msgs::Point>::iterator i = centroids.begin(); i != centroids.end(); ++i) { for (double a = 0; a < 2 * M_PI; a += (M_PI / 2)) { geometry_msgs::PoseStamped temp_grasp_pose; geometry_msgs::PoseStamped temp_pre_grasp_pose; temp_grasp_pose.header.frame_id = co.id; temp_pre_grasp_pose.header.frame_id = co.id; if (!get_grasp_point(plane, *i, gripper_depth , a, temp_grasp_pose, temp_pre_grasp_pose, meshi)) continue; // h++; // 7. use moveit to test poses - O(much)??? // if (!pi_->check_group_object_collision(gripper_group, temp_grasp_pose, co)) // { // ROS_INFO_STREAM("collision!" ); // ros::WallDuration(0.5).sleep(); // ROS_WARN_STREAM("centroid " << *i); poses.push_back(temp_grasp_pose); pre_poses.push_back(temp_pre_grasp_pose); // } } } } pi_->publishMarkerPoints(co.id, c); if (poses.empty()) { ROS_WARN_STREAM("No Grasppositions found for: " << co.id); return 0; } //sort geometry_msgs::PointStamped p; if (!get_point_above_object(co.id, p)) return 0; std::sort(poses.begin(), poses.end(), boost::bind(sort_base_link_mesh_poses, _1, _2, p)); std::sort(pre_poses.begin(), pre_poses.end(), boost::bind(sort_base_link_mesh_poses, _1, _2, p)); ROS_INFO_STREAM("poses:" << poses.size()); for (int i = 0; i < poses.size() ; ++i) { pi_->publishMarker(poses[i], i); pi_->publishMarker(pre_poses[i], i + poses.size()); } ROS_INFO_STREAM((ros::Time::now() - t)); return 1; }
// This is a safe variant of the polygon offset, tailored for a single ExPolygon: // a single polygon with multiple non-overlapping holes. // Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours. void offset(const Slic3r::ExPolygons &expolygons, ClipperLib::Paths* retval, const float delta, ClipperLib::JoinType joinType, double miterLimit) { // printf("new ExPolygon offset\n"); const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE); ClipperLib::Paths contours; ClipperLib::Paths holes; contours.reserve(expolygons.size()); { size_t n_holes = 0; for (size_t i = 0; i < expolygons.size(); ++ i) n_holes += expolygons[i].holes.size(); holes.reserve(n_holes); } for (Slic3r::ExPolygons::const_iterator it_expoly = expolygons.begin(); it_expoly != expolygons.end(); ++ it_expoly) { // 1) Offset the outer contour. { ClipperLib::Path input; Slic3rMultiPoint_to_ClipperPath(it_expoly->contour, &input); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.AddPath(input, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; co.Execute(out, delta_scaled); contours.insert(contours.end(), out.begin(), out.end()); } // 2) Offset the holes one by one, collect the results. { for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) { ClipperLib::Path input; Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole, &input); scaleClipperPolygon(input); ClipperLib::ClipperOffset co; if (joinType == jtRound) co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE); else co.MiterLimit = miterLimit; co.AddPath(input, joinType, ClipperLib::etClosedPolygon); ClipperLib::Paths out; co.Execute(out, - delta_scaled); holes.insert(holes.end(), out.begin(), out.end()); } } } // 3) Subtract holes from the contours. ClipperLib::Paths output; { ClipperLib::Clipper clipper; clipper.Clear(); clipper.AddPaths(contours, ClipperLib::ptSubject, true); clipper.AddPaths(holes, ClipperLib::ptClip, true); clipper.Execute(ClipperLib::ctDifference, *retval, ClipperLib::pftNonZero, ClipperLib::pftNonZero); } // 4) Unscale the output. unscaleClipperPolygons(*retval); }
BOOL GamePhysicsWorld::ClipperPolygonByShape( GameSprite* ptr_gamesprite, const std::string &shape_name, float float_position_x, float float_position_y ) { int num_result = FALSE; int num_ret_code = FALSE; b2Body* ptr_b2body_old = NULL; b2Fixture* ptr_b2fixture = NULL; b2Body* ptr_b2body_new = NULL; b2BodyDef bodyDef; b2Concave b2concave; ClipperLib::Paths clipper_paths_clipper(1); float float_offset_x = 0.0f; float float_offset_y = 0.0f; KGLOG_PROCESS_ERROR(ptr_gamesprite); ptr_b2body_old = ptr_gamesprite->GetB2Body(); KGLOG_PROCESS_ERROR(ptr_b2body_old); bodyDef.position = ptr_b2body_old->GetPosition(); float_offset_x = float_position_x - bodyDef.position.x * PTM_RATIO; float_offset_y = float_position_y - bodyDef.position.y * PTM_RATIO; bodyDef.type = ptr_b2body_old->GetType(); bodyDef.userData = ptr_b2body_old->GetUserData(); ptr_b2body_new = m_ptr_b2world->CreateBody(&bodyDef); ptr_b2fixture = ptr_b2body_old->GetFixtureList(); KGLOG_PROCESS_ERROR(ptr_b2fixture); num_ret_code = getPolygonFromCache(shape_name, &clipper_paths_clipper, float_offset_x, float_offset_y); KGLOG_PROCESS_ERROR(num_ret_code); while (ptr_b2fixture) { ClipperLib::Paths clipper_paths_main(1); ClipperLib::Paths clipper_paths_result; ClipperLib::Clipper clipper; num_ret_code = getPolygonFormBody(ptr_b2fixture, &clipper_paths_main); KGLOG_PROCESS_ERROR(num_ret_code); num_ret_code = clipper.AddPaths(clipper_paths_main, ptSubject, true); KGLOG_PROCESS_ERROR(num_ret_code); num_ret_code = clipper.AddPaths(clipper_paths_clipper, ptClip, true); KGLOG_PROCESS_ERROR(num_ret_code); num_ret_code = clipper.Execute(ClipperLib::ctDifference, clipper_paths_result, pftNonZero, pftNonZero); KGLOG_PROCESS_ERROR(num_ret_code); Paths::iterator it_group = clipper_paths_result.begin(); for(NULL; it_group != clipper_paths_result.end(); ++it_group) { Path::iterator it = it_group->begin(); b2Vec2 vec_vertices[1000]; int count_vertices = 0; b2FixtureDef b2fixturedef_new; b2fixturedef_new.restitution = ptr_b2fixture->GetRestitution(); b2fixturedef_new.friction = ptr_b2fixture->GetFriction(); b2fixturedef_new.density = ptr_b2fixture->GetDensity(); for(NULL; it != it_group->end(); ++it) { vec_vertices[count_vertices++].Set(float(it->X) / (PTM_RATIO * CLIPPER_RATIO), float(it->Y) / (PTM_RATIO * CLIPPER_RATIO)); } num_ret_code = b2concave.Create(ptr_b2body_new, &b2fixturedef_new, vec_vertices, count_vertices); KGLOG_PROCESS_ERROR(num_ret_code); } ptr_b2fixture = ptr_b2fixture->GetNext(); } num_ret_code = ptr_gamesprite->SetB2Body(ptr_b2body_new); KGLOG_PROCESS_ERROR(num_ret_code); m_ptr_b2world->DestroyBody(ptr_b2body_old); ptr_b2body_old = NULL; num_result = TRUE; Exit0: if (!num_result) { if(ptr_b2body_new) { m_ptr_b2world->DestroyBody(ptr_b2body_new); ptr_b2body_new = NULL; } } return num_result; }