/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004-2016 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __VCGLIB_SPATIAL_ITERATORS #define __VCGLIB_SPATIAL_ITERATORS #include #include #include #include #include #include #include #include #include namespace vcg{ template class RayIterator { public: typedef typename Spatial_Idexing::ScalarType ScalarType; typedef typename vcg::Ray3 RayType; typedef typename Spatial_Idexing::Box3x IndexingBoxType; protected: typedef typename Spatial_Idexing::ObjType ObjType; typedef typename vcg::Point3 CoordType; typedef typename Spatial_Idexing::CellIterator CellIterator; ScalarType max_dist; ///control right bonding current cell index (only on initialization) void _ControlLimits() { for (int i=0;i<3;i++) { vcg::Point3i dim=Si.siz; if (CurrentCell.V(i)<0) CurrentCell.V(i) = 0; else if (CurrentCell.V(i)>=dim.V(i)) CurrentCell.V(i)=dim.V(i)-1; } } ///find initial line parameters void _FindLinePar() { /* Punti goal */ ///da verificare se vanno oltre ai limiti vcg::Point3i ip; Si.PToIP(start,ip); Si.IPiToPf(ip,goal); for (int i=0;i<3;i++) if(r.Direction().V(i)>0.0) goal.V(i)+=Si.voxel.V(i); ScalarType gx=goal.X(); ScalarType gy=goal.Y(); ScalarType gz=goal.Z(); dist=(r.Origin()-goal).Norm(); const float LocalMaxScalar = (std::numeric_limits::max)(); const float EPS = std::numeric_limits::min(); /* Parametri della linea */ ScalarType tx,ty,tz; if( fabs(r.Direction().X())>EPS ) tx = (gx-r.Origin().X())/r.Direction().X(); else tx =LocalMaxScalar; if( fabs(r.Direction().Y())>EPS) ty = (gy-r.Origin().Y())/r.Direction().Y(); else ty =LocalMaxScalar; if( fabs(r.Direction().Z())>EPS ) tz = (gz-r.Origin().Z())/r.Direction().Z(); else tz =LocalMaxScalar; t=CoordType(tx,ty,tz); } bool _controlEnd() { return (((CurrentCell.X()<0)||(CurrentCell.Y()<0)||(CurrentCell.Z()<0))|| ((CurrentCell.X()>=Si.siz.X())||(CurrentCell.Y()>=Si.siz.Y())||(CurrentCell.Z()>=Si.siz.Z()))); } void _NextCell() { assert(!end); vcg::Box3 bb_current; Si.IPiToPf(CurrentCell,bb_current.min); Si.IPiToPf(CurrentCell+vcg::Point3i(1,1,1),bb_current.max); CoordType inters; IntersectionRayBox(bb_current,r,inters); ScalarType testmax_dist=(inters-r.Origin()).Norm(); if (testmax_dist>max_dist) end=true; else { if( t.X()(Si.bbox,r,start))){ end=true; return; } Si.PToIP(start,CurrentCell); _ControlLimits(); _FindLinePar(); //go to first intersection while ((!End())&& Refresh()) _NextCell(); } bool End() {return end;} ///refresh current cell intersection , return false if there are ///at lest 1 intersection bool Refresh() { //Elems.clear(); typename Spatial_Idexing::CellIterator first,last,l; ///take first, last iterators to elements in the cell Si.Grid(CurrentCell.X(),CurrentCell.Y(),CurrentCell.Z(),first,last); for(l=first;l!=last;++l) { ObjType* elem=&(*(*l)); ScalarType t; CoordType Int; if((!elem->IsD())&&(!tm.IsMarked(elem))&&(int_funct((**l),r,t))&&(t<=max_dist)) { Int=r.Origin()+r.Direction()*t; Elems.push_back(Entry_Type(elem,t,Int)); tm.Mark(elem); } } ////then control if there are more than 1 element std::sort(Elems.begin(),Elems.end()); CurrentElem=Elems.rbegin(); return((Elems.size()==0)||(Dist()>dist)); } void operator ++() { if (!Elems.empty()) Elems.pop_back(); CurrentElem = Elems.rbegin(); if (Dist()>dist) { if (!End()) { _NextCell(); while ((!End())&&Refresh()) _NextCell(); } } } ObjType &operator *(){return *((*CurrentElem).elem);} CoordType IntPoint() {return ((*CurrentElem).intersection);} ScalarType Dist() { if (Elems.size()>0) return ((*CurrentElem).dist); else return ((ScalarType)FLT_MAX); } ///set the current spatial indexing structure used void SetIndexStructure(Spatial_Idexing &_Si) {Si=_Si;} protected: ///structure that mantain for the current cell pre-calculated data struct Entry_Type { public: Entry_Type(ObjType* _elem,ScalarType _dist,CoordType _intersection) { elem=_elem; dist=_dist; intersection=_intersection; } inline bool operator < ( const Entry_Type & l ) const{return (dist > l.dist); } ObjType* elem; ScalarType dist; CoordType intersection; }; RayType r; //ray to find intersections Spatial_Idexing &Si; //reference to spatial index algorithm bool end; //true if the scan is terminated INTFUNCTOR &int_funct; TMARKER tm; std::vector Elems; //element loaded from curren cell typedef typename std::vector::reverse_iterator ElemIterator; ElemIterator CurrentElem; //iterator to current element vcg::Point3i CurrentCell; //current cell //used for raterization CoordType start; CoordType goal; ScalarType dist; CoordType t; }; template class ClosestIterator { typedef typename Spatial_Idexing::ObjType ObjType; typedef typename Spatial_Idexing::ScalarType ScalarType; typedef typename vcg::Point3 CoordType; typedef typename Spatial_Idexing::CellIterator CellIterator; ///control the end of scanning bool _EndGrid() { if ((explored.min==vcg::Point3i(0,0,0))&&(explored.max==Si.siz)) end =true; return end; } void _UpdateRadius() { if (radius>=max_dist) end=true; radius+=step_size; //control bounds if (radius>max_dist) radius=max_dist; } ///add cell to the curren set of explored cells bool _NextShell() { //then expand the box explored=to_explore; _UpdateRadius(); Box3 b3d(p,radius); Si.BoxToIBox(b3d,to_explore); Box3i ibox(Point3i(0,0,0),Si.siz-Point3i(1,1,1)); to_explore.Intersect(ibox); if (!to_explore.IsNull()) { assert(!( to_explore.min.X()<0 || to_explore.max.X()>=Si.siz[0] || to_explore.min.Y()<0 || to_explore.max.Y()>=Si.siz[1] || to_explore.min.Z()<0 || to_explore.max.Z()>=Si.siz[2] )); return true; } return false; } public: ///contructor ClosestIterator(Spatial_Idexing &_Si,DISTFUNCTOR _dist_funct):Si(_Si),dist_funct(_dist_funct){} ///set the current spatial indexing structure used void SetIndexStructure(Spatial_Idexing &_Si) {Si=_Si;} void SetMarker(TMARKER _tm) { tm=_tm; } ///initialize the Iterator void Init(CoordType _p,const ScalarType &_max_dist) { explored.SetNull(); to_explore.SetNull(); p=_p; max_dist=_max_dist; Elems.clear(); end=false; tm.UnMarkAll(); //step_size=Si.voxel.X(); step_size=Si.voxel.Norm(); radius=0; ///inflate the bbox until find a valid bbox while ((!_NextShell())&&(!End())) {} while ((!End())&& Refresh()&&(!_EndGrid())) _NextShell(); } //return true if the scan is complete bool End() {return end;} ///refresh Object found also considering current shere radius, //and object comes from previos that are already in the stack //return false if no elements find bool Refresh() { int ix,iy,iz; for( iz = to_explore.min.Z();iz <= to_explore.max.Z(); ++iz) for(iy =to_explore.min.Y(); iy <=to_explore.max.Y(); ++iy) for(ix =to_explore.min.X(); ix <= to_explore.max.X();++ix) { // this test is to avoid to re-process already analyzed cells. if((explored.IsNull())|| (ixexplored.max[0] || iyexplored.max[1] || izexplored.max[2] )) { typename Spatial_Idexing::CellIterator first,last,l; Si.Grid(ix,iy,iz,first,last); for(l=first;l!=last;++l) { ObjType *elem=&(**l); if (!tm.IsMarked(elem)) { CoordType nearest; ScalarType dist=max_dist; if (dist_funct((**l),p,dist,nearest)) Elems.push_back(Entry_Type(elem,fabs(dist),nearest)); tm.Mark(elem); } } } } ////sort the elements in Elems and take a iterator to the last one std::sort(Elems.begin(),Elems.end()); CurrentElem=Elems.rbegin(); return((Elems.size()==0)||(Dist()>radius)); } bool ToUpdate() {return ((Elems.size()==0)||(Dist()>radius));} void operator ++() { if (!Elems.empty()) Elems.pop_back(); CurrentElem = Elems.rbegin(); if ((!End())&& ToUpdate()) do{_NextShell();} while (Refresh()&&(!_EndGrid())); } ObjType &operator *(){return *((*CurrentElem).elem);} //return distance of the element form the point if no element //are in the vector then return max dinstance ScalarType Dist() { if (Elems.size()>0) return ((*CurrentElem).dist); else return ((ScalarType)FLT_MAX); } CoordType NearestPoint() {return ((*CurrentElem).intersection);} protected: ///structure that mantain for the current cell pre-calculated data struct Entry_Type { public: Entry_Type(ObjType* _elem,ScalarType _dist,CoordType _intersection) { elem=_elem; dist=_dist; intersection=_intersection; } inline bool operator < ( const Entry_Type & l ) const{return (dist > l.dist); } inline bool operator == ( const Entry_Type & l ) const{return (elem == l.elem); } ObjType* elem; ScalarType dist; CoordType intersection; }; CoordType p; //initial point Spatial_Idexing &Si; //reference to spatial index algorithm bool end; //true if the scan is terminated ScalarType max_dist; //max distance when the scan terminate vcg::Box3i explored; //current bounding box explored vcg::Box3i to_explore; //current bounding box explored ScalarType radius; //curret radius for sphere expansion ScalarType step_size; //radius step std::vector Elems; //element loaded from the current sphere DISTFUNCTOR dist_funct; TMARKER tm; typedef typename std::vector::reverse_iterator ElemIterator; ElemIterator CurrentElem; //iterator to current element }; } #endif