bool CSketch::IsCircle()const { if (m_objects.size() == 1) { return m_objects.front()->GetType() == CircleType; } if (m_objects.size() > 1) { if (m_objects.front()->GetType() != ArcType) return false; HArc* reference_arc = (HArc*)(m_objects.front()); gp_Circ reference_circle = reference_arc->GetCircle(); for (std::list<HeeksObj*>::const_iterator It = m_objects.begin(); It != m_objects.end(); It++) { HeeksObj* span = *It; if (span->GetType() != ArcType) return false; HArc* arc = (HArc*)span; gp_Circ circle = arc->GetCircle(); if (fabs(circle.Radius() - reference_circle.Radius()) > wxGetApp().m_geom_tol) return false; if (!circle.Axis().Direction().IsEqual(reference_circle.Axis().Direction(), 0.01)) return false; } return true; } return false; }
std::vector<TopoDS_Face> MultiPoly(std::list<CSketch*> sketches) { tol = wxGetApp().m_geom_tol; shapes.clear(); //first pass: build lists of closed shapes std::list<CSketch*>::iterator it; for(it = sketches.begin(); it!= sketches.end(); ++it) { CSketch* sketch = *it; //Copy this sketches objects into a new list std::list<EndedObject*> sketchobjs; HeeksObj* obj = sketch->GetFirstChild(); while(obj) { //TODO: for now we only handle EndedObject EndedObject* eobj = dynamic_cast<EndedObject*>(obj); if(eobj) { HArc* arc = dynamic_cast<HArc*>(obj); if(arc) { shapes.push_back(new FastArc(arc->A->m_p,arc->B->m_p,arc->C->m_p,arc->m_axis.Direction().Z() > 0, arc->GetCircle())); } else shapes.push_back(new FastLine(eobj->A->m_p,eobj->B->m_p)); } obj = sketch->GetNextChild(); } } //Get a list of all the intersection points Intersector *m_int = new SimpleIntersector(); std::map<FastCurve*, std::vector<Intersection> > intersections = m_int->Intersect(shapes); //Make our flashy double hashmap TwoDNearMap bcurves(tol); //Create a new list of bounded segment objects. Whose endpoints are locatable via hash //with the exception that the hash returns values within tolerance of the specified point std::map<FastCurve*, std::vector<Intersection> >::iterator it2; for(it2 = intersections.begin(); it2 != intersections.end(); ++it2) { FastCurve *tline = (*it2).first; std::vector<Intersection> inter = (*it2).second; for(unsigned i=0; i < inter.size()-1; i++) { double startu=tline->GetU(inter[i].X,inter[i].Y); double newu=tline->GetU(inter[i+1].X,inter[i+1].Y); CompoundSegment* segment; if(startu < newu) segment = new CompoundSegment(tline,tol,startu,newu); else segment = new CompoundSegment(tline,tol,newu,startu); bcurves.insert(inter[i].X,inter[i].Y,segment); bcurves.insert(inter[i+1].X,inter[i+1].Y,segment); startu = newu; } } //This gets the hashtable working bcurves.sort(); AnalyzeNearMap(bcurves); std::vector<CompoundSegment*> closed_shapes; //Create a new tree of boundedcurves, that is much smaller. follow all chains and attempt to remove //segments that are connected to only 2 other curves. This will yield a non-orientable graph //so our definition of polygons better be very graph theoretical std::vector<void*> returnvec; for(int i=0; i < bcurves.GetVecCount(); i++) { OneDNearMap* ptMap = bcurves.GetElement(i); double x_coord = bcurves.GetCoord(i); for(int j=0; j < ptMap->GetVecCount(); j++) { double y_coord = ptMap->GetCoord(j); if(!ptMap->IsValid(j)) continue; returnvec.clear(); bcurves.find(x_coord,y_coord,returnvec); if(returnvec.size() == 1) { //TODO: this means the current segment is part of an unclosed shape. However it is not clear that //this shape is fully concatenated or does not intersect a closed shape. these should probably be removed //prior to this loop continue; } if(returnvec.size() != 2) continue; //Concatenate the 2 groups and remove *it4 from the map CompoundSegment* seg1 = (CompoundSegment*)returnvec[0]; CompoundSegment* seg2 = (CompoundSegment*)returnvec[1]; if(seg1 == seg2) { //this means we have found a closed shape. Remove it from the bcurves and add it to a list of closed shapes //remove from the map bcurves.remove(x_coord,y_coord,seg1); bcurves.remove(x_coord,y_coord,seg2); closed_shapes.push_back(seg1); continue; } ConcatSegments(x_coord,y_coord,seg1,seg2,bcurves); } } //Now we have a graph of CompoundSegment*. These should be fast to traverse. //Non self intersecting shapes are already in closed_shapes //We could speed this up by regenerating near_map to get rid of removed references bool done=false; while(!done) { bool found=false; for(int i=0; i < bcurves.GetVecCount(); i++) { OneDNearMap* ptMap = bcurves.GetElement(i); double x_coord = bcurves.GetCoord(i); for(int j=0; j < ptMap->GetVecCount(); j++) { double y_coord = ptMap->GetCoord(j); if(!ptMap->IsValid(j)) continue; returnvec.clear(); bcurves.find(x_coord,y_coord,returnvec); //for most cases, returnvec should have 4 elements. more complicated cases have an even number > 4 //check for elements that are the same, which mean this polygon could terminate here, so terminate it //and merge the other CompoundSegments if there are only two remaining int nfound=0; for(size_t k=0; k < returnvec.size(); k++) { for(size_t l=k+1; l < returnvec.size(); l++) { if(returnvec[k] == returnvec[l]) { //this means we have found a closed shape. Remove it from the bcurves and add it to a list of closed shapes //remove from the map bcurves.remove(x_coord,y_coord,returnvec[k]); bcurves.remove(x_coord,y_coord,returnvec[l]); closed_shapes.push_back((CompoundSegment*)returnvec[k]); nfound+=2; found=true; } } } //now we know that no 2 elements in returnvec are equal. //make sure there are the right number of elements for our next op if(returnvec.size() - nfound != 2) continue; //Quick and dirty way to get the pointers returnvec.clear(); bcurves.find(x_coord,y_coord,returnvec); //Merge the segments and get them out of this coordinate ConcatSegments(x_coord,y_coord,(CompoundSegment*)returnvec[0],(CompoundSegment*)returnvec[1],bcurves); found=true; } } if(!found) done = true; } //Now that we have all closed shapes, we need to define the relationships. Since we know that they are not intersecting //3 kinds of things can happen. A shape is either inside, enclosing, adjacent, or unrelated to another. std::vector<std::vector<CompoundSegment*> > inside_of; inside_of.resize(closed_shapes.size()); for(unsigned i=0; i < closed_shapes.size(); i++) { for(unsigned j=0; j < closed_shapes.size(); j++) { //We can determine if a shape is inside or outside by finding the winding number of just 1 point with the //entire other polygon if(i==j) continue; int rays = closed_shapes[i]->GetRayIntersectionCount(closed_shapes[j]->Begin()); if(rays%2) { //Polygon J is inside of polygon I inside_of[j].push_back(closed_shapes[i]); int x=0; x++; } } } //This is used to reverse the ordering of a closed shape. Getting it to be CW or CCW //OCC is picky about the ordering when the polygon has holes for(unsigned i=0; i < closed_shapes.size(); i++) { closed_shapes[i]->Order(); #ifdef FORCEPOLYGONORDERING bool cw = closed_shapes[i]->GetCW(); if(!cw) { closed_shapes[i]->Reverse(); closed_shapes[i]->Order(); } #endif } //Sort these lists for easy comparison for(unsigned i=0; i < inside_of.size(); i++) { std::sort(inside_of[i].begin(),inside_of[i].end()); } //Now we want to descend into this thing. First find all shapes that are inside of nothing else std::vector<std::pair<CompoundSegment*,std::vector<CompoundSegment*> > > gold; find_level(true,gold,closed_shapes,inside_of,std::vector<CompoundSegment*>()); return TopoDSFaceAdaptor(gold); }