static void SimplifySketch(const double deviation, bool make_bspline ) { wxGetApp().CreateUndoPoint(); double original_tolerance = wxGetApp().m_geom_tol; wxGetApp().m_geom_tol = sketch_tool_options.m_cleanup_tolerance; std::list<HeeksObj *> selected_sketches; std::copy( wxGetApp().m_marked_list->list().begin(), wxGetApp().m_marked_list->list().end(), std::inserter( selected_sketches, selected_sketches.begin() )); std::list<HeeksObj*>::const_iterator It; for(It = selected_sketches.begin(); It != selected_sketches.end(); It++){ HeeksObj* object = *It; std::list<HeeksObj *> new_objects; if (object->GetType() == SketchType) { std::list<TopoDS_Shape> wires; try { heekscad_interface.ConvertSketchToFaceOrWire(object, wires, false); } // End try catch(...) { continue; } for (std::list<TopoDS_Shape>::iterator itWire = wires.begin(); itWire != wires.end(); itWire++) { std::list<SimplifySketchTool::SortPoint> points = SimplifySketchTool::GetPoints( TopoDS::Wire(*itWire), deviation ); if (sketch_tool_options.m_sort_points) { // The sort points option is turned on. The idea of this is to detect shapes that include // sections that 'double back' on themselves. The first example being a shape made up of // a box as well as a single line that layed along one edge of the box. In this case the extra // line was superfluous. If we sort the points so that each point is closest to the previous // point then, hopefully, we will reorder these shapes that double back on themselves. If this // doesn't work then the user can always turn the 'sort points' option off and try again. std::vector<SimplifySketchTool::SortPoint> sorted_points; std::copy( points.begin(), points.end(), std::inserter( sorted_points, sorted_points.begin() )); for (std::vector<SimplifySketchTool::SortPoint>::iterator l_itPoint = sorted_points.begin(); l_itPoint != sorted_points.end(); l_itPoint++) { // We've already begun. Just sort based on the previous point's location. std::vector<SimplifySketchTool::SortPoint>::iterator l_itNextPoint = l_itPoint; l_itNextPoint++; if (l_itNextPoint != sorted_points.end()) { SimplifySketchTool::sort_points_by_distance compare( *l_itPoint ); std::sort( l_itNextPoint, sorted_points.end(), compare ); } // End if - then } // End for points.clear(); std::copy( sorted_points.begin(), sorted_points.end(), std::inserter( points, points.begin() )); // This sorting process will have resulted in the start and end points being located next to each other // and hence removed. If the original wire was periodic (closed shape) then make sure the last point // is the same as the first point. TopoDS_Wire wire(TopoDS::Wire(*itWire)); if (wire.Closed()) { if (*(points.begin()) != *(points.rbegin())) { points.push_back(*points.begin()); // Close the shape manually. } } } // Whether we sorted or not, we may want to close the shape. if (sketch_tool_options.m_force_closed_shape) { if (*(points.begin()) != *(points.rbegin())) { points.push_back(*points.begin()); // Close the shape manually. } } // Now keep removing points from this list as long as the midpoints are within deviation of // the line between the two neighbour points. bool points_removed = false; do { points_removed = false; for (std::list<SimplifySketchTool::SortPoint>::iterator itPoint = points.begin(); itPoint != points.end(); itPoint++ ) { std::list<SimplifySketchTool::SortPoint>::iterator itP1 = itPoint; std::list<SimplifySketchTool::SortPoint>::iterator itP2 = itPoint; std::list<SimplifySketchTool::SortPoint>::iterator itP3 = itPoint; itP2++; if (itP2 != points.end()) { itP3 = itP2; itP3++; if (itP3 != points.end()) { // First see if p1 and p2 are too close to each other. if (itP1->Distance(*itP2) < deviation) { // Discard p2. points.erase(itP2); points_removed = true; continue; } if (itP2->Distance(*itP3) < deviation) { // Discard p2 points.erase(itP2); points_removed = true; continue; } if (itP1->Distance(*itP3) > deviation) { // Now draw a line between p1 and p3. Measure the distance between p2 and the nearest point // along that line. If this distance is less than the max deviation then discard p2. gp_Lin line(*itP1, gp_Dir(itP3->X() - itP1->X(), itP3->Y() - itP1->Y(), itP3->Z() - itP1->Z())); if (line.SquareDistance(*itP2) < deviation) { // Discard p2 points.erase(itP2); points_removed = true; continue; } } } } } // End for } while (points_removed == true); if (points.size() >= 2) { if (make_bspline) { try { TColgp_Array1OfPnt Points(0, points.size()-1); Standard_Integer i=0; for (std::list<SimplifySketchTool::SortPoint>::iterator itPoint = points.begin(); itPoint != points.end(); itPoint++, i++) { Points.SetValue(i, *itPoint); } // GeomAPI_PointsToBSpline bspline(Points); GeomAPI_PointsToBSpline bspline(Points, sketch_tool_options.m_degree_min, sketch_tool_options.m_degree_max, GeomAbs_Shape(sketch_tool_options.m_continuity), sketch_tool_options.m_cleanup_tolerance); // Standard_EXPORT GeomAPI_PointsToBSpline(const TColgp_Array1OfPnt& Points,const Standard_Integer DegMin = 3,const Standard_Integer DegMax = 8,const GeomAbs_Shape Continuity = GeomAbs_C2,const Standard_Real Tol3D = 1.0e-3); HSpline *hspline = new HSpline(bspline.Curve(), &(wxGetApp().current_color)); heekscad_interface.Add( hspline, NULL ); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); wxMessageBox(_("Failed to create BSpline curve")); } } // End if - then else { // We're making straight lines HeeksObj *sketch = heekscad_interface.NewSketch(); for (std::list<SimplifySketchTool::SortPoint>::iterator itPoint = points.begin(); itPoint != points.end(); itPoint++) { std::list<SimplifySketchTool::SortPoint>::iterator itNext = itPoint; itNext++; if (itNext == points.end()) continue; double start[3], end[3]; itPoint->ToDoubleArray(start); itNext->ToDoubleArray(end); sketch->Add(heekscad_interface.NewLine(start, end), NULL); } // End for // heekscad_interface.Add(sketch, NULL); new_objects.push_back(sketch); } // End if - else } // End if - then } // End for if (new_objects.size() > 0) { #ifdef MULTIPLE_OWNERS std::list<HeeksObj *> parents = object->Owners(); for (std::list<HeeksObj *>::iterator itOwner = parents.begin(); itOwner != parents.end(); itOwner++) { #else if(object->m_owner) { #endif if ((object->CanEditString()) && (object->GetShortString())) { // (*itOwner)->Remove(object); // Mark the old sketches with a name that can be easily recognised so that we can delete the // old objects if we're satisfied with the replacements. wxString title; title << _("Replaced ") << object->GetShortString(); object->OnEditString(title); } // End if - then for (std::list<HeeksObj *>::iterator itNewChild = new_objects.begin(); itNewChild != new_objects.end(); itNewChild++) { #ifdef MULTIPLE_OWNERS (*itOwner)->Add( *itNewChild, NULL ); #else object->m_owner->Add( *itNewChild, NULL ); #endif } // End for } // End for } // End if - then } // End if - then } // End for wxGetApp().m_geom_tol = original_tolerance; wxGetApp().Changed(); } void SimplifySketchTool::Run() { SimplifySketch(m_deviation, false); } // End Run() method