/********************************************************************/ /* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno */ /* All rights reserved. */ /********************************************************************/ #include "MGCLStdAfx.h" #include "mg/Box.h" #include "mg/Position.h" #include "mg/Curve.h" #include "mg/CompositeCurve.h" #include "mg/TrimmedCurve.h" #include "mg/Straight.h" #include "mg/LBRep.h" #include "mg/SurfCurve.h" #include "mg/FSurface.h" #include "mg/Surface.h" #include "mg/CParam_list.h" #include "mg/CCisect_list.h" #include "mg/CSisect_list.h" #include "mg/Position_list.h" #include "mg/Tolerance.h" #include "topo/LEPoint.h" #include "topo/LPoint.h" #include "topo/Edge.h" #include "topo/LCisect_vector.h" #include "topo/LLisect_vector.h" #include "topo/Loop.h" #include "topo/Face.h" #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // //Implements MGLoop Class. //MGLoop is a boundary of a face, a boundary of 2D manifold cell. //MGLoop always accepts parameter space curve and world space curve //of a boundary curve, and constructs a boundary of a face from the //two types of curves. //Input curves direction indicate which part of the face will be target //part after trimed by the boundary. In 2D space (u,v) of the parameter //space, LEFT side of the parameter curve along the curve's direction //is the target part of face. ///////Constructor//////// //Void constructor. MGLoop::MGLoop() :m_kind(UNDEFINED),m_area(0.),m_perim_num_s(0),m_perim_num_e(0){;} //Copy constructor. MGLoop::MGLoop(const MGLoop& loop2) :MGBoundary(loop2), m_kind(loop2.m_kind),m_area(loop2.m_area), m_perim_num_s(loop2.m_perim_num_s),m_perim_num_e(loop2.m_perim_num_e){;} //Fundamental constructor. //Construct from boundary complex(i.e. MGLoop). //This constructor takes the ownership of MGCell* in boundary. MGLoop::MGLoop( std::list boundaries) //Boundary data of the super class MGBoundary. :MGBoundary(boundaries) ,m_kind(UNDEFINED),m_area(0.),m_perim_num_s(0), m_perim_num_e(0){;} //Construct a loop of one edge. MGLoop::MGLoop(MGEdge* edge) :m_kind(UNDEFINED),m_area(0.), m_perim_num_s(0), m_perim_num_e(0){ append_pcell(edge); } //Construct a Loop of one edge of one curve cell. //param_curve is parameter space representation of the face //of which this loop will be a boundary, will make parameter cell. //world_curve is world coordinate representation of the face //of which this loop will be a boundary, will make binder cell. //range1 is parameter range of the curve param_curve, //range2 is parameter range of the curve world_curve. //When range1,2 are not specified, the start and the end of the curve are //treated as their range. //***param_curve and world_curve must have the same direction. MGLoop::MGLoop(const MGCurve& param_curve, const MGCurve& world_curve) :m_kind(UNDEFINED),m_area(0.), m_perim_num_s(0), m_perim_num_e(0){ std::unique_ptr pcurve(param_curve.clone()); std::unique_ptr wcurve(world_curve.clone()); make_loop(pcurve,wcurve); } MGLoop::MGLoop( const MGCurve& param_curve, const MGInterval& range1, const MGCurve& world_curve, const MGInterval& range2) :m_kind(UNDEFINED),m_area(0.), m_perim_num_s(0), m_perim_num_e(0){ std::unique_ptr pcurve(param_curve.clone()); pcurve->limit(range1); std::unique_ptr wcurve(world_curve.clone()); wcurve->limit(range2); make_loop(pcurve,wcurve); } MGLoop::MGLoop( std::unique_ptr& param_curve, std::unique_ptr& world_curve) :m_kind(UNDEFINED),m_area(0.), m_perim_num_s(0), m_perim_num_e(0){ make_loop(param_curve,world_curve); } //Copy constructor with binder cell map. MGLoop::MGLoop( const MGLoop& loop, //original Loop. MGCellMap& cmap) //cellmap to register binder association. //Binder cells of the pcells in loop will be registered in cmap. :MGBoundary(loop, cmap),m_area(loop.m_area),m_kind(loop.m_kind) ,m_perim_num_e(loop.m_perim_num_e), m_perim_num_s(loop.m_perim_num_s){;} //Make loop void MGLoop::make_loop( std::unique_ptr& param_curve,//parameter curve std::unique_ptr& world_curve //World curve ){ MGCurve* pcurve=param_curve.release(); MGCurve* wcurve=world_curve.release(); MGCompositeCurve* pcurveC=dynamic_cast(pcurve); MGCompositeCurve* wcurveC=dynamic_cast(wcurve); int npcurveC; if(pcurveC){ npcurveC=pcurveC->number_of_curves(); if(npcurveC==1){ //transform pcurveC to an ordinary curve. //(which will be stored in pcurve). pcurve=pcurveC->release_front(); delete pcurveC; pcurveC=0; if(wcurveC){ int nwcurveC=wcurveC->number_of_curves(); if(nwcurveC==1){ wcurve=wcurveC->release_front(); delete wcurveC; } } } } if(!pcurveC){ //Case that param_curve is not MGCmpositeCurve. //Generate loop complex. MGEdge* e=new MGEdge(pcurve); e->set_binder_edge(wcurve); append_pcell(e); return; } //Case that param_curve is MGCmpositeCurve. //Generate MGEdge for each component curve of pcurveC. bool use_wcurveC=false;//Flag to indicate that wcurveC[i] be used //for pcurveC[i]'s binder. if(wcurveC){ if(npcurveC==wcurveC->number_of_curves()) use_wcurveC=true; } for(int i=0; irelease_front()); append(e); if(use_wcurveC){ MGCurve* wcurvei=wcurveC->release_front(); e->set_binder_edge(wcurvei); } } delete pcurveC; delete wcurveC; } ///////Destructor/////// ///////operator overload/////// //Assignment. //When the leaf object of this and bnd2 are not equal, this assignment //does nothing. MGLoop& MGLoop::operator=(const MGLoop& loop2){ if(this==&loop2) return *this; MGBoundary::operator=(loop2); m_kind=UNDEFINED; m_area=0.; return *this; } MGLoop& MGLoop::operator=(const MGGel& gel2){ const MGLoop* gel2_is_this=dynamic_cast(&gel2); if(gel2_is_this) operator=(*gel2_is_this); return *this; } //Object transformation. MGLoop& MGLoop::operator+=(const MGVector& v){ MGBoundary::operator+=(v); m_kind=UNDEFINED; m_area=0.; return *this; } MGLoop& MGLoop::operator-=(const MGVector& v){ MGBoundary::operator-=(v); m_kind=UNDEFINED; m_area=0.; return *this; } MGLoop& MGLoop::operator*=(double scale){ MGBoundary::operator*=(scale); m_kind=UNDEFINED; m_area=0.; return *this; } MGLoop& MGLoop::operator*=(const MGMatrix& mat){ MGBoundary::operator*=(mat); m_kind=UNDEFINED; m_area=0.; return *this; } MGLoop& MGLoop::operator*=(const MGTransf& tr){ MGBoundary::operator*=(tr); m_kind=UNDEFINED; m_area=0.; return *this; } //This operator is to sort loops in the order: // 1. Perimeter boundary. // 2. Outer boundary. // 3. Inner boundary. // 4. Inactive loop. bool MGLoop::operator<(const MGLoop& loop2)const{ const MGFace* f1=face(); const MGFace* f2=loop2.face(); if(f1!=f2) return MGComplex::operator<(loop2); int i1,i2,j1,j2; bool is_peri1=both_end_on_perimeter(i1,i2); bool is_peri2=loop2.both_end_on_perimeter(j1,j2); if(is_peri1 && !is_peri2) return true; else if(!is_peri1 && is_peri2) return false; else if(is_peri1 && is_peri2){ //Now both are on perimeter. i1,i2,j1,j2 are valid. if(i2j1 || i2>j2 || i1>j1 || i1>j2) return false; //Now i1==i2==j1==j2. MGPosition p1=start_point(), p2=loop2.start_point(); MGPosition q1=end_point(), q2=loop2.end_point(); int is_v=i1%2; double t1,t2; t1=p1(is_v), t2=q1(is_v); if(i1>=2){ t1*=-1.; t2*=-1.;} if(t2=2){ t1*=-1.; t2*=-1.;} if(t2less_than(i1,p1,p2); else return true; }else{ //Now both are not on perimeter. bool cls1=closed(), cls2=loop2.closed(); if(!cls1 && !cls2) return true; else if(cls1 && !cls2) return true; if(!cls1 && cls2) return false; else{ //Now both are closed. if(is_outer_boundary()) return true;//Outer boundary. else if(loop2.is_outer_boundary()) return false; //this is inner and loop2 is outer. return this<(&loop2); } } } bool MGLoop::operator<(const MGGel& gel2)const{ const MGLoop* gel2_is_this=dynamic_cast(&gel2); if(gel2_is_this) return operator<(*gel2_is_this); return false; } bool MGLoop::operator<(const MGComplex& gel2)const{ const MGLoop* gel2_is_this=dynamic_cast(&gel2); if(gel2_is_this) return operator<(*gel2_is_this); return false; } ///////Member Function/////// //Test if this is active boundary. bool MGLoop::active() const{ get_kind(); return m_kind>0; } //Append edge to the end of loop. //append connects the edge's start to the end of the loop. void MGLoop::append(MGEdge* e){ if(edge_exist()) last_edge()->join(false,e); else append_pcell(e); m_kind=UNDEFINED; } //Build one edge of srf from the curve wcrv on srf and common information //pspan and peri_num, which are a perimeter peri_num's parameter spans(psapn). //wcrv must not be a MGCompositeCurve. //One edge is generated and append to this loop. void MGLoop::append_edge_from_crv( const MGSurface& srf, const MGCurve& wcrv,//curve of world coordinates on this face that may //coincide to a perimeter of the surface of srf. double& tLast,//wcrv's parameter value to start is input and the end param value //of the last edge generated will be output. double terror,//wcrv's parameter space error. const std::vector& pspan,//common parameter value of a perimeter peri_num. int peri_num,//pspan and peri_num are output of getPerimeterCommon(). Refer to it. bool orientation_is_opposite//orientation flag of wcrv to edge. True if opposite. ){ std::unique_ptr ccrv(new MGCompositeCurve);//temporal curve to join this loop. int ncommon=(int)pspan.size()/4; for(int i=0; itLast+terror){ MGCurve* uvcrv=srf.get_parameterCurve(MGTrimmedCurve(wcrv,tLast,t0)); ccrv->connect_to_end(uvcrv);//std::cout<<(*ccrv)<connect_to_end(new MGStraight(uv1,uv0));//std::cout<<(*edge)<connect_to_end(uvcrv);//std::cout<<(*edge)<negate(); MGCurve* crv; int ncrv=ccrv->number_of_curves(); if(!ncrv){ MGPosition uvS, uvE; srf.perp_one(wcrv.eval(tLast),uvS); srf.perp_one(wcrv.eval(tEnd),uvE); crv=new MGStraight(uvE,uvS); }else if(ncrv==1) crv=ccrv->release_front(); else crv=ccrv.release(); append(new MGEdge(crv)); tLast=tEnd; } //Compute curvilinear integral of the parameter space of the area //sorrounded by the loop. double MGLoop::area()const{ get_kind(); if(m_kind==OUTER_LOOP || m_kind==INNER_LOOP) return m_area; return m_area=compute_area(); } //Test if loop is a perimeter boundary loop or not. //If yes, gets perimeter id. //pid_s, e are valid only when both_end_on_perimeter() is true, //contain perimeter number of the start or end of the loop. bool MGLoop::both_end_on_perimeter(int& pid_s, int& pid_e,const MGFSurface* srf) const{ get_kind(srf); pid_s=m_perim_num_s; pid_e=m_perim_num_e; return m_kind==PERIMITER_LOOP; } //Make a clone. MGLoop* MGLoop::clone(MGCell& parent) const{ MGLoop* lpp=clone(); lpp->set_parent(parent); return lpp; } MGLoop* MGLoop::clone() const{ MGLoop* lpp=new MGLoop(*this); return lpp; } //Make a clone. //The forms that have cmap as an argumetnt is to register binder association. //Binders of pcells in this loop will be registered in cmap. //Returned is pointer of newed object, must be deleted. //When parent is specified, clone's parent is set to the parent. MGLoop* MGLoop::clone(MGCell& parent,MGCellMap& cmap) const{ MGLoop* lpp=clone(cmap); lpp->set_parent(parent); return lpp; } MGLoop* MGLoop::clone(MGCellMap& cmap) const{ MGLoop* lpp=new MGLoop(*this,cmap); return lpp; } //Make a clone that has not binders. MGLoop* MGLoop::clone_without_binders(MGCell& parent) const{ MGLoop* lpp=clone_without_binders(); lpp->set_parent(parent); return lpp; } MGLoop* MGLoop::clone_without_binders() const{ MGLoop* lpp=new MGLoop(); lpp->copy_boundary_without_binders(*this); return lpp; } //Test if this is closed boundary. bool MGLoop::closed() const{ if(!edge_exist()) return false; return (first_edge()->pre_edge()==last_edge());//When closed. } //Compute the closest point from the point P to this loop. //Returned is the loop's point, and distance is the length of distance //between P and MGLEPoint. //All the coordinate values are of parameter space of the face's surface. MGLEPoint MGLoop::closest(const MGPosition& P, double& distance) const{ MGLEPoint lp; const_cellItr pcitr=pcell_begin(),pcitre=pcell_end(),pcisave; double t=0.,len=-1.; MGTolerance::push(); MGTolerance::set_wc_zero(error()); double lent, ttemp; const MGEdge* e; for(; pcitr!=pcitre; pcitr++){ lent=(*pcitr)->box().distance(P); if(len<0. || lent(*pcitr); MGTrimmedCurve crv(e->trimmed_curve()); //std::cout< boundaries=curves_world(); int bnum=(int)boundaries.size(); const MGSurface* srf=0; const MGFace* f=face(); if(f) srf=f->surface(); if(!bnum || !srf) return false; double tc=sl.closest(srf->center()); MGUnit_vector sldir=sl.direction(); const MGPosition origin=sl.eval(tc); MGMatrix M; M.set_axis(sldir,2); MGPvector boxps(bnum); std::vector boxes(bnum); for(int i=0; ibox(); bxi-=origin; bxi*=M; MGBox* bxi2D=new MGBox(2,bxi); boxps.reset(i,bxi2D); boxes[i]=mgBCPair(bxi2D,i);//set the pair of box and curve pointer. } const MGPosition& ORIGIN2=MGDefault::origin_2D(); MGBox2PositionCompare comp(ORIGIN2); std::sort(boxes.begin(), boxes.end(), comp); double dist1, dist2=dist*dist; if(dist<=0.) dist2=-1.; MGPosition P,P1; MGPosition tt;//The nearest parameter of Curve and sl are set in tt[0] and tt[1]. const MGCurve* Curve; int jsave=-1; for(int j=0; j=dist2) continue; MGPosition tt2=crvi.closest(sl); P1=crvi.eval(tt2[0]); MGVector dif=P1-sl.eval(tt2[1]); dist1=dif%dif; if(dist1=0; if(found){// //Here, j=id of boundaries that indicates the j-th boundary Curve, //tt[0] is the parameter Curve, and tt[1] is the parameter of sl. int icrv=boxes[jsave].second; MGComplex::const_pcellItr eItr=pcellIterator(icrv); const MGEdge* ei=static_cast(*eItr); closest=MGLEPoint(eItr,ei->param_pcell(tt[0])); dist=sqrt(dist2); } return found; } //Compute curvilinear integral of the loop. double MGLoop::compute_area()const{ double area=0.; const_cellItr i=pcell_begin(),ie=pcell_end(); for(; i!=ie; i++){ const MGEdge* edg=edge_from_iterator(i); const MGCurve* crv=edg->base_curve(); if(crv){ MGInterval rng=edg->range(); area+=crv->curvilinear_integral (rng.low_point(), rng.high_point()); } } return area; } //Copy loop data. //This boundary data is cleared and loop's boundary is copied into this. void MGLoop::copy_boundary(const MGBoundary& loop){ assert(dynamic_cast(&loop)); const MGLoop* lpp=dynamic_cast(&loop); MGBoundary::copy_boundary(loop); m_area=lpp->m_area; m_kind=lpp->m_kind; } //Copy boundary data, but does not copy the binders. void MGLoop::copy_boundary_without_binders(const MGBoundary& loop){ assert(dynamic_cast(&loop)); const MGLoop* lpp=dynamic_cast(&loop); MGBoundary::copy_boundary_without_binders(loop); m_area=lpp->m_area; m_kind=lpp->m_kind; } //Obtain vector of curves(TrimmedCurve) of the loop. //The curves are of parameter space expression. ///Let crvs be the output of curves() and wcrvs of curves_world(), ///then crvs[i] corresponds to wcrvs[i] one by one. MGPvector MGLoop::curves()const{ MGComplex::const_cellItr i=pcell_begin(),ie=pcell_end(); int n=number_of_pcells(), j=0; MGPvector crvs(n); for(; i!=ie; i++,j++){ const MGEdge* edg=edge_from_iterator(i); crvs.reset(j,new MGTrimmedCurve(edg->trimmed_curve())); } return crvs; } //Obtain vector of curves(world coordinate expression) of the loop. //Output curves are MGTrimmedCurve of edge's binders. //When some of the edges do not have binders, they will be created. ///Let crvs be the output of curves() and wcrvs of curves_world(), ///then crvs[i] corresponds to wcrvs[i] one by one. MGPvector MGLoop::curves_world()const{ assert(surface()); //Surface expression must exist. MGPvector crvs; MGComplex::const_cellItr i=pcell_begin(),ie=pcell_end(); for(; i!=ie; i++){ const MGEdge* eip=edge_from_iterator(i); MGEdge* bedg=eip->make_binder_with_curve(); MGTrimmedCurve trim(bedg->trimmed_curve()); MGCurve* crv=trim.clone(); //if(!eip->equal_direction_to_binder()) // crv->negate(); crvs.push_back(crv); } return crvs; } //Return i-th edge pointer. MGEdge* MGLoop::edge(int i){ m_kind=UNDEFINED; MGCellNB* cell=pcelli(i); return static_cast(cell); } const MGEdge* MGLoop::edge(int i) const{ const MGCellNB* cell=pcelli(i); return static_cast(cell); } //Get edge pointer from its iterator in MGComplex of MGBoudarynD. MGEdge* edge_from_iterator(MGComplex::pcellItr i){ return static_cast(*i); } const MGEdge* edge_from_iterator(MGComplex::const_pcellItr i){ return static_cast(*i); } //Get edge number in this loop. //If e is not a member of this loop, 0 will be returned. int MGLoop::edge_num(const MGEdge* e)const{ const_pcellItr cell=pcell_begin(); const_pcellItr celle=pcell_end(); int i=0; for(; cell!=celle; cell++, i++) if((*cell)==dynamic_cast(e)) return i; return 0; } //Return end point of this loop as MGLEPoint. //loop must include at least one edge, or this output is undefined. MGLEPoint MGLoop::end_LPoint() const{ double t=0.; const_pcellItr cb=pcell_begin(), ce=pcell_end(); if(cb!=ce){ce--; t=edge_from_iterator(ce)->param_e();} return MGLEPoint(ce,t); } //Return end point of this loop as MGPosition. //The point is of parameter space. MGPosition MGLoop::end_point() const{ MGPosition P; if(edge_exist()){ const MGEdge* e=last_edge(); double t=e->param_e(); P=e->base_curve()->eval(t); } return P; } //Get error of this loop. //This is obtained from the box of the loop and relative zero. double MGLoop::error()const{ const MGCellNB* parent=star(); double err; if(parent) err=parent->parameter_error(); else{ double err1,err2; MGBox prange=box(); err1=prange(0).relative_error(); err2=prange(1).relative_error(); err=sqrt(err1*err1+err2*err2); } return err; } //Evaluation of the loop at the point t. //When nderi=0, get a parameter (u,v) of the surface at the boundary point. MGVector eval(const MGLEPoint& t, int nderi){ return t.eval(nderi); } //Evaluation of the loop at the point t. MGVector MGLoop::eval(const MGLPoint& t, int nderi)const{ MGVector data; const MGCurve* crv=edge(t.edge_num())->base_curve(); if(crv) data=crv->eval(t.param(), nderi); return data; } //Evaluation of the loop at i-th edge's parameter t. MGVector MGLoop::eval(int i, double t, int nderi)const{ MGVector data; const MGCurve* crv=edge(i)->base_curve(); if(crv) data=crv->eval(t, nderi); return data; } //Return pointer of the face. If the loop is not a boundary of any face, //null will be returned. const MGFace* MGLoop::face() const{ const MGCellNB* cell=star(); return dynamic_cast(cell); } MGFace* MGLoop::face(){ MGCellNB* cell=star(); return dynamic_cast(cell); } //Return edge pointer of the first edge. const MGEdge* MGLoop::first_edge() const{ const MGCellNB* cell=first_pcell(); return static_cast(cell); } MGEdge* MGLoop::first_edge(){ m_kind=UNDEFINED; MGCellNB* cell=first_pcell(); return static_cast(cell); } //Compute loop kind. void MGLoop::compute_kind(const MGFSurface* srf)const{ if(edge_exist()){ const MGEdge* pre=first_edge()->pre_edge(); if(pre==last_edge()){//When closed. m_area=compute_area(); if(m_area<0.) m_kind=INNER_LOOP; //Inner boundary loop. else m_kind=OUTER_LOOP; //Outer boundary loop. }else{ if(get_perimeter_num(m_perim_num_s,m_perim_num_e,srf)) m_kind=PERIMITER_LOOP; //Perimeter boundary loop. else m_kind=INACTIVE; //Inactive loop. } }else m_kind=UNDEFINED; } //Get the loop id of this loop in the star face baoundary. //Let face=face(), then face->loop(get_loop_id_in_face())=this; //When this does not have star face, or this is not a boundary of a face, //-1 will be returned. int MGLoop::get_loop_id_in_face()const{ const MGFace* f=face(); if(!f) return -1; int n=f->number_of_loops(); for(int i=0; iloop(i)==this) return int(i); } return -1; } //Get loop kind. void MGLoop::get_kind(const MGFSurface* srf) const{ if(m_kind>=0) return; compute_kind(srf); } //Get perimeter number where start or end point lies on. //Function's return value is: // true if both end on perimeter, // false if any of start or end point not on perimeter. //pid_s, _e are valid only when true is returned. bool MGLoop::get_perimeter_num(int& pid_s, int& pid_e,const MGFSurface* surf) const{ pid_s=pid_e=0; const MGSurface* srf=0; if(surf) srf=surf->get_surface_pointer(); if(!srf) srf=surface(); if(!srf) return false; MGPosition p=start_point(); double u=p.ref(0), v=p.ref(1); double rczero=MGTolerance::rc_zero(); MGTolerance::set_rc_zero(rczero*50.); bool result; if(srf->on_a_perimeter(u,v,pid_s)){ p=end_point(); u=p.ref(0), v=p.ref(1); result=srf->on_a_perimeter(u,v,pid_e)!=0; }else result=false; MGTolerance::set_rc_zero(rczero); return result; } //Test if parameter value (u,v) is inside this loop or not. //inside means inside face, that is, //if the loop is inner, outside inner loops and //if the loop is outer boundary loop, inside the outer boundary loop. //This can be used for perimeter boundary loops. //Returned is: // 0:outside(not on the loop) // 1:unknown // 2:inside(not on the loop) /// otherwise:on the loop(int(parameter edge id +100))will be returned. int MGLoop::inside(double u, double v) const{ return inside(MGPosition(u,v)); } int MGLoop::inside(const MGPosition& uv) const{ int out; if(box().includes(uv)) out=inside_test(uv); else{ if(is_inner_boundary()) out=2; else out=0; } return out; } //Compute intersections of this loop(parameter rep of the face) //and param_curve. MGLCisect_vector MGLoop::isect(const MGCurve& param_curve)const{ double err=error(); double errsave=MGTolerance::set_wc_zero(err); MGLCisect_vector lcv=isect(err,param_curve); MGTolerance::set_wc_zero(errsave); return lcv; } ///Compute intersections of this loop(parameter rep of a face) ///and param_curve. MGLCisect_vector MGLoop::isect( double error,//error to get intersection of the loops and sl. const MGCurve& param_curve ) const{ MGLCisect_vector lcis(*this); if(!has_common(param_curve)) return lcis; MGComplex::const_pcellItr i=pcell_begin(), ie=pcell_end(); //Compute intersection points. for(; i!=ie ; i++){ const MGEdge* e=edge_from_iterator(i); MGTrimmedCurve curve(e->trimmed_curve()); MGCCisect_list list=curve.isect(param_curve); MGCCisect_list::CCiterator itr=list.begin(), itrend=list.end(); for(;itr!=itrend; itr++) lcis.append( MGLCisect( MGLEPoint(i,(*itr).param1()), (*itr).param2(), (*itr).point() ) ); } return lcis; } //Compute intersections of two loops. MGLLisect_vector MGLoop::isect(const MGLoop& loop2) const{ MGLLisect_vector vec(*this); if(!has_common(loop2)) return vec; MGPosition P,Q; double len; double err=error(); //1. Check end points of this loop. Q=start_point(); MGLEPoint t=loop2.closest(Q,len); if(len<=err) vec.append(Q,start_LPoint(),t); Q=end_point(); t=loop2.closest(Q,len); if(len<=err) vec.append(Q,end_LPoint(),t); //2. Check end points of loop2. Q=loop2.start_point(); t=closest(Q,len); if(len<=err) vec.append(Q,t,loop2.start_LPoint()); Q=loop2.end_point(); t=closest(Q,len); if(len<=err) vec.append(Q,t,loop2.end_LPoint()); double errsave=MGTolerance::set_wc_zero(err); //3. Compute normal intersection point. MGComplex::const_pcellItr i=loop2.pcell_begin(), ie=loop2.pcell_end(); for(; i!=ie; i++){ const MGEdge* edg=edge_from_iterator(i); MGLCisect_vector lcvec=isect(edg->trimmed_curve()); int m=lcvec.entries(); for(int j=0; j MGLoop::isect_1D( double f, // Coordinate value int coordinate // Coordinate kind of the data f(from 0). ) const{ std::vector vec; const MGBox& lpbx=box(); if(lpbx[coordinate]<trimmed_curve(); MGCParam_list tlist=crv.isect_1D(f, coordinate); MGCParam_list::Citerator ti=tlist.begin(), te=tlist.end(); for(;ti!=te; ti++){ MGPosition Q=crv.eval(*ti); if(!Plist.in(MGBox(Q,tol),itr)){ Plist.push_back(Q); vec.push_back(MGLEPoint(ei, *ti)); } } } MGTolerance::set_wc_zero(errsave); return vec; } //Compute intersection points of 1D sub curves of the original loop. //Parameter values of intersection points(MGLEPoint's) will be returned. //This is for tessellation and intersection with perimeter boudary edges will //be excluded. std::vector MGLoop::isect_1D_tess( double f, // Coordinate value int coordinate // Coordinate kind of the data f(from 0). ) const{ std::vector vec; const MGBox& lpbx=box(); if(lpbx[coordinate]<surface()); double u0=surf.param_s_u(), u1=surf.param_e_u() ,v0=surf.param_s_v(), v1=surf.param_e_v(); double err=error(); double tol=err*3.; double errsave=MGTolerance::set_wc_zero(err); MGPosition_list Plist; //This is used to avoid the answers of multiple points at a connection. MGPosition_list::iterator itr; MGComplex::const_pcellItr ei=pcell_begin(), ee=pcell_end(); for(; ei!=ee; ei++){ const MGEdge* edg=edge_from_iterator(ei); const MGCurve* crv=edg->base_curve(); const MGStraight* sl=dynamic_cast(crv); if(sl){ MGPosition sluvs=edg->start_point(), sluve=edg->end_point(); if(sluvs[0]==sluve[0]) if(sluvs[0]==u0 || sluvs[0]==u1) continue; if(sluvs[1]==sluve[1]) if(sluvs[1]==v0 || sluvs[1]==v1) continue; }else{ const MGLBRep* lb=dynamic_cast(crv); if(lb){ if(lb->order()==2 && lb->bdim()==2){ MGPosition sluvs=edg->start_point(), sluve=edg->end_point(); if(sluvs[0]==sluve[0]) if(sluvs[0]==u0 || sluvs[0]==u1) continue; if(sluvs[1]==sluve[1]) if(sluvs[1]==v0 || sluvs[1]==v1) continue; } } } const MGInterval& frng=(edg->box())[coordinate]; if(ftrimmed_curve(); MGCParam_list tlist=tcrv.isect_1D(f, coordinate); MGCParam_list::Citerator ti=tlist.begin(), te=tlist.end(); for(;ti!=te; ti++){ MGPosition Q=tcrv.eval(*ti); if(!Plist.in(MGBox(Q,tol),itr)){ Plist.push_back(Q); vec.push_back(MGLEPoint(ei, *ti)); } } } MGTolerance::set_wc_zero(errsave); return vec; } //Compute intersections of this loop's binder edges with f. //If some parameter edges did not have a binder, isect_binder generates them. MGLSPoint_vector MGLoop::isect_binder( const MGFSurface& f )const{ assert(face());//This loop must be a boundary of a face. double error=MGTolerance::wc_zero(); double error2=MGTolerance::line_zero()*.5; MGLSPoint_vector leps; const_pcellItr i=pcell_begin(), ie=pcell_end();//To traverse all the edges. for(; i!=ie; i++){ const MGEdge& pedge=*(edge_from_iterator(i)); //std::cout<number_of_pcells(); for(int i=1; i<=npc; i++){ MGEdge* e=loop2->edge(npc-i); e->free_from_parent(); prepend(e); } }else{ pcellItr i=loop2->pcell_begin(), ie=loop2->pcell_end(); while(i!=ie){ MGEdge* e=edge_from_iterator(i++); e->free_from_parent(); append(e); } } delete loop2; } void MGLoop::join(bool start, std::unique_ptr& loop2){ join(start,loop2.release()); } //Return edge pointer of the last edge. const MGEdge* MGLoop::last_edge() const{ const MGCellNB* cell=last_pcell(); return static_cast(cell); } MGEdge* MGLoop::last_edge(){ MGCellNB* cell=last_pcell(); m_kind=UNDEFINED; return static_cast(cell); } //Reverse the direction of the boundary. //(Coordinate transformation is not performed.) void MGLoop::negate(){ MGBoundary::negate(); m_kind=UNDEFINED; } //Negate the boundary according to the parent cell negation. //That is, //1. Transform the coordinates of the bondary cell. //(This transfromation depends on how the parent cell is transformed //when negate() is invoked. So, the member cells of this boundary //are transformed by negate_transoform of the parent cell.) //2. Reverse the direction of the parameter cells(negate each cell). //3. Reverse the ordering of the parameter cells. //4. Negate the binders. void MGLoop::negate_as_boundary( const MGCellNB* parent ){ MGBoundary::negate_as_boundary(parent); if(m_kind==PERIMITER_LOOP) get_perimeter_num(m_perim_num_s,m_perim_num_e); } //Test if end point of the loop is on perimeter of the surface. //Returned is true when on perimeter, false if not. //When on perimeter, perimeter number of the surface is returned in pid_e. bool MGLoop::on_perimeter_end(int& pid_e,const MGFSurface* surf)const{ const MGSurface* srf=surf->get_surface_pointer(); if(!srf) srf=surface(); if(!srf) return false; MGPosition p=end_point(); double u=p.ref(0), v=p.ref(1); return (srf->on_a_perimeter(u,v,pid_e))!=0; } //Test if start point of the loop is on perimeter of the surface. //Returned is true when on perimeter, false if not. //When on perimeter, perimeter number of the surface is returned in pid_s. bool MGLoop::on_perimeter_start(int& pid_s,const MGFSurface* surf)const{ const MGSurface* srf=0; if(surf) srf=surf->get_surface_pointer(); if(!srf) srf=surface(); if(!srf) return false; MGPosition p=start_point(); double u=p.ref(0), v=p.ref(1); return (srf->on_a_perimeter(u,v,pid_s))!=0; } //Test if all the edges included are on a surface perimeter. bool MGLoop::on_surface_perimeter(const MGFace& face)const{ const_pcellItr i=pcell_begin(), ie=pcell_end();//To traverse all the edges. for(; i!=ie; i++){ const MGEdge& pedge=*(edge_from_iterator(i)); if(pedge.on_surface_perimeter(face)) continue; else return false; } return true; } // Output virtual function. std::ostream& MGLoop::out(std::ostream& ostrm) const{ ostrm<<"<binder_edge(); ostrm<<"Edge"<>"<join(true,e); else append_pcell(e); m_kind=UNDEFINED; } //Return start point of this loop as MGLEPoint. MGLEPoint MGLoop::start_LPoint() const{ double t=0.; const_pcellItr cb=pcell_begin(), ce=pcell_end(); if(cb!=ce){t=edge_from_iterator(cb)->param_s();} return MGLEPoint(cb,t); } //Return start point of this loop as MGPosition. //The point is of parameter space. MGPosition MGLoop::start_point() const{ MGPosition P; if(edge_exist()){ const MGEdge* e=first_edge(); P=e->eval(e->param_s()); } return P; } //Obtain parent surface pointer. const MGSurface* MGLoop::surface()const{ const MGSurface* surf=0; const MGCellNB* cell=star(); if(cell){ const MGGeometry* geo=cell->extent(); if(geo) surf=dynamic_cast(geo); } return surf; } //Test if (u,v) is in, on, or out of curves by obtaining intersetion points //of sl with the curves. The loop has a direction and if this is //inner, inside means outside of the closed curves. //Returned is: // 0:outside(not on the loop) // 1:unknown // 2:inside(not on the loop) // otherwise:on the loop(int(parameter edge id +100))will be returned. //When 1 is returned, try again by changing the sample straight line sl. int MGLoop::in_on_curves( const MGPosition& uv, //Test point const double error[3], //error[0]: Tolerance allowed. Used for the test of on curve. //error[1]: loop's u span length //error[2]: loop's v span length const MGPvector& crvs,//Vector of curves that make loop. //This has the direction as a face boundary, and the in-ness is //determined according to the direcion. const MGStraight& sl) //Sample straight line to test the inclusion. const{ double errsave=MGTolerance::wc_zero(); //Save error. const double& err=error[0]; int n=(int)crvs.size(); double len,lenmin=0.; const MGVector& dir=sl.sl_direction(); const MGCurve *crvSave=0; const MGCurve *crv; MGCCisect isec, isecSave; MGVector difmin; //Compute nearest intersection point from uv to crvs. //If no intersection found, crvSave==0 is kept. MGTolerance::set_wc_zero(err*.5); //Make error smaller. int isave; for(int i=0; iisect(sl); int n_is=list.entries(); for(int j=0; jget_surface_pointer(); if(srf){ MGVector V0=f->eval(uv), V1=f->eval(isecSave.point()); V0-=V1; if(V0%V0<=errsave*errsave){ out=100+isave; //When intersection on a curve. MGTolerance::set_wc_zero(errsave); //Restore original error. return out; } } } MGVector dif(isecSave.point(), uv); MGVector tangen=crvSave->eval(isecSave.param1(),1); MGVector nrmal=dif*tangen; //std::cout<<"nrmal="<