/********************************************************************/ /* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno */ /* All rights reserved. */ /********************************************************************/ #include "MGCLStdAfx.h" #include "mg/CParam_list.h" #include "mg/Position_list.h" #include "mg/CSisect_list.h" #include "mg/SSisect_list.h" #include "mg/Straight.h" #include "mg/SurfCurve.h" #include "mg/Pvector.h" #include "mg/Curve.h" #include "mg/LBRep.h" #include "mg/TrimmedCurve.h" #include "mg/Tolerance.h" #include "topo/Edge.h" #include "topo/Loop.h" #include "topo/LEPoint.h" #include "topo/LPoint.h" #include "topo/Face.h" #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif using namespace std; // //Implements MGFace Class. //MGFace is an instance of MGCell. /////// Constructor /////// //Fundamental constructor. //Construct a face from geometry of manifold dimension 2 //and the boundaries. //The constructor takes the ownership of geo and MGBoundary in boundaries. //boundaries must be loops. MGFace::MGFace( MGSurface* geo, std::vector& boundaries, MGCell* binder ):MGCell(geo, boundaries, binder){ assert(geo->manifold_dimension()==2); } //Conversion constructor from MGFSurface to MGFace. MGFace::MGFace(const MGFSurface& surf) :MGCell(static_cast(surf.get_surface_pointer()->clone())) ,m_box_param(surf.param_range()){ copy_appearance(*(surf.object_pointer())); const MGFace* f=dynamic_cast(&surf); if(!f) return; copy_all_boundaries(*f); copy_binder(*f); } //Construct a face by copying boundaries(only parameter rep of the boundary) //from argument boundaries. MGFace::MGFace( const MGSurface& surf, const std::vector& boundaries ):MGCell(surf){ std::vector::const_iterator i=boundaries.begin(), iend=boundaries.end(); for(;i!=iend; i++){ const MGLoop* loopi=dynamic_cast(*i); if(loopi) append_boundary(loopi->clone_without_binders()); } } //This form is to input a newed surface. The constructor takes the ownership //of the surf. MGFace::MGFace( MGSurface* surf, const std::vector& boundaries ):MGCell(surf){ std::vector::const_iterator i=boundaries.begin(), iend=boundaries.end(); for(;i!=iend; i++){ const MGLoop* loopi=dynamic_cast(*i); if(loopi) append_boundary(loopi->clone_without_binders()); } } //Copy constructor. MGFace::MGFace(const MGFace& face):MGCell(face),m_box_param(face.m_box_param){ copy_all_boundaries(face); copy_binder(face); } //Constructor. MGFace::MGFace(const MGFace& face, bool copy_boundary, bool no_binder) :MGCell(face),m_box_param(face.m_box_param){ if(copy_boundary) copy_all_boundaries(face); if(no_binder) return; copy_binder(face); } /////// operator overload/////// // Faceに平行移動を行ないオブジェクトを生成する。 //Translation of the Face MGFace MGFace::operator+ (const MGVector& v) const{ MGFace face(*this); face+=v; return face; } // Faceに逆方向の平行移動を行ないオブジェクトを生成する。 //Translation of the Face MGFace MGFace::operator- (const MGVector& v) const{ MGFace face(*this); face-=v; return face; } //Faceのスケーリングを行い,Faceを作成する。 //Scaling of the Face by a double. MGFace MGFace::operator* (double s) const{ MGFace face(*this); face*=s; return face; } //Faceのスケーリングを行い,Faceを作成する。 //Scaling of the Face by a double. MGFace operator* (double s, const MGFace& face){ MGFace tface(face); tface*=s; return tface; } // 与えられた変換でFaceの変換を行い,Faceを作成する。 //Transformation of the Face by a matrix. MGFace MGFace::operator* (const MGMatrix& mat) const{ MGFace face(*this); face*=mat; return face; } // 与えられた変換によってトランスフォームをおこないFaceを生成する。 //Transformation of the Face by a MGTransf. MGFace MGFace::operator* (const MGTransf& tr) const{ MGFace face(*this); face*=tr; return face; } //Assignment. //When the leaf object of this and cell2 are not equal, this assignment //does nothing. MGFace& MGFace::operator=(const MGFace& face){ if(this==&face) return *this; set_cell(face); m_box_param=face.m_box_param; return *this; } MGFace& MGFace::operator=(const MGGel& gel2){ const MGFace* gel2_is_this=dynamic_cast(&gel2); if(gel2_is_this) operator=(*gel2_is_this); return *this; } bool MGFace::operator<(const MGGel& gel2)const{ const MGFace* gel2_is_this=dynamic_cast(&gel2); if(gel2_is_this) return operator<(*gel2_is_this); return false; } std::ostream& MGFace::out(std::ostream& ostrm) const{ ostrm<<"<>"<arrow(box(),u,v,data); } //Add a new loop to this face as aboundary. //When the old inner loops that are outside the nloop will be removed from this. //nloop can be inner or outer. void MGFace::add_boundary(MGLoop* nloop){ if(nloop->is_outer_boundary()){ if(hasOuterBoundaryLoop()) erase_boundary(int(0)); } int nlps=number_of_loops(); for(int i=nlps-1; i>=0; i--){ if(!nloop->inside(loop(i)->start_point())) erase_boundary(i); } m_box_param.set_null(); if(nloop->is_outer_boundary()) MGCell::prepend_boundary(nloop); else MGCell::append_boundary(nloop); shrink_base_surface_to_knot(); } //Append new one boundary to boundary vectors. //Returned is the number of boudaries after appending. //bound must be a newed MGLoop, and the ownership is transfered to this. //*** append_boundary does not check validity with other loops //(e.x. already existed loops will be outside the new boudanry bound). //If the validity check is necessary, use add_boudanry(). int MGFace::append_boundary(MGBoundary* bound){ m_box_param.set_null(); return MGCell::append_boundary(bound); } //Obtain binder face pointer. //Null when this does not have binder. MGFace* MGFace::binder_face() const{ MGCellNB* bcell=binder(); return static_cast(bcell); } //Get the clone of this as a MGFace. //If this is MGSurface, it is converted to MGFace. MGFace* MGSurface::clone_as_face()const{ return new MGFace(copy_surface()); } ///Copy and set the binder face. void MGFace::copy_binder(const MGFace& faceOriginal){ if(is_pcell()){ const MGFace* bindr=faceOriginal.binder_face(); if(bindr){ MGFace* fb=new MGFace(*bindr); //Copy binder. set_binder(*fb); } } } //Obtain all the boundary curves(world coordinates representation) //of the face. //That is, all of the outer boundaries and all of the inner boundaries. MGPvector MGFace::face_boundaries()const{ MGPvector crvs=outer_boundary(); int n=number_of_inner_boundaries(),i; for(i=0; i crvsi=inner_boundary(i); crvs.push_back(crvsi); } return crvs; } //Return box of the parameter space of the face. //After trimmed one. const MGBox& MGFace::box_param() const{ if(m_box_param.is_null()) compute_box_param(); return m_box_param; } //Make a clone of the cell. MGFace* MGFace::clone() const{ return new MGFace(*this, true,true); } //Generate a new MGCellBase pointer by newing the original MGCellBase. //This is a proprietry routine of MGComplex copy. //Copy all boundary data, (but does not copy own binder cell relation) //and register boundary binder association of new and old into cmap. MGFace* MGFace::clone(MGCellMap& cmap)const{ MGFace* cell=clone_without_boundaries(); cell->copy_all_boundaries(*this,cmap); cell->copy_box(*this); cell->copy_perror(*this); return cell; } //Make a clone without boundaries of this face. //clone_without_boundaries() does not copy the binder cell relation. MGFace* MGFace::clone_without_boundaries() const{ return new MGFace(*this, false,true); } //Make a clone of this(this is a binder), and set binder and parameter cell //relation between the new binder and the parameter cell f. MGFace* MGFace::clone_binder(const MGCellBase& f) const{ MGFace* bface=new MGFace(*this); f.set_binder(*bface); return bface; } //Compute closest point from a point. //Returned is the parameter value of the face that is closest to point. MGPosition MGFace::closest(const MGPosition& point) const{ const MGSurface* srf=surface(); MGPosition P,P1; double dist,dist1; MGPosition uv; MGVector dif; //(P,uv,dist) will be the colsest pair of the face to point. //uv:parameter value of P, dist:distance between P and point. //First, compute closest candidates on the surface. int n=perp_one(point,uv); MGPvector prmtr=outer_boundary(); if(n==0){P=prmtr[0]->start_point(); uv=MGPosition();} else P=eval(uv); dif=(P-point); dist=dif%dif; //Second, compute closest candidates on the boundaries. // 2.1 Outer boundary. int pnum,i; pnum=(int)prmtr.size(); for(i=0; iclosest(point); P1=prmtr[i]->eval(t); dif=P1-point; dist1=dif%dif; if(dist1 prmtrj=inner_boundary(j); pnum=(int)prmtrj.size(); for(i=0; iclosest(point); P1=prmtrj[i]->eval(t); dif=P1-point; dist1=dif%dif; if(dist1closest_on_boundary(sl); double distance=-1.; MGLEPoint closest; for(int i=0; iclosest_world(sl,closest,distance); } return closest.eval(); } //compute box of the cell in m_box. //Currently this does not compute correct box, compute m_extent box. void MGFace::compute_box() const{ const MGSurface* srf=surface(); if(srf) m_box=srf->box_limitted(box_param()); else set_box_as_null(); } //Compute parameter range box. void MGFace::compute_box_param() const{ if(hasOuterBoundaryLoop()){ const MGLoop* lp=loop(int(0)); m_box_param=lp->box(); }else{ const MGSurface* srf=surface(); if(srf) m_box_param=srf->param_range();//Compute parameter range box. else{ int n=number_of_boundaries(); if(n){ const MGLoop* lp=loop(int(0)); m_box_param=lp->box(); } } } } //set box as null(to set the box as initial) void MGFace::set_box_as_null()const{ MGCell::set_box_as_null(); m_box_param.set_null(); } //Test if directions of parameter curve and world curve of the face boundary //is equal or not. This function can be used to test the pair of //the output of outer_boundary() and outer_boundary_param(), or the pair of //inner_boundary() and inner_boundary_param(). //Return is: //true if equal direction, false if opposite direction. bool MGFace::equal_direction( const MGPvector& wcurves, //output of outer_boundary() or inner_boundary(). const MGPvector& pcurves, //output of outer_boundary_param() or inner_boundary_param(). int i //id of the curve in wcurves and pcurves to test the direction. ) const{ assert(size_t(i)param_s()+wcurves[i]->param_e())*0.5; return (scrv.direction(t1))%(wcurves[i]->direction(t2))>0.; } //Erase i-th loop. //void MGFace::erase_boundary(int i){ // bool is_in=(*(loop(i))).is_inner_boundary(); // MGCell::erase_boundary(i); //} //Evaluate. //Input parameter value is not checked if it is in_range() or not. //Even if it is not in_range(), surface evaluation will be executed. MGVector MGFace::eval(double u, double v, //Face parameter value(u,v) int ndu, int ndv) const//Order of derivative. { const MGSurface* srf=surface(); return srf->eval(u,v,ndu,ndv); } MGVector MGFace::eval(const MGPosition& uv, //Face parameter value(u,v) int ndu, int ndv) const//Order of derivative. { const MGSurface* srf=surface(); return srf->eval(uv,ndu,ndv); } //Get inner_aboundary loops included in the input box. std::vector MGFace::get_inner_boundary_loops( const MGBox& uvbox )const{ std::vector lps; int is; int n=number_of_inner_boundaries(is); if(n==0) return lps; double u0=uvbox[0].low_point(), u1=uvbox[0].high_point(); double v0=uvbox[1].low_point(), v1=uvbox[1].high_point(); for(int i=0; ibox(); const MGInterval& urange=bx[0]; if(urangeu1) continue; const MGInterval& vrange=bx[1]; if(vrangev1) continue; lps.push_back(lpi); } return lps; } //Test if this face has boundary loops or not in the specified box. //If this has one, return true. bool MGFace::hasLoop(const MGBox& uvbox) const{ int n=number_of_loops(); if(n==0) return false; double u0=uvbox[0].low_point(), u1=uvbox[0].high_point(); double v0=uvbox[1].low_point(), v1=uvbox[1].high_point(); for(int i=0; ibox(); const MGInterval& urange=bx[0]; const MGInterval& vrange=bx[1]; if(urange>=u0 && urange<=u1 && vrange>=v0 && vrange<=v1) return true; } return false; } //Test if this face has the outer boundary loop instead of perimeter boundary //loops. If this has the outer boundary loop and has not perimeter boundary //loops, return true. bool MGFace::hasOuterBoundaryLoop() const{ int n=number_of_boundaries(); if(!n) return false; if(loop(int(0))->is_outer_boundary()) return true; return false; } //Test if this face has perimeter boundary loops or not. //If this has one, return true. bool MGFace::hasPerimeterBoundaryLoop() const{ int n=number_of_boundaries(); if(!n) return false; if(loop(int(0))->is_perimeter_boundary()) return true; return false; } //Obtain i-th inner_boundary curves(world coordinates representation) //of the face. Let the output of inner_boundary(i) be wcurves and //of inner_boundary_param(i) be pcurves, then wcurves[j] corresponds //to pcurves[j] one to one. Number of inner_boundary can be obtained //by the function number_of_inner_boundaries(). MGPvector MGFace::inner_boundary(int i)const{ int start; int nb=number_of_inner_boundaries(start); MGPvector crvs; if(nb && (i crvsj=lp->curves_world(); crvs.push_back(crvsj); } return crvs; } //Obtain i-th inner_boundary curves(parameter space representation) //of the face. Let the output of inner_boundary(i) be wcurves and //of inner_boundary_param(i) be pcurves, then wcurves[j] corresponds //to pcurves[j] one to one. Number of inner_boundary can be obtained //by the function number_of_inner_boundaries(). MGPvector MGFace::inner_boundary_param(int i)const{ int start; MGPvector crvs; int nb=number_of_inner_boundaries(start); if(nb && (ipcell_begin(),ie=lp->pcell_end(); for(; i!=ie; i++){ const MGEdge* edg=edge_from_iterator(i); crvs.push_back(new MGTrimmedCurve(edg->trimmed_curve())); } } return crvs; } //Test if (u,v) is inside inner boundary. inside means not on the //boundary and not included inside the face. //If true is returned, the id of m_boundaies is returned. //Function's return value is: // 0:outside of all the inner loops(not on the loop) // 1:unknown // 2:inside an inner loop(not on the loop), and the loop id is returned in id. // otherwise:on the loop(int(MGEdge* of parameter edge))will be returned, // and the loop id is returned in id. int MGFace::inside_inner_boundary( const MGPosition& uv, int& id )const{ int start; int n=number_of_inner_boundaries(start); for(int i=0; iinside(uv); if(!in_the_loop) return 2; if(in_the_loop>2) return in_the_loop; } return 0; } //Test if (u,v) is inside the outer boundary. //Inside the outer boundary means that inside outer_boudary_param() or not. //***Caution*** //(1)This must not be used for faces that do not have perimeter or outer boundary //loop. //(2)inside_outer_boundary does not check about the inner loops. // //Function's return value is: // 0:outside the outer boundary(not on a loop) // 1:unknown // 2:inside the outer boundary(not on a loop) // otherwise:on the outer boundary loop(including perimeter loops) int MGFace::inside_outer_boundary( const MGPosition& uv )const{ std::vector loops; extract_loops(loops); return inside_outer_loop(uv,loops,surface()); } //Test if parameter value (u,v) is in the range of the face parameter. bool MGFace::in_range(double u, double v)const{ return in_range(MGPosition(u,v)); } bool MGFace::in_range(const MGPosition& uv)const{ if(box_param()<2) return true; else if(in==2) return false; else if(no_outer_boundaries()) return true; else return inside_outer_boundary(uv)>=2; } } //Test if (u,v) is inside the face. //Function's return value is: // 0:outside the face. // 1:unknown. // 2:inside the face, not on a boundary. // <0:(u,v) is on an inner boundary, and abs(return code) is the loop id. // 4:(u,v) is on the outer boundary(including perimeter loops). // >=10: (u,v) is on a perimeter, (10+perimeter number) will be returned. int MGFace::in_range_with_on( const MGPosition& uv )const{ if(box_param()<2) return -int(loop_id); else if(in==2) return 0; if(no_outer_boundaries()){ const MGSurface* srf=surface(); if(srf) return srf->in_range_with_on(uv); else return 2; } in=inside_outer_boundary(uv); if(in>2) return 4; else return in; } //Obtain i-th boundary loop of the face. MGLoop* MGFace::loop(int i){ MGBoundary* bnd=boundary(i); return static_cast(bnd); } const MGLoop* MGFace::loop(int i)const{ const MGBoundary* bnd=boundary(i); return static_cast(bnd); } MGLoop* MGFace::loop(iterator i){ return static_cast(*i); } const MGLoop* MGFace::loop(const_iterator i)const{ return static_cast(*i); } //Make a binder cell of this parameter cell. //Returned is the binder pointer generated by new. //The binder has no geometry, only has binder and parameter cell relationship. MGCellNB* MGFace::make_binder() const{ MGCellNB* cell=binder(); if(cell) return cell; MGFace* bface=new MGFace(); set_binder(*bface); return bface; } //Make this cell's binder cell's extent expression. //Returned is a MGGeometry pointer generated by new. //When this cell does not have star cell, null pointer will be returned. //make_binder_extent() only makes the expression, and does nothing to //the topology structure. MGGeometry* MGFace::make_binder_extent() const{ //Currently this does nothing since class Solid is not supported. return 0; } //Make sure that this has an extent expression. //When this did not have an extent, make the extent from the partner //member's parameter expression and the star cell. //This must be a binder cell that has partner members that are //boundaries. When this is not the case or this had an extent already, //it does nothing. void MGFace::make_extent() const{ if(extent()) return; if(!is_bcell()) return; // const MGCellBase* partner=m_partners[0]; // const MGFace* pface=dynamic_cast(partner); return; //Currently this does nothing since class Solid is not supported. /* assert(pface->solid()); assert(pface->solid()->xxxxxxx()); MGCurve* bcrv; //If binder edge did not have curve representation. bcrv=new MGSurfCurve(*srf,pedge->trimmed_curve()); MGEdge* thisE=const_cast(this); thisE->set_extent(bcrv); */ } //Obtain the i-th member partner face. const MGFace* MGFace::member_partner_face(int i)const{ return static_cast(member_partner(i)); } //Negate the face. void MGFace::negate(){ MGCellNB::negate(); if(!m_box_param.is_null()) m_box_param=MGBox(2,m_box_param,1,0); //Exchange parameter range of(u,v). } //Test if no outer boundary except the surface perimeters. //That is, test if the following two conditions are satisfied: // 1. no perimeter boundaries. // 2. no outer boundary. bool MGFace::no_outer_boundaries()const{ int n=number_of_boundaries(); if(!n) return true; const MGLoop* lp_first=loop(int(0)); if(lp_first->is_perimeter_boundary()) return false; if(lp_first->is_outer_boundary()) return false; return true; } //Get number of inner boundaries. //Returned i is the id of the first inner boundary loop if inner boundaries //exist. int MGFace::number_of_inner_boundaries(int& i)const{ int n=number_of_boundaries(); i=0; while(iis_perimeter_boundary()) i++; while(iis_outer_boundary()) i++; int j=i; while(jis_inner_boundary()) j++; return j-i; } //Compute number of active loops. int MGFace::number_of_loops()const{ int n=number_of_boundaries(); int i=0; while(iis_perimeter_boundary()) i++; while(iis_outer_boundary()) i++; while(iis_inner_boundary()) i++; return i; } //Get number of perimeter boundary loop. int MGFace::number_of_perimeter_boundaries()const{ int n=number_of_boundaries(); int i=0; while(iis_perimeter_boundary()) i++; return i; } //Test if a point P is on the face. //Returned is true if the point P is on the face. //false if P was not on the face. bool MGFace::on(const MGPosition& P, MGPosition& uv //Parameter value of the face is returrned. //Even if P is not on the face, nearest point //parameter value will be returned. ) const{ uv=closest(P); return P==eval(uv); } //Test if input (u,v) is parameter value on a perimeter of the base surface. //If u or v is on a perimeter, they will be updated to the perimeter value. bool MGFace::on_a_perimeter( double& u, double& v, //Surface parameter (u,v) int& perim_num //if function returns true, //the perimete number is output. )const{ return surface()->on_a_perimeter(u,v,perim_num); } //Obtain parameter value of the face whose world coordinates are P. MGPosition MGFace::param(const MGPosition& P)const{ const MGSurface* srf=surface(); MGPosition uv=srf->param(P); return range(uv); } // Return ending parameter value. double MGFace::param_e_u()const{ const MGBox& uvbox=box_param(); return uvbox[0].high_point(); } double MGFace::param_e_v()const{ const MGBox& uvbox=box_param(); return uvbox[1].high_point(); } // Return starting parameter value of the base surface. double MGFace::param_s_u()const{ const MGBox& uvbox=box_param(); return uvbox[0].low_point(); } double MGFace::param_s_v()const{ const MGBox& uvbox=box_param(); return uvbox[1].low_point(); } //Return the foot of the perpendicular straight line from P. //Computation is done from the guess parameter value. //Function's return value is whether point is obtained(true) or not(false). bool MGFace::perp_guess( const MGPosition& P, //Point const MGPosition& uvguess, // guess parameter value of the shell MGPosition& uv // Parameter value will be returned. ) const{ const MGBox& pbox=box_param(); //Parameter range of the face. MGPosition uv0(pbox[0].low_point(), pbox[1].low_point()); MGPosition uv1(pbox[0].high_point(), pbox[1].high_point()); bool obtained=false; if(surface()->perp_guess(uv0,uv1,P,uvguess,uv)) obtained=in_range(uv); return obtained; } //Compute perpendicular points of a curve and the face, given //guess starting paramter values. //Function's return value is: // perp_guess=true if perpendicular points obtained, // perp_guess=false if perpendicular points not obtained, bool MGFace::perp_guess( const MGCurve& curve, //curve. const MGPosition& uvguess, //Guess parameter value of the face. double tguess, //Guess parameter value of the curve. MGPosition& uv, //perpendicular point's parameter values of the shell double& t //will be output. ) const{ const MGBox& pbox=box_param(); //Parameter range of the face. MGPosition uv0(pbox[0].low_point(), pbox[1].low_point()); MGPosition uv1(pbox[0].high_point(), pbox[1].high_point()); bool obtained=false; MGPosition tuvguess(3), tuv; tuvguess(0)=tguess;tuvguess(1)=uvguess[0];tuvguess(2)=uvguess[1]; if(surface()->perp_guess(uv0,uv1,curve,1.,-1.,tuvguess,tuv)){ t=tuv[0]; uv=MGPosition(2,tuv,0,1); obtained=in_range(uv); } return obtained; } //指定点から最も近い、垂線の足とパラメータ値を返す。 //Return the foot of the perpendicular straight line from p that is //nearest to point p. // Function's return value is whether point is obtained(1) or not(0) int MGFace::perp_point ( const MGPosition& p, // 指定点(point) MGPosition& uv, //Parameter value of the surface will be returned. const MGPosition* uvguess // guess parameter value of surface ) const { MGPosition uv0(1.,1.), uv1(0.,0.); if(uvguess) return perp_guess(p,*uvguess,uv); else return perp_one(p,uv); } //Compute perpendicular points on the face from a point P((x,y,z)). //MGPosition uv in the MGPosition_list is: //uv(0): u parameter, and uv(1): v parameter of the face. //Generally number of uv are more than one. MGPosition_list MGFace::perps(const MGPosition& P) const{ MGPosition_list uvs; const MGSurface* srf=surface(); if(!srf) return uvs; uvs=srf->perps(P); remove_outside_param(uvs); return uvs; } //Compute the parameter value of the closest point from the straight to //this object. //sl is the eye projection line whose direction is from yon to hither, and if //sl had multiple intersection points, The closest point to the eye will be selected. MGPosition MGFace::pick_closest(const MGStraight& sl)const{ const MGSurface* srf=surface(); if(no_outer_boundaries()) return srf->pick_closest(sl); MGCSisect_list ises=srf->isectSl(sl); int n=ises.size(); double t; MGPosition uv; MGCSisect_list::CSiterator is=ises.begin(), ie=ises.end(); for(; is!=ie; is++){ const MGPosition& uv2=(*is).param_surface(); if(in_range(uv2)){ double t2=(*is).param_curve(); if(uv.is_null()){ t=t2; uv=uv2; }else{ if(t2>t){ t=t2; uv=uv2; } } } } if(!uv.is_null()) return uv; //Second, compute closest candidates on the boundaries. return closest_on_boundary(sl); } //Dedicated function of range. //Will check if point (u,v) is inside inner boundary or not. //If inside an inner boundary, obtain the closest point to the boundary. MGPosition MGFace::range_check_inner_boundary( const MGPosition& uv )const{ int loop_id; double len; int in=inside_inner_boundary(uv,loop_id); if(in>=2){ const MGLoop* cloop=loop(loop_id); MGLEPoint lp=cloop->closest(uv,len); return cloop->eval(lp); }else{ return uv; } } //Round the input parameter (u,v) of the face to the nearest point of //the face parameter range. //**********This algorithm should be improved later.********** //(Especially about using MGClosest_to_curves) MGPosition MGFace::range(const MGPosition& uv) const{ const MGSurface* srf=surface(); if(!srf) return uv; double errsave=MGTolerance::wc_zero(); MGTolerance::set_wc_zero(parameter_error()); MGPosition uv_new; if(!srf->in_range(uv)){ if(no_outer_boundaries()) uv_new=srf->range(uv); else uv_new=MGClosest_to_curves(uv,outer_boundary_param()); goto end_process; } //Now uv is in the parameter range of surface. if(!number_of_boundaries()){ uv_new=uv; //When no boundaries. goto end_process; } if(no_outer_boundaries()){ uv_new=range_check_inner_boundary(uv); goto end_process; } //When there exists perimeter boundary. if(inside_outer_boundary(uv)) uv_new=range_check_inner_boundary(uv); else uv_new=MGClosest_to_curves(uv,outer_boundary_param()); end_process: MGTolerance::set_wc_zero(errsave); return uv_new; } //Test if this face has an inactive loop. //If this has one, return true. bool MGFace::hasInactiveLoop()const{ int n=number_of_boundaries(); for(int i=n-1; i>=0; i--){ if(loop(i)->is_inactive(this)) return true; } return false; } //Remove inactive loops from this face. void MGFace::remove_inactive_loops(){ int n=number_of_boundaries(); for(int i=n-1; i>=0; i--){ if(loop(i)->is_inactive(this)) erase_boundary(i); } } //Remove parameter uv from uvs that is outside face parameter range. void MGFace::remove_outside_param(MGPosition_list& uvs)const{ MGPosition_list::iterator i=uvs.begin(), iend=uvs.end(), i1; while(i!=iend){ i1=i; i1++; if(!in_range(*i)) uvs.removeAt(i); i=i1; } } //Get surface pointer. MGSurface* MGFace::surface(){ MGGeometry* cell=extent(); return dynamic_cast(cell); } const MGSurface* MGFace::surface() const{ const MGGeometry* cell=extent(); return dynamic_cast(cell); } //Obtain the closest point from point uv to vector of curves. //MGClosest_to_curves does not change wc_zero, and so calling program of //MGClosest_to_curves should change it if necessary. MGPosition MGClosest_to_curves( const MGPosition& uv, //Point. const MGPvector& curves //vector of curves. ){ int n=(int)curves.size(); if(n==0) return uv; double t=curves[0]->closest(uv); MGPosition uv_min=curves[0]->eval(t), uv1; MGVector dif=uv-uv_min; double lenmin=dif%dif, len1; for(int i=1; iclosest(uv); uv1=curves[i]->eval(t); dif=uv-uv1; len1=dif%dif; if(len1