| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242 |
- // This file is part of libigl, a simple c++ geometry processing library.
- //
- // Copyright (C) 2018 Zhongshi Jiang <[email protected]>
- //
- // This Source Code Form is subject to the terms of the Mozilla Public License
- // v. 2.0. If a copy of the MPL was not distributed with this file, You can
- // obtain one at http://mozilla.org/MPL/2.0/.
- #include "exact_geodesic.h"
- //Copyright (C) 2008 Danil Kirsanov, MIT License
- //Code from https://code.google.com/archive/p/geodesic/
- // Compiled into a single file by Zhongshi Jiang
- #include "PI.h"
- #include <algorithm>
- #include "IGL_ASSERT.h"
- #include <cmath>
- #include <cstddef>
- #include <ctime>
- #include <fstream>
- #include <iostream>
- #include <set>
- #include <vector>
- #include <memory>
- #include <cmath>
- namespace igl{
- namespace geodesic{
- //#include "geodesic_constants_and_simple_functions.h"
- //double const GEODESIC_INF = std::numeric_limits<double>::max();
- double const GEODESIC_INF = 1e100;
- //in order to avoid numerical problems with "infinitely small" intervals,
- //we drop all the intervals smaller than SMALLEST_INTERVAL_RATIO*edge_length
- double const SMALLEST_INTERVAL_RATIO = 1e-6;
- //double const SMALL_EPSILON = 1e-10;
- inline double cos_from_edges(double const a, //compute the cosine of the angle given the lengths of the edges
- double const b,
- double const c)
- {
- assert(a>1e-50);
- assert(b>1e-50);
- assert(c>1e-50);
- double result = (b*b + c*c - a*a)/(2.0*b*c);
- result = std::max(result, -1.0);
- return std::min(result, 1.0);
- }
- inline double angle_from_edges(double const a, //compute the cosine of the angle given the lengths of the edges
- double const b,
- double const c)
- {
- return acos(cos_from_edges(a,b,c));
- }
- template<class Points, class Faces>
- inline bool read_mesh_from_file(char* filename,
- Points& points,
- Faces& faces)
- {
- std::ifstream file(filename);
- assert(file.is_open());
- if(!file.is_open()) return false;
- unsigned num_points;
- file >> num_points;
- assert(num_points>=3);
- unsigned num_faces;
- file >> num_faces;
- points.resize(num_points*3);
- for(typename Points::iterator i=points.begin(); i!=points.end(); ++i)
- {
- file >> *i;
- }
- faces.resize(num_faces*3);
- for(typename Faces::iterator i=faces.begin(); i!=faces.end(); ++i)
- {
- file >> *i;
- }
- file.close();
- return true;
- }
- // #include "geodesic_memory"
- template<class T> //quickly allocates multiple elements of a given type; no deallocation
- class SimlpeMemoryAllocator
- {
- public:
- typedef T* pointer;
- SimlpeMemoryAllocator(unsigned block_size = 0,
- unsigned max_number_of_blocks = 0)
- {
- reset(block_size,
- max_number_of_blocks);
- };
- ~SimlpeMemoryAllocator(){};
- void reset(unsigned block_size,
- unsigned max_number_of_blocks)
- {
- m_block_size = block_size;
- m_max_number_of_blocks = max_number_of_blocks;
- m_current_position = 0;
- m_storage.reserve(max_number_of_blocks);
- m_storage.resize(1);
- m_storage[0].resize(block_size);
- };
- pointer allocate(unsigned const n) //allocate n units
- {
- assert(n < m_block_size);
- if(m_current_position + n >= m_block_size)
- {
- m_storage.push_back( std::vector<T>() );
- m_storage.back().resize(m_block_size);
- m_current_position = 0;
- }
- pointer result = & m_storage.back()[m_current_position];
- m_current_position += n;
- return result;
- };
- private:
- std::vector<std::vector<T> > m_storage;
- unsigned m_block_size; //size of a single block
- unsigned m_max_number_of_blocks; //maximum allowed number of blocks
- unsigned m_current_position; //first unused element inside the current block
- };
- template<class T> //quickly allocates and deallocates single elements of a given type
- class MemoryAllocator
- {
- public:
- typedef T* pointer;
- MemoryAllocator(unsigned block_size = 1024,
- unsigned max_number_of_blocks = 1024)
- {
- reset(block_size,
- max_number_of_blocks);
- };
- ~MemoryAllocator(){};
- void clear()
- {
- reset(m_block_size,
- m_max_number_of_blocks);
- }
- void reset(unsigned block_size,
- unsigned max_number_of_blocks)
- {
- m_block_size = block_size;
- m_max_number_of_blocks = max_number_of_blocks;
- assert(m_block_size > 0);
- assert(m_max_number_of_blocks > 0);
- m_current_position = 0;
- m_storage.reserve(max_number_of_blocks);
- m_storage.resize(1);
- m_storage[0].resize(block_size);
- m_deleted.clear();
- m_deleted.reserve(2*block_size);
- };
- pointer allocate() //allocates single unit of memory
- {
- pointer result;
- if(m_deleted.empty())
- {
- if(m_current_position + 1 >= m_block_size)
- {
- m_storage.push_back( std::vector<T>() );
- m_storage.back().resize(m_block_size);
- m_current_position = 0;
- }
- result = & m_storage.back()[m_current_position];
- ++m_current_position;
- }
- else
- {
- result = m_deleted.back();
- m_deleted.pop_back();
- }
- return result;
- };
- void deallocate(pointer p) //allocate n units
- {
- if(m_deleted.size() < m_deleted.capacity())
- {
- m_deleted.push_back(p);
- }
- };
- private:
- std::vector<std::vector<T> > m_storage;
- unsigned m_block_size; //size of a single block
- unsigned m_max_number_of_blocks; //maximum allowed number of blocks
- unsigned m_current_position; //first unused element inside the current block
- std::vector<pointer> m_deleted; //pointers to deleted elemets
- };
- class OutputBuffer
- {
- public:
- OutputBuffer():
- m_num_bytes(0)
- {}
- void clear()
- {
- m_num_bytes = 0;
- m_buffer = std::shared_ptr<double>();
- }
- template<class T>
- T* allocate(unsigned n)
- {
- double wanted = n*sizeof(T);
- if(wanted > m_num_bytes)
- {
- unsigned new_size = (unsigned) std::ceil(wanted / (double)sizeof(double));
- m_buffer = std::shared_ptr<double>(new double[new_size]);
- m_num_bytes = new_size*sizeof(double);
- }
- return (T*)m_buffer.get();
- }
- template <class T>
- T* get()
- {
- return (T*)m_buffer.get();
- }
- template<class T>
- unsigned capacity()
- {
- return (unsigned)std::floor((double)m_num_bytes/(double)sizeof(T));
- };
- private:
- std::shared_ptr<double> m_buffer;
- unsigned m_num_bytes;
- };
- class Vertex;
- class Edge;
- class Face;
- class Mesh;
- class MeshElementBase;
- typedef Vertex* vertex_pointer;
- typedef Edge* edge_pointer;
- typedef Face* face_pointer;
- typedef Mesh* mesh_pointer;
- typedef MeshElementBase* base_pointer;
- template <class Data> //simple vector that stores info about mesh references
- class SimpleVector //for efficiency, it uses an outside memory allocator
- {
- public:
- SimpleVector():
- m_size(0),
- m_begin(NULL)
- {};
- typedef Data* iterator;
- unsigned size(){return m_size;};
- iterator begin(){return m_begin;};
- iterator end(){return m_begin + m_size;};
- template<class DataPointer>
- void set_allocation(DataPointer begin, unsigned size)
- {
- assert(begin != NULL || size == 0);
- m_size = size;
- m_begin = (iterator)begin;
- }
- Data& operator[](unsigned i)
- {
- assert(i < m_size);
- return *(m_begin + i);
- }
- void clear()
- {
- m_size = 0;
- m_begin = NULL;
- }
- private:
- unsigned m_size;
- Data* m_begin;
- };
- enum PointType
- {
- VERTEX,
- EDGE,
- FACE,
- UNDEFINED_POINT
- };
- class MeshElementBase //prototype of vertices, edges and faces
- {
- public:
- typedef SimpleVector<vertex_pointer> vertex_pointer_vector;
- typedef SimpleVector<edge_pointer> edge_pointer_vector;
- typedef SimpleVector<face_pointer> face_pointer_vector;
- MeshElementBase():
- m_id(0),
- m_type(UNDEFINED_POINT)
- {};
- vertex_pointer_vector& adjacent_vertices(){return m_adjacent_vertices;};
- edge_pointer_vector& adjacent_edges(){return m_adjacent_edges;};
- face_pointer_vector& adjacent_faces(){return m_adjacent_faces;};
- unsigned& id(){return m_id;};
- PointType type(){return m_type;};
- protected:
- vertex_pointer_vector m_adjacent_vertices; //list of the adjacent vertices
- edge_pointer_vector m_adjacent_edges; //list of the adjacent edges
- face_pointer_vector m_adjacent_faces; //list of the adjacent faces
- unsigned m_id; //unique id
- PointType m_type; //vertex, edge or face
- };
- class Point3D //point in 3D and corresponding operations
- {
- public:
- Point3D(){};
- Point3D(Point3D* p)
- {
- x() = p->x();
- y() = p->y();
- z() = p->z();
- };
- double* xyz(){return m_coordinates;};
- double& x(){return *m_coordinates;};
- double& y(){return *(m_coordinates+1);};
- double& z(){return *(m_coordinates+2);};
- void set(double new_x, double new_y, double new_z)
- {
- x() = new_x;
- y() = new_y;
- z() = new_z;
- }
- void set(double* data)
- {
- x() = *data;
- y() = *(data+1);
- z() = *(data+2);
- }
- double distance(double* v)
- {
- double dx = m_coordinates[0] - v[0];
- double dy = m_coordinates[1] - v[1];
- double dz = m_coordinates[2] - v[2];
- return sqrt(dx*dx + dy*dy + dz*dz);
- };
- double distance(Point3D* v)
- {
- return distance(v->xyz());
- };
- void add(Point3D* v)
- {
- x() += v->x();
- y() += v->y();
- z() += v->z();
- };
- void multiply(double v)
- {
- x() *= v;
- y() *= v;
- z() *= v;
- };
- private:
- double m_coordinates[3]; //xyz
- };
- class Vertex: public MeshElementBase, public Point3D
- {
- public:
- Vertex()
- {
- m_type = VERTEX;
- };
- ~Vertex(){};
- bool& saddle_or_boundary(){return m_saddle_or_boundary;};
- private:
- //this flag speeds up exact geodesic algorithm
- bool m_saddle_or_boundary; //it is true if total adjacent angle is larger than 2*PI or this vertex belongs to the mesh boundary
- };
- class Face: public MeshElementBase
- {
- public:
- Face()
- {
- m_type = FACE;
- };
- ~Face(){};
- edge_pointer opposite_edge(vertex_pointer v);
- vertex_pointer opposite_vertex(edge_pointer e);
- edge_pointer next_edge(edge_pointer e, vertex_pointer v);
- double vertex_angle(vertex_pointer v)
- {
- for(unsigned i=0; i<3; ++i)
- {
- if(adjacent_vertices()[i]->id() == v->id())
- {
- return m_corner_angles[i];
- }
- }
- assert(0);
- return 0;
- }
- double* corner_angles(){return m_corner_angles;};
- private:
- double m_corner_angles[3]; //triangle angles in radians; angles correspond to vertices in m_adjacent_vertices
- };
- class Edge: public MeshElementBase
- {
- public:
- Edge()
- {
- m_type = EDGE;
- };
- ~Edge(){};
- double& length(){return m_length;};
- face_pointer opposite_face(face_pointer f)
- {
- if(adjacent_faces().size() == 1)
- {
- assert(adjacent_faces()[0]->id() == f->id());
- return NULL;
- }
- assert(adjacent_faces()[0]->id() == f->id() ||
- adjacent_faces()[1]->id() == f->id());
- return adjacent_faces()[0]->id() == f->id() ?
- adjacent_faces()[1] : adjacent_faces()[0];
- };
- vertex_pointer opposite_vertex(vertex_pointer v)
- {
- assert(belongs(v));
- return adjacent_vertices()[0]->id() == v->id() ?
- adjacent_vertices()[1] : adjacent_vertices()[0];
- };
- bool belongs(vertex_pointer v)
- {
- return adjacent_vertices()[0]->id() == v->id() ||
- adjacent_vertices()[1]->id() == v->id();
- }
- bool is_boundary(){return adjacent_faces().size() == 1;};
- vertex_pointer v0(){return adjacent_vertices()[0];};
- vertex_pointer v1(){return adjacent_vertices()[1];};
- void local_coordinates(Point3D* point,
- double& x,
- double& y)
- {
- double d0 = point->distance(v0());
- if(d0 < 1e-50)
- {
- x = 0.0;
- y = 0.0;
- return;
- }
- double d1 = point->distance(v1());
- if(d1 < 1e-50)
- {
- x = m_length;
- y = 0.0;
- return;
- }
- x = m_length/2.0 + (d0*d0 - d1*d1)/(2.0*m_length);
- y = sqrt(std::max(0.0, d0*d0 - x*x));
- return;
- }
- private:
- double m_length; //length of the edge
- };
- class SurfacePoint:public Point3D //point on the surface of the mesh
- {
- public:
- SurfacePoint():
- m_p(NULL)
- {};
- SurfacePoint(vertex_pointer v): //set the surface point in the vertex
- SurfacePoint::Point3D(v),
- m_p(v)
- {};
- SurfacePoint(face_pointer f): //set the surface point in the center of the face
- m_p(f)
- {
- set(0,0,0);
- add(f->adjacent_vertices()[0]);
- add(f->adjacent_vertices()[1]);
- add(f->adjacent_vertices()[2]);
- multiply(1./3.);
- };
- SurfacePoint(edge_pointer e, //set the surface point in the middle of the edge
- double a = 0.5):
- m_p(e)
- {
- double b = 1 - a;
- vertex_pointer v0 = e->adjacent_vertices()[0];
- vertex_pointer v1 = e->adjacent_vertices()[1];
- x() = b*v0->x() + a*v1->x();
- y() = b*v0->y() + a*v1->y();
- z() = b*v0->z() + a*v1->z();
- };
- SurfacePoint(base_pointer g,
- double x,
- double y,
- double z,
- PointType /*t = UNDEFINED_POINT*/):
- m_p(g)
- {
- set(x,y,z);
- };
- void initialize(SurfacePoint const& p)
- {
- *this = p;
- }
- ~SurfacePoint(){};
- PointType type(){return m_p ? m_p->type() : UNDEFINED_POINT;};
- base_pointer& base_element(){return m_p;};
- protected:
- base_pointer m_p; //could be face, vertex or edge pointer
- };
- inline edge_pointer Face::opposite_edge(vertex_pointer v)
- {
- for(unsigned i=0; i<3; ++i)
- {
- edge_pointer e = adjacent_edges()[i];
- if(!e->belongs(v))
- {
- return e;
- }
- }
- assert(0);
- return NULL;
- }
- inline vertex_pointer Face::opposite_vertex(edge_pointer e)
- {
- for(unsigned i=0; i<3; ++i)
- {
- vertex_pointer v = adjacent_vertices()[i];
- if(!e->belongs(v))
- {
- return v;
- }
- }
- assert(0);
- return NULL;
- }
- inline edge_pointer Face::next_edge(edge_pointer e, vertex_pointer v)
- {
- assert(e->belongs(v));
- for(unsigned i=0; i<3; ++i)
- {
- edge_pointer next = adjacent_edges()[i];
- if(e->id() != next->id() && next->belongs(v))
- {
- return next;
- }
- }
- assert(0);
- return NULL;
- }
- struct HalfEdge //prototype of the edge; used for mesh construction
- {
- unsigned face_id;
- unsigned vertex_0; //adjacent vertices sorted by id value
- unsigned vertex_1; //they are sorted, vertex_0 < vertex_1
- };
- inline bool operator < (const HalfEdge &x, const HalfEdge &y)
- {
- if(x.vertex_0 == y.vertex_0)
- {
- return x.vertex_1 < y.vertex_1;
- }
- else
- {
- return x.vertex_0 < y.vertex_0;
- }
- }
- inline bool operator != (const HalfEdge &x, const HalfEdge &y)
- {
- return x.vertex_0 != y.vertex_0 || x.vertex_1 != y.vertex_1;
- }
- inline bool operator == (const HalfEdge &x, const HalfEdge &y)
- {
- return x.vertex_0 == y.vertex_0 && x.vertex_1 == y.vertex_1;
- }
- struct edge_visible_from_source
- {
- unsigned source;
- edge_pointer edge;
- };
- class Mesh
- {
- public:
- Mesh()
- {};
- ~Mesh(){};
- template<class Points, class Faces>
- void initialize_mesh_data(unsigned num_vertices,
- Points& p,
- unsigned num_faces,
- Faces& tri); //build mesh from regular point-triangle representation
- template<class Points, class Faces>
- void initialize_mesh_data(Points& p, Faces& tri); //build mesh from regular point-triangle representation
- std::vector<Vertex>& vertices(){return m_vertices;};
- std::vector<Edge>& edges(){return m_edges;};
- std::vector<Face>& faces(){return m_faces;};
- unsigned closest_vertices(SurfacePoint* p,
- std::vector<vertex_pointer>* storage = NULL); //list vertices closest to the point
- private:
- void build_adjacencies(); //build internal structure of the mesh
- bool verify(); //verifies connectivity of the mesh and prints some debug info
- typedef void* void_pointer;
- void_pointer allocate_pointers(unsigned n)
- {
- return m_pointer_allocator.allocate(n);
- }
- std::vector<Vertex> m_vertices;
- std::vector<Edge> m_edges;
- std::vector<Face> m_faces;
- SimlpeMemoryAllocator<void_pointer> m_pointer_allocator; //fast memory allocating for Face/Vertex/Edge cross-references
- };
- inline unsigned Mesh::closest_vertices(SurfacePoint* p,
- std::vector<vertex_pointer>* storage)
- {
- assert(p->type() != UNDEFINED_POINT);
- if(p->type() == VERTEX)
- {
- if(storage)
- {
- storage->push_back(static_cast<vertex_pointer>(p->base_element()));
- }
- return 1;
- }
- else if(p->type() == FACE)
- {
- if(storage)
- {
- vertex_pointer* vp= p->base_element()->adjacent_vertices().begin();
- storage->push_back(*vp);
- storage->push_back(*(vp+1));
- storage->push_back(*(vp+2));
- }
- return 2;
- }
- else if(p->type() == EDGE) //for edge include all 4 adjacent vertices
- {
- edge_pointer edge = static_cast<edge_pointer>(p->base_element());
- if(storage)
- {
- storage->push_back(edge->adjacent_vertices()[0]);
- storage->push_back(edge->adjacent_vertices()[1]);
- for(unsigned i = 0; i < edge->adjacent_faces().size(); ++i)
- {
- face_pointer face = edge->adjacent_faces()[i];
- storage->push_back(face->opposite_vertex(edge));
- }
- }
- return 2 + edge->adjacent_faces().size();
- }
- assert(0);
- return 0;
- }
- template<class Points, class Faces>
- void Mesh::initialize_mesh_data(Points& p, Faces& tri) //build mesh from regular point-triangle representation
- {
- assert(p.size() % 3 == 0);
- unsigned const num_vertices = p.size() / 3;
- assert(tri.size() % 3 == 0);
- unsigned const num_faces = tri.size() / 3;
- initialize_mesh_data(num_vertices, p, num_faces, tri);
- }
- template<class Points, class Faces>
- void Mesh::initialize_mesh_data(unsigned num_vertices,
- Points& p,
- unsigned num_faces,
- Faces& tri)
- {
- unsigned const approximate_number_of_internal_pointers = (num_vertices + num_faces)*4;
- unsigned const max_number_of_pointer_blocks = 100;
- m_pointer_allocator.reset(approximate_number_of_internal_pointers,
- max_number_of_pointer_blocks);
- m_vertices.resize(num_vertices);
- for(unsigned i=0; i<num_vertices; ++i) //copy coordinates to vertices
- {
- Vertex& v = m_vertices[i];
- v.id() = i;
- unsigned shift = 3*i;
- v.x() = p[shift];
- v.y() = p[shift + 1];
- v.z() = p[shift + 2];
- }
- m_faces.resize(num_faces);
- for(unsigned i=0; i<num_faces; ++i) //copy adjacent vertices to polygons/faces
- {
- Face& f = m_faces[i];
- f.id() = i;
- f.adjacent_vertices().set_allocation(allocate_pointers(3),3); //allocate three units of memory
- unsigned shift = 3*i;
- for(unsigned j=0; j<3; ++j)
- {
- unsigned vertex_index = tri[shift + j];
- assert(vertex_index < num_vertices);
- f.adjacent_vertices()[j] = &m_vertices[vertex_index];
- }
- }
- build_adjacencies(); //build the structure of the mesh
- }
- inline void Mesh::build_adjacencies()
- {
- // Vertex->adjacent Faces
- std::vector<unsigned> count(m_vertices.size()); //count adjacent vertices
- for(unsigned i=0; i<m_faces.size(); ++i)
- {
- Face& f = m_faces[i];
- for(unsigned j=0; j<3; ++j)
- {
- unsigned vertex_id = f.adjacent_vertices()[j]->id();
- assert(vertex_id < m_vertices.size());
- count[vertex_id]++;
- }
- }
- for(unsigned i=0; i<m_vertices.size(); ++i) //reserve space
- {
- Vertex& v = m_vertices[i];
- unsigned num_adjacent_faces = count[i];
- v.adjacent_faces().set_allocation(allocate_pointers(num_adjacent_faces), //allocate three units of memory
- num_adjacent_faces);
- }
- std::fill(count.begin(), count.end(), 0);
- for(unsigned i=0; i<m_faces.size(); ++i)
- {
- Face& f = m_faces[i];
- for(unsigned j=0; j<3; ++j)
- {
- vertex_pointer v = f.adjacent_vertices()[j];
- v->adjacent_faces()[count[v->id()]++] = &f;
- }
- }
- //find all edges
- //i.e. find all half-edges, sort and combine them into edges
- std::vector<HalfEdge> half_edges(m_faces.size()*3);
- unsigned k = 0;
- for(unsigned i=0; i<m_faces.size(); ++i)
- {
- Face& f = m_faces[i];
- for(unsigned j=0; j<3; ++j)
- {
- half_edges[k].face_id = i;
- unsigned vertex_id_1 = f.adjacent_vertices()[j]->id();
- unsigned vertex_id_2 = f.adjacent_vertices()[(j+1) % 3]->id();
- half_edges[k].vertex_0 = std::min(vertex_id_1, vertex_id_2);
- half_edges[k].vertex_1 = std::max(vertex_id_1, vertex_id_2);
- k++;
- }
- }
- std::sort(half_edges.begin(), half_edges.end());
- unsigned number_of_edges = 1;
- for(unsigned i=1; i<half_edges.size(); ++i)
- {
- if(half_edges[i] != half_edges[i-1])
- {
- ++number_of_edges;
- }
- else
- {
- if(i<half_edges.size()-1) //sanity check: there should be at most two equal half-edges
- { //if it fails, most likely the input data are messed up
- assert(half_edges[i] != half_edges[i+1]);
- }
- }
- }
- // Edges->adjacent Vertices and Faces
- m_edges.resize(number_of_edges);
- unsigned edge_id = 0;
- for(unsigned i=0; i<half_edges.size();)
- {
- Edge& e = m_edges[edge_id];
- e.id() = edge_id++;
- e.adjacent_vertices().set_allocation(allocate_pointers(2),2); //allocate two units of memory
- e.adjacent_vertices()[0] = &m_vertices[half_edges[i].vertex_0];
- e.adjacent_vertices()[1] = &m_vertices[half_edges[i].vertex_1];
- e.length() = e.adjacent_vertices()[0]->distance(e.adjacent_vertices()[1]);
- assert(e.length() > 1e-100); //algorithm works well with non-degenerate meshes only
- if(i != half_edges.size()-1 && half_edges[i] == half_edges[i+1]) //double edge
- {
- e.adjacent_faces().set_allocation(allocate_pointers(2),2);
- e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
- e.adjacent_faces()[1] = &m_faces[half_edges[i+1].face_id];
- i += 2;
- }
- else //single edge
- {
- e.adjacent_faces().set_allocation(allocate_pointers(1),1); //one adjucent faces
- e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
- i += 1;
- }
- }
- // Vertices->adjacent Edges
- std::fill(count.begin(), count.end(), 0);
- for(unsigned i=0; i<m_edges.size(); ++i)
- {
- Edge& e = m_edges[i];
- assert(e.adjacent_vertices().size()==2);
- count[e.adjacent_vertices()[0]->id()]++;
- count[e.adjacent_vertices()[1]->id()]++;
- }
- for(unsigned i=0; i<m_vertices.size(); ++i)
- {
- m_vertices[i].adjacent_edges().set_allocation(allocate_pointers(count[i]),
- count[i]);
- }
- std::fill(count.begin(), count.end(), 0);
- for(unsigned i=0; i<m_edges.size(); ++i)
- {
- Edge& e = m_edges[i];
- for(unsigned j=0; j<2; ++j)
- {
- vertex_pointer v = e.adjacent_vertices()[j];
- v->adjacent_edges()[count[v->id()]++] = &e;
- }
- }
- // Faces->adjacent Edges
- for(unsigned i=0; i<m_faces.size(); ++i)
- {
- m_faces[i].adjacent_edges().set_allocation(allocate_pointers(3),3);
- }
- count.resize(m_faces.size());
- std::fill(count.begin(), count.end(), 0);
- for(unsigned i=0; i<m_edges.size(); ++i)
- {
- Edge& e = m_edges[i];
- for(unsigned j=0; j<e.adjacent_faces().size(); ++j)
- {
- face_pointer f = e.adjacent_faces()[j];
- assert(count[f->id()]<3);
- f->adjacent_edges()[count[f->id()]++] = &e;
- }
- }
- //compute angles for the faces
- for(unsigned i=0; i<m_faces.size(); ++i)
- {
- Face& f = m_faces[i];
- double abc[3];
- double sum = 0;
- for(unsigned j=0; j<3; ++j) //compute angle adjacent to the vertex j
- {
- for(unsigned k=0; k<3; ++k)
- {
- vertex_pointer v = f.adjacent_vertices()[(j + k)%3];
- abc[k] = f.opposite_edge(v)->length();
- }
- double angle = angle_from_edges(abc[0], abc[1], abc[2]);
- assert(angle>1e-5); //algorithm works well with non-degenerate meshes only
- f.corner_angles()[j] = angle;
- sum += angle;
- }
- IGL_ASSERT(std::abs(sum - igl::PI) < 1e-5); //algorithm works well with non-degenerate meshes only
- }
- //define m_turn_around_flag for vertices
- std::vector<double> total_vertex_angle(m_vertices.size());
- for(unsigned i=0; i<m_faces.size(); ++i)
- {
- Face& f = m_faces[i];
- for(unsigned j=0; j<3; ++j)
- {
- vertex_pointer v = f.adjacent_vertices()[j];
- total_vertex_angle[v->id()] += f.corner_angles()[j];
- }
- }
- for(unsigned i=0; i<m_vertices.size(); ++i)
- {
- Vertex& v = m_vertices[i];
- v.saddle_or_boundary() = (total_vertex_angle[v.id()] > 2.0*igl::PI - 1e-5);
- }
- for(unsigned i=0; i<m_edges.size(); ++i)
- {
- Edge& e = m_edges[i];
- if(e.is_boundary())
- {
- e.adjacent_vertices()[0]->saddle_or_boundary() = true;
- e.adjacent_vertices()[1]->saddle_or_boundary() = true;
- }
- }
- assert(verify());
- }
- inline bool Mesh::verify() //verifies connectivity of the mesh and prints some debug info
- {
- // make sure that all vertices are mentioned at least once.
- // though the loose vertex is not a bug, it most likely indicates that something is wrong with the mesh
- std::vector<bool> map(m_vertices.size(), false);
- for(unsigned i=0; i<m_edges.size(); ++i)
- {
- edge_pointer e = &m_edges[i];
- map[e->adjacent_vertices()[0]->id()] = true;
- map[e->adjacent_vertices()[1]->id()] = true;
- }
- assert(std::find(map.begin(), map.end(), false) == map.end());
- //make sure that the mesh is connected trough its edges
- //if mesh has more than one connected component, it is most likely a bug
- std::vector<face_pointer> stack(1,&m_faces[0]);
- stack.reserve(m_faces.size());
- map.resize(m_faces.size());
- std::fill(map.begin(), map.end(), false);
- map[0] = true;
- while(!stack.empty())
- {
- face_pointer f = stack.back();
- stack.pop_back();
- for(unsigned i=0; i<3; ++i)
- {
- edge_pointer e = f->adjacent_edges()[i];
- face_pointer f_adjacent = e->opposite_face(f);
- if(f_adjacent && !map[f_adjacent->id()])
- {
- map[f_adjacent->id()] = true;
- stack.push_back(f_adjacent);
- }
- }
- }
- assert(std::find(map.begin(), map.end(), false) == map.end());
- //print some mesh statistics that can be useful in debugging
- // std::cout << "mesh has " << m_vertices.size()
- // << " vertices, " << m_faces.size()
- // << " faces, " << m_edges.size()
- // << " edges\n";
- //unsigned total_boundary_edges = 0;
- double longest_edge = 0;
- double shortest_edge = 1e100;
- for(unsigned i=0; i<m_edges.size(); ++i)
- {
- Edge& e = m_edges[i];
- //total_boundary_edges += e.is_boundary() ? 1 : 0;
- longest_edge = std::max(longest_edge, e.length());
- shortest_edge = std::min(shortest_edge, e.length());
- }
- // std::cout << total_boundary_edges << " edges are boundary edges\n";
- // std::cout << "shortest/longest edges are "
- // << shortest_edge << "/"
- // << longest_edge << " = "
- // << shortest_edge/longest_edge
- // << std::endl;
- double minx = 1e100;
- double maxx = -1e100;
- double miny = 1e100;
- double maxy = -1e100;
- double minz = 1e100;
- double maxz = -1e100;
- for(unsigned i=0; i<m_vertices.size(); ++i)
- {
- Vertex& v = m_vertices[i];
- minx = std::min(minx, v.x());
- maxx = std::max(maxx, v.x());
- miny = std::min(miny, v.y());
- maxy = std::max(maxy, v.y());
- minz = std::min(minz, v.z());
- maxz = std::max(maxz, v.z());
- }
- // std::cout << "enclosing XYZ box:"
- // <<" X[" << minx << "," << maxx << "]"
- // <<" Y[" << miny << "," << maxy << "]"
- // <<" Z[" << minz << "," << maxz << "]"
- // << std::endl;
- //double dx = maxx - minx;
- //double dy = maxy - miny;
- //double dz = maxz - minz;
- // std::cout << "approximate diameter of the mesh is "
- // << sqrt(dx*dx + dy*dy + dz*dz)
- // << std::endl;
- double min_angle = 1e100;
- double max_angle = -1e100;
- for(unsigned i=0; i<m_faces.size(); ++i)
- {
- Face& f = m_faces[i];
- for(unsigned j=0; j<3; ++j)
- {
- double angle = f.corner_angles()[j];
- min_angle = std::min(min_angle, angle);
- max_angle = std::max(max_angle, angle);
- }
- }
- // std::cout << "min/max face angles are "
- // << min_angle/igl::PI*180.0 << "/"
- // << max_angle/igl::PI*180.0
- // << " degrees\n";
- // std::cout << std::endl;
- return true;
- }
- inline void fill_surface_point_structure(geodesic::SurfacePoint* point,
- double* data,
- Mesh* mesh)
- {
- point->set(data);
- unsigned type = (unsigned) data[3];
- unsigned id = (unsigned) data[4];
- if(type == 0) //vertex
- {
- point->base_element() = &mesh->vertices()[id];
- }
- else if(type == 1) //edge
- {
- point->base_element() = &mesh->edges()[id];
- }
- else //face
- {
- point->base_element() = &mesh->faces()[id];
- }
- }
- inline void fill_surface_point_double(geodesic::SurfacePoint* point,
- double* data,
- long /*mesh_id*/)
- {
- data[0] = point->x();
- data[1] = point->y();
- data[2] = point->z();
- data[4] = point->base_element()->id();
- if(point->type() == VERTEX) //vertex
- {
- data[3] = 0;
- }
- else if(point->type() == EDGE) //edge
- {
- data[3] = 1;
- }
- else //face
- {
- data[3] = 2;
- }
- }
- class Interval;
- class IntervalList;
- typedef Interval* interval_pointer;
- typedef IntervalList* list_pointer;
- class Interval //interval of the edge
- {
- public:
- Interval(){};
- ~Interval(){};
- enum DirectionType
- {
- FROM_FACE_0,
- FROM_FACE_1,
- FROM_SOURCE,
- UNDEFINED_DIRECTION
- };
- double signal(double x) //geodesic distance function at point x
- {
- assert(x>=0.0 && x <= m_edge->length());
- if(m_d == GEODESIC_INF)
- {
- return GEODESIC_INF;
- }
- else
- {
- double dx = x - m_pseudo_x;
- if(m_pseudo_y == 0.0)
- {
- return m_d + std::abs(dx);
- }
- else
- {
- return m_d + sqrt(dx*dx + m_pseudo_y*m_pseudo_y);
- }
- }
- }
- double max_distance(double end)
- {
- if(m_d == GEODESIC_INF)
- {
- return GEODESIC_INF;
- }
- else
- {
- double a = std::abs(m_start - m_pseudo_x);
- double b = std::abs(end - m_pseudo_x);
- return a > b ? m_d + sqrt(a*a + m_pseudo_y*m_pseudo_y):
- m_d + sqrt(b*b + m_pseudo_y*m_pseudo_y);
- }
- }
- void compute_min_distance(double stop) //compute min, given c,d theta, start, end.
- {
- assert(stop > m_start);
- if(m_d == GEODESIC_INF)
- {
- m_min = GEODESIC_INF;
- }
- else if(m_start > m_pseudo_x)
- {
- m_min = signal(m_start);
- }
- else if(stop < m_pseudo_x)
- {
- m_min = signal(stop);
- }
- else
- {
- assert(m_pseudo_y<=0);
- m_min = m_d - m_pseudo_y;
- }
- }
- //compare two intervals in the queue
- bool operator()(interval_pointer const x, interval_pointer const y) const
- {
- if(x->min() != y->min())
- {
- return x->min() < y->min();
- }
- else if(x->start() != y->start())
- {
- return x->start() < y->start();
- }
- else
- {
- return x->edge()->id() < y->edge()->id();
- }
- }
- double stop() //return the endpoint of the interval
- {
- return m_next ? m_next->start() : m_edge->length();
- }
- double hypotenuse(double a, double b)
- {
- return sqrt(a*a + b*b);
- }
- void find_closest_point(double const x,
- double const y,
- double& offset,
- double& distance); //find the point on the interval that is closest to the point (alpha, s)
- double& start(){return m_start;};
- double& d(){return m_d;};
- double& pseudo_x(){return m_pseudo_x;};
- double& pseudo_y(){return m_pseudo_y;};
- double& min(){return m_min;};
- interval_pointer& next(){return m_next;};
- edge_pointer& edge(){return m_edge;};
- DirectionType& direction(){return m_direction;};
- bool visible_from_source(){return m_direction == FROM_SOURCE;};
- unsigned& source_index(){return m_source_index;};
- void initialize(edge_pointer edge,
- SurfacePoint* point = NULL,
- unsigned source_index = 0);
- protected:
- double m_start; //initial point of the interval on the edge
- double m_d; //distance from the source to the pseudo-source
- double m_pseudo_x; //coordinates of the pseudo-source in the local coordinate system
- double m_pseudo_y; //y-coordinate should be always negative
- double m_min; //minimum distance on the interval
- interval_pointer m_next; //pointer to the next interval in the list
- edge_pointer m_edge; //edge that the interval belongs to
- unsigned m_source_index; //the source it belongs to
- DirectionType m_direction; //where the interval is coming from
- };
- struct IntervalWithStop : public Interval
- {
- public:
- double& stop(){return m_stop;};
- protected:
- double m_stop;
- };
- class IntervalList //list of the of intervals of the given edge
- {
- public:
- IntervalList(){m_first = NULL;};
- ~IntervalList(){};
- void clear()
- {
- m_first = NULL;
- };
- void initialize(edge_pointer e)
- {
- m_edge = e;
- m_first = NULL;
- };
- interval_pointer covering_interval(double offset) //returns the interval that covers the offset
- {
- assert(offset >= 0.0 && offset <= m_edge->length());
- interval_pointer p = m_first;
- while(p && p->stop() < offset)
- {
- p = p->next();
- }
- return p;// && p->start() <= offset ? p : NULL;
- };
- void find_closest_point(SurfacePoint* point,
- double& offset,
- double& distance,
- interval_pointer& interval)
- {
- interval_pointer p = m_first;
- distance = GEODESIC_INF;
- interval = NULL;
- double x,y;
- m_edge->local_coordinates(point, x, y);
- while(p)
- {
- if(p->min()<GEODESIC_INF)
- {
- double o, d;
- p->find_closest_point(x, y, o, d);
- if(d < distance)
- {
- distance = d;
- offset = o;
- interval = p;
- }
- }
- p = p->next();
- }
- };
- unsigned number_of_intervals()
- {
- interval_pointer p = m_first;
- unsigned count = 0;
- while(p)
- {
- ++count;
- p = p->next();
- }
- return count;
- }
- interval_pointer last()
- {
- interval_pointer p = m_first;
- if(p)
- {
- while(p->next())
- {
- p = p->next();
- }
- }
- return p;
- }
- double signal(double x)
- {
- interval_pointer interval = covering_interval(x);
- return interval ? interval->signal(x) : GEODESIC_INF;
- }
- interval_pointer& first(){return m_first;};
- edge_pointer& edge(){return m_edge;};
- private:
- interval_pointer m_first; //pointer to the first member of the list
- edge_pointer m_edge; //edge that owns this list
- };
- class SurfacePointWithIndex : public SurfacePoint
- {
- public:
- unsigned index(){return m_index;};
- void initialize(SurfacePoint& p, unsigned index)
- {
- SurfacePoint::initialize(p);
- m_index = index;
- }
- bool operator()(SurfacePointWithIndex* x, SurfacePointWithIndex* y) const //used for sorting
- {
- assert(x->type() != UNDEFINED_POINT && y->type() !=UNDEFINED_POINT);
- if(x->type() != y->type())
- {
- return x->type() < y->type();
- }
- else
- {
- return x->base_element()->id() < y->base_element()->id();
- }
- }
- private:
- unsigned m_index;
- };
- class SortedSources : public std::vector<SurfacePointWithIndex>
- {
- private:
- typedef std::vector<SurfacePointWithIndex*> sorted_vector_type;
- public:
- typedef sorted_vector_type::iterator sorted_iterator;
- typedef std::pair<sorted_iterator, sorted_iterator> sorted_iterator_pair;
- sorted_iterator_pair sources(base_pointer mesh_element)
- {
- m_search_dummy.base_element() = mesh_element;
- return equal_range(m_sorted.begin(),
- m_sorted.end(),
- &m_search_dummy,
- m_compare_less);
- }
- void initialize(std::vector<SurfacePoint>& sources) //we initialize the sources by copie
- {
- resize(sources.size());
- m_sorted.resize(sources.size());
- for(unsigned i=0; i<sources.size(); ++i)
- {
- SurfacePointWithIndex& p = *(begin() + i);
- p.initialize(sources[i],i);
- m_sorted[i] = &p;
- }
- std::sort(m_sorted.begin(), m_sorted.end(), m_compare_less);
- };
- SurfacePointWithIndex& operator[](unsigned i)
- {
- assert(i < size());
- return *(begin() + i);
- }
- private:
- sorted_vector_type m_sorted;
- SurfacePointWithIndex m_search_dummy; //used as a search template
- SurfacePointWithIndex m_compare_less; //used as a compare functor
- };
- inline void Interval::find_closest_point(double const rs,
- double const hs,
- double& r,
- double& d_out) //find the point on the interval that is closest to the point (alpha, s)
- {
- if(m_d == GEODESIC_INF)
- {
- r = GEODESIC_INF;
- d_out = GEODESIC_INF;
- return;
- }
- double hc = -m_pseudo_y;
- double rc = m_pseudo_x;
- double end = stop();
- double local_epsilon = SMALLEST_INTERVAL_RATIO*m_edge->length();
- if(std::abs(hs+hc) < local_epsilon)
- {
- if(rs<=m_start)
- {
- r = m_start;
- d_out = signal(m_start) + std::abs(rs - m_start);
- }
- else if(rs>=end)
- {
- r = end;
- d_out = signal(end) + fabs(end - rs);
- }
- else
- {
- r = rs;
- d_out = signal(rs);
- }
- }
- else
- {
- double ri = (rs*hc + hs*rc)/(hs+hc);
- if(ri<m_start)
- {
- r = m_start;
- d_out = signal(m_start) + hypotenuse(m_start - rs, hs);
- }
- else if(ri>end)
- {
- r = end;
- d_out = signal(end) + hypotenuse(end - rs, hs);
- }
- else
- {
- r = ri;
- d_out = m_d + hypotenuse(rc - rs, hc + hs);
- }
- }
- }
- inline void Interval::initialize(edge_pointer edge,
- SurfacePoint* source,
- unsigned source_index)
- {
- m_next = NULL;
- //m_geodesic_previous = NULL;
- m_direction = UNDEFINED_DIRECTION;
- m_edge = edge;
- m_source_index = source_index;
- m_start = 0.0;
- //m_stop = edge->length();
- if(!source)
- {
- m_d = GEODESIC_INF;
- m_min = GEODESIC_INF;
- return;
- }
- m_d = 0;
- if(source->base_element()->type() == VERTEX)
- {
- if(source->base_element()->id() == edge->v0()->id())
- {
- m_pseudo_x = 0.0;
- m_pseudo_y = 0.0;
- m_min = 0.0;
- return;
- }
- else if(source->base_element()->id() == edge->v1()->id())
- {
- m_pseudo_x = stop();
- m_pseudo_y = 0.0;
- m_min = 0.0;
- return;
- }
- }
- edge->local_coordinates(source, m_pseudo_x, m_pseudo_y);
- m_pseudo_y = -m_pseudo_y;
- compute_min_distance(stop());
- }
- // #include "geodesic_algorithm_base.h"
- class GeodesicAlgorithmBase
- {
- public:
- enum AlgorithmType
- {
- EXACT,
- DIJKSTRA,
- SUBDIVISION,
- UNDEFINED_ALGORITHM
- };
- GeodesicAlgorithmBase(geodesic::Mesh* mesh):
- m_type(UNDEFINED_ALGORITHM),
- m_max_propagation_distance(1e100),
- m_mesh(mesh)
- {};
- virtual ~GeodesicAlgorithmBase(){};
- virtual void propagate(std::vector<SurfacePoint>& sources,
- double max_propagation_distance = GEODESIC_INF, //propagation algorithm stops after reaching the certain distance from the source
- std::vector<SurfacePoint>* stop_points = NULL) = 0; //or after ensuring that all the stop_points are covered
- virtual void trace_back(SurfacePoint& destination, //trace back piecewise-linear path
- std::vector<SurfacePoint>& path) = 0;
- void geodesic(SurfacePoint& source,
- SurfacePoint& destination,
- std::vector<SurfacePoint>& path); //lazy people can find geodesic path with one function call
- void geodesic(std::vector<SurfacePoint>& sources,
- std::vector<SurfacePoint>& destinations,
- std::vector<std::vector<SurfacePoint> >& paths); //lazy people can find geodesic paths with one function call
- virtual unsigned best_source(SurfacePoint& point, //after propagation step is done, quickly find what source this point belongs to and what is the distance to this source
- double& best_source_distance) = 0;
- virtual void print_statistics() //print info about timing and memory usage in the propagation step of the algorithm
- {
- std::cout << "propagation step took " << m_time_consumed << " seconds " << std::endl;
- };
- AlgorithmType type(){return m_type;};
- virtual std::string name();
- geodesic::Mesh* mesh(){return m_mesh;};
- protected:
- void set_stop_conditions(std::vector<SurfacePoint>* stop_points,
- double stop_distance);
- double stop_distance()
- {
- return m_max_propagation_distance;
- }
- AlgorithmType m_type; // type of the algorithm
- typedef std::pair<vertex_pointer, double> stop_vertex_with_distace_type;
- std::vector<stop_vertex_with_distace_type> m_stop_vertices; // algorithm stops propagation after covering certain vertices
- double m_max_propagation_distance; // or reaching the certain distance
- geodesic::Mesh* m_mesh;
- double m_time_consumed; //how much time does the propagation step takes
- double m_propagation_distance_stopped; //at what distance (if any) the propagation algorithm stopped
- };
- inline double length(std::vector<SurfacePoint>& path)
- {
- double length = 0;
- if(!path.empty())
- {
- for(unsigned i=0; i<path.size()-1; ++i)
- {
- length += path[i].distance(&path[i+1]);
- }
- }
- return length;
- }
- inline void print_info_about_path(std::vector<SurfacePoint>& path)
- {
- std::cout << "number of the points in the path = " << path.size()
- << ", length of the path = " << length(path)
- << std::endl;
- }
- inline std::string GeodesicAlgorithmBase::name()
- {
- switch(m_type)
- {
- case EXACT:
- return "exact";
- case DIJKSTRA:
- return "dijkstra";
- case SUBDIVISION:
- return "subdivision";
- default:
- case UNDEFINED_ALGORITHM:
- return "undefined";
- }
- }
- inline void GeodesicAlgorithmBase::geodesic(SurfacePoint& source,
- SurfacePoint& destination,
- std::vector<SurfacePoint>& path) //lazy people can find geodesic path with one function call
- {
- std::vector<SurfacePoint> sources(1, source);
- std::vector<SurfacePoint> stop_points(1, destination);
- double const max_propagation_distance = GEODESIC_INF;
- propagate(sources,
- max_propagation_distance,
- &stop_points);
- trace_back(destination, path);
- }
- inline void GeodesicAlgorithmBase::geodesic(std::vector<SurfacePoint>& sources,
- std::vector<SurfacePoint>& destinations,
- std::vector<std::vector<SurfacePoint> >& paths) //lazy people can find geodesic paths with one function call
- {
- double const max_propagation_distance = GEODESIC_INF;
- propagate(sources,
- max_propagation_distance,
- &destinations); //we use desinations as stop points
- paths.resize(destinations.size());
- for(unsigned i=0; i<paths.size(); ++i)
- {
- trace_back(destinations[i], paths[i]);
- }
- }
- inline void GeodesicAlgorithmBase::set_stop_conditions(std::vector<SurfacePoint>* stop_points,
- double stop_distance)
- {
- m_max_propagation_distance = stop_distance;
- if(!stop_points)
- {
- m_stop_vertices.clear();
- return;
- }
- m_stop_vertices.resize(stop_points->size());
- std::vector<vertex_pointer> possible_vertices;
- for(unsigned i = 0; i < stop_points->size(); ++i)
- {
- SurfacePoint* point = &(*stop_points)[i];
- possible_vertices.clear();
- m_mesh->closest_vertices(point, &possible_vertices);
- vertex_pointer closest_vertex = NULL;
- double min_distance = 1e100;
- for(unsigned j = 0; j < possible_vertices.size(); ++j)
- {
- double distance = point->distance(possible_vertices[j]);
- if(distance < min_distance)
- {
- min_distance = distance;
- closest_vertex = possible_vertices[j];
- }
- }
- assert(closest_vertex);
- m_stop_vertices[i].first = closest_vertex;
- m_stop_vertices[i].second = min_distance;
- }
- }
- class GeodesicAlgorithmExact : public GeodesicAlgorithmBase
- {
- public:
- GeodesicAlgorithmExact(geodesic::Mesh* mesh):
- GeodesicAlgorithmBase(mesh),
- m_memory_allocator(mesh->edges().size(), mesh->edges().size()),
- m_edge_interval_lists(mesh->edges().size())
- {
- m_type = EXACT;
- for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
- {
- m_edge_interval_lists[i].initialize(&mesh->edges()[i]);
- }
- };
- ~GeodesicAlgorithmExact(){};
- void propagate(std::vector<SurfacePoint>& sources,
- double max_propagation_distance = GEODESIC_INF, //propagation algorithm stops after reaching the certain distance from the source
- std::vector<SurfacePoint>* stop_points = NULL); //or after ensuring that all the stop_points are covered
- void trace_back(SurfacePoint& destination, //trace back piecewise-linear path
- std::vector<SurfacePoint>& path);
- unsigned best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source
- double& best_source_distance);
- void print_statistics();
- private:
- typedef std::set<interval_pointer, Interval> IntervalQueue;
- void update_list_and_queue(list_pointer list,
- IntervalWithStop* candidates, //up to two candidates
- unsigned num_candidates);
- unsigned compute_propagated_parameters(double pseudo_x,
- double pseudo_y,
- double d, //parameters of the interval
- double start,
- double end, //start/end of the interval
- double alpha, //corner angle
- double L, //length of the new edge
- bool first_interval, //if it is the first interval on the edge
- bool last_interval,
- bool turn_left,
- bool turn_right,
- IntervalWithStop* candidates); //if it is the last interval on the edge
- void construct_propagated_intervals(bool invert,
- edge_pointer edge,
- face_pointer face, //constructs iNew from the rest of the data
- IntervalWithStop* candidates,
- unsigned& num_candidates,
- interval_pointer source_interval);
- double compute_positive_intersection(double start,
- double pseudo_x,
- double pseudo_y,
- double sin_alpha,
- double cos_alpha); //used in construct_propagated_intervals
- unsigned intersect_intervals(interval_pointer zero,
- IntervalWithStop* one); //intersecting two intervals with up to three intervals in the end
- interval_pointer best_first_interval(SurfacePoint& point,
- double& best_total_distance,
- double& best_interval_position,
- unsigned& best_source_index);
- bool check_stop_conditions(unsigned& index);
- void clear()
- {
- m_memory_allocator.clear();
- m_queue.clear();
- for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
- {
- m_edge_interval_lists[i].clear();
- }
- m_propagation_distance_stopped = GEODESIC_INF;
- };
- list_pointer interval_list(edge_pointer e)
- {
- return &m_edge_interval_lists[e->id()];
- };
- void set_sources(std::vector<SurfacePoint>& sources)
- {
- m_sources.initialize(sources);
- }
- void initialize_propagation_data();
- void list_edges_visible_from_source(MeshElementBase* p,
- std::vector<edge_pointer>& storage); //used in initialization
- long visible_from_source(SurfacePoint& point); //used in backtracing
- void best_point_on_the_edge_set(SurfacePoint& point,
- std::vector<edge_pointer> const& storage,
- interval_pointer& best_interval,
- double& best_total_distance,
- double& best_interval_position);
- void possible_traceback_edges(SurfacePoint& point,
- std::vector<edge_pointer>& storage);
- bool erase_from_queue(interval_pointer p);
- IntervalQueue m_queue; //interval queue
- MemoryAllocator<Interval> m_memory_allocator; //quickly allocate and deallocate intervals
- std::vector<IntervalList> m_edge_interval_lists; //every edge has its interval data
- enum MapType {OLD, NEW}; //used for interval intersection
- MapType map[5];
- double start[6];
- interval_pointer i_new[5];
- unsigned m_queue_max_size; //used for statistics
- unsigned m_iterations; //used for statistics
- SortedSources m_sources;
- };
- inline void GeodesicAlgorithmExact::best_point_on_the_edge_set(SurfacePoint& point,
- std::vector<edge_pointer> const& storage,
- interval_pointer& best_interval,
- double& best_total_distance,
- double& best_interval_position)
- {
- best_total_distance = 1e100;
- for(unsigned i=0; i<storage.size(); ++i)
- {
- edge_pointer e = storage[i];
- list_pointer list = interval_list(e);
- double offset;
- double distance;
- interval_pointer interval;
- list->find_closest_point(&point,
- offset,
- distance,
- interval);
- if(distance < best_total_distance)
- {
- best_interval = interval;
- best_total_distance = distance;
- best_interval_position = offset;
- }
- }
- }
- inline void GeodesicAlgorithmExact::possible_traceback_edges(SurfacePoint& point,
- std::vector<edge_pointer>& storage)
- {
- storage.clear();
- if(point.type() == VERTEX)
- {
- vertex_pointer v = static_cast<vertex_pointer>(point.base_element());
- for(unsigned i=0; i<v->adjacent_faces().size(); ++i)
- {
- face_pointer f = v->adjacent_faces()[i];
- storage.push_back(f->opposite_edge(v));
- }
- }
- else if(point.type() == EDGE)
- {
- edge_pointer e = static_cast<edge_pointer>(point.base_element());
- for(unsigned i=0; i<e->adjacent_faces().size(); ++i)
- {
- face_pointer f = e->adjacent_faces()[i];
- storage.push_back(f->next_edge(e,e->v0()));
- storage.push_back(f->next_edge(e,e->v1()));
- }
- }
- else
- {
- face_pointer f = static_cast<face_pointer>(point.base_element());
- storage.push_back(f->adjacent_edges()[0]);
- storage.push_back(f->adjacent_edges()[1]);
- storage.push_back(f->adjacent_edges()[2]);
- }
- }
- inline long GeodesicAlgorithmExact::visible_from_source(SurfacePoint& point) //negative if not visible
- {
- assert(point.type() != UNDEFINED_POINT);
- if(point.type() == EDGE)
- {
- edge_pointer e = static_cast<edge_pointer>(point.base_element());
- list_pointer list = interval_list(e);
- double position = std::min(point.distance(e->v0()), e->length());
- interval_pointer interval = list->covering_interval(position);
- //assert(interval);
- if(interval && interval->visible_from_source())
- {
- return (long)interval->source_index();
- }
- else
- {
- return -1;
- }
- }
- else if(point.type() == FACE)
- {
- return -1;
- }
- else if(point.type() == VERTEX)
- {
- vertex_pointer v = static_cast<vertex_pointer>(point.base_element());
- for(unsigned i=0; i<v->adjacent_edges().size(); ++i)
- {
- edge_pointer e = v->adjacent_edges()[i];
- list_pointer list = interval_list(e);
- double position = e->v0()->id() == v->id() ? 0.0 : e->length();
- interval_pointer interval = list->covering_interval(position);
- if(interval && interval->visible_from_source())
- {
- return (long)interval->source_index();
- }
- }
- return -1;
- }
- assert(0);
- return 0;
- }
- inline double GeodesicAlgorithmExact::compute_positive_intersection(double start,
- double pseudo_x,
- double pseudo_y,
- double sin_alpha,
- double cos_alpha)
- {
- assert(pseudo_y < 0);
- double denominator = sin_alpha*(pseudo_x - start) - cos_alpha*pseudo_y;
- if(denominator<0.0)
- {
- return -1.0;
- }
- double numerator = -pseudo_y*start;
- if(numerator < 1e-30)
- {
- return 0.0;
- }
- if(denominator < 1e-30)
- {
- return -1.0;
- }
- return numerator/denominator;
- }
- inline void GeodesicAlgorithmExact::list_edges_visible_from_source(MeshElementBase* p,
- std::vector<edge_pointer>& storage)
- {
- assert(p->type() != UNDEFINED_POINT);
- if(p->type() == FACE)
- {
- face_pointer f = static_cast<face_pointer>(p);
- for(unsigned i=0; i<3; ++i)
- {
- storage.push_back(f->adjacent_edges()[i]);
- }
- }
- else if(p->type() == EDGE)
- {
- edge_pointer e = static_cast<edge_pointer>(p);
- storage.push_back(e);
- }
- else //VERTEX
- {
- vertex_pointer v = static_cast<vertex_pointer>(p);
- for(unsigned i=0; i<v->adjacent_edges().size(); ++i)
- {
- storage.push_back(v->adjacent_edges()[i]);
- }
- }
- }
- inline bool GeodesicAlgorithmExact::erase_from_queue(interval_pointer p)
- {
- if(p->min() < GEODESIC_INF/10.0)// && p->min >= queue->begin()->first)
- {
- assert(m_queue.count(p)<=1); //the set is unique
- IntervalQueue::iterator it = m_queue.find(p);
- if(it != m_queue.end())
- {
- m_queue.erase(it);
- return true;
- }
- }
- return false;
- }
- inline unsigned GeodesicAlgorithmExact::intersect_intervals(interval_pointer zero,
- IntervalWithStop* one) //intersecting two intervals with up to three intervals in the end
- {
- assert(zero->edge()->id() == one->edge()->id());
- assert(zero->stop() > one->start() && zero->start() < one->stop());
- assert(one->min() < GEODESIC_INF/10.0);
- double const local_epsilon = SMALLEST_INTERVAL_RATIO*one->edge()->length();
- unsigned N=0;
- if(zero->min() > GEODESIC_INF/10.0)
- {
- start[0] = zero->start();
- if(zero->start() < one->start() - local_epsilon)
- {
- map[0] = OLD;
- start[1] = one->start();
- map[1] = NEW;
- N = 2;
- }
- else
- {
- map[0] = NEW;
- N = 1;
- }
- if(zero->stop() > one->stop() + local_epsilon)
- {
- map[N] = OLD; //"zero" interval
- start[N++] = one->stop();
- }
- start[N+1] = zero->stop();
- return N;
- }
- double const local_small_epsilon = 1e-8*one->edge()->length();
- double D = zero->d() - one->d();
- double x0 = zero->pseudo_x();
- double x1 = one->pseudo_x();
- double R0 = x0*x0 + zero->pseudo_y()*zero->pseudo_y();
- double R1 = x1*x1 + one->pseudo_y()*one->pseudo_y();
- double inter[2]; //points of intersection
- char Ninter=0; //number of the points of the intersection
- if(std::abs(D)<local_epsilon) //if d1 == d0, equation is linear
- {
- double denom = x1 - x0;
- if(std::abs(denom)>local_small_epsilon)
- {
- inter[0] = (R1 - R0)/(2.*denom); //one solution
- Ninter = 1;
- }
- }
- else
- {
- double D2 = D*D;
- double Q = 0.5*(R1-R0-D2);
- double X = x0 - x1;
- double A = X*X - D2;
- double B = Q*X + D2*x0;
- double C = Q*Q - D2*R0;
- if (std::abs(A)<local_small_epsilon) //if A == 0, linear equation
- {
- if(std::abs(B)>local_small_epsilon)
- {
- inter[0] = -C/B; //one solution
- Ninter = 1;
- }
- }
- else
- {
- double det = B*B-A*C;
- if(det>local_small_epsilon*local_small_epsilon) //two roots
- {
- det = sqrt(det);
- if(A>0.0) //make sure that the roots are ordered
- {
- inter[0] = (-B - det)/A;
- inter[1] = (-B + det)/A;
- }
- else
- {
- inter[0] = (-B + det)/A;
- inter[1] = (-B - det)/A;
- }
- if(inter[1] - inter[0] > local_small_epsilon)
- {
- Ninter = 2;
- }
- else
- {
- Ninter = 1;
- }
- }
- else if(det>=0.0) //single root
- {
- inter[0] = -B/A;
- Ninter = 1;
- }
- }
- }
- //---------------------------find possible intervals---------------------------------------
- double left = std::max(zero->start(), one->start()); //define left and right boundaries of the intersection of the intervals
- double right = std::min(zero->stop(), one->stop());
- double good_start[4]; //points of intersection within the (left, right) limits +"left" + "right"
- good_start[0] = left;
- unsigned char Ngood_start=1; //number of the points of the intersection
- for(unsigned char i=0; i<Ninter; ++i) //for all points of intersection
- {
- double x = inter[i];
- if(x > left + local_epsilon && x < right - local_epsilon)
- {
- good_start[Ngood_start++] = x;
- }
- }
- good_start[Ngood_start++] = right;
- MapType mid_map[3];
- for(unsigned char i=0; i<Ngood_start-1; ++i)
- {
- double mid = (good_start[i] + good_start[i+1])*0.5;
- mid_map[i] = zero->signal(mid) <= one->signal(mid) ? OLD : NEW;
- }
- //-----------------------------------output----------------------------------
- N = 0;
- if(zero->start() < left - local_epsilon) //additional "zero" interval
- {
- if(mid_map[0] == OLD) //first interval in the map is already the old one
- {
- good_start[0] = zero->start();
- }
- else
- {
- map[N] = OLD; //"zero" interval
- start[N++] = zero->start();
- }
- }
- for(long i=0;i<Ngood_start-1;++i) //for all intervals
- {
- MapType current_map = mid_map[i];
- if(N==0 || map[N-1] != current_map)
- {
- map[N] = current_map;
- start[N++] = good_start[i];
- }
- }
- if(zero->stop() > one->stop() + local_epsilon)
- {
- if(N==0 || map[N-1] == NEW)
- {
- map[N] = OLD; //"zero" interval
- start[N++] = one->stop();
- }
- }
- start[0] = zero->start(); // just to make sure that epsilons do not damage anything
- //start[N] = zero->stop();
- return N;
- }
- inline void GeodesicAlgorithmExact::initialize_propagation_data()
- {
- clear();
- IntervalWithStop candidate;
- std::vector<edge_pointer> edges_visible_from_source;
- for(unsigned i=0; i<m_sources.size(); ++i) //for all edges adjacent to the starting vertex
- {
- SurfacePoint* source = &m_sources[i];
- edges_visible_from_source.clear();
- list_edges_visible_from_source(source->base_element(),
- edges_visible_from_source);
- for(unsigned j=0; j<edges_visible_from_source.size(); ++j)
- {
- edge_pointer e = edges_visible_from_source[j];
- candidate.initialize(e, source, i);
- candidate.stop() = e->length();
- candidate.compute_min_distance(candidate.stop());
- candidate.direction() = Interval::FROM_SOURCE;
- update_list_and_queue(interval_list(e), &candidate, 1);
- }
- }
- }
- inline void GeodesicAlgorithmExact::propagate(std::vector<SurfacePoint>& sources,
- double max_propagation_distance, //propagation algorithm stops after reaching the certain distance from the source
- std::vector<SurfacePoint>* stop_points)
- {
- set_stop_conditions(stop_points, max_propagation_distance);
- set_sources(sources);
- initialize_propagation_data();
- clock_t start = clock();
- unsigned satisfied_index = 0;
- m_iterations = 0; //for statistics
- m_queue_max_size = 0;
- IntervalWithStop candidates[2];
- while(!m_queue.empty())
- {
- m_queue_max_size = std::max(static_cast<unsigned int>(m_queue.size()), m_queue_max_size);
- unsigned const check_period = 10;
- if(++m_iterations % check_period == 0) //check if we covered all required vertices
- {
- if (check_stop_conditions(satisfied_index))
- {
- break;
- }
- }
- interval_pointer min_interval = *m_queue.begin();
- m_queue.erase(m_queue.begin());
- edge_pointer edge = min_interval->edge();
- //list_pointer list = interval_list(edge);
- assert(min_interval->d() < GEODESIC_INF);
- bool const first_interval = min_interval->start() == 0.0;
- //bool const last_interval = min_interval->stop() == edge->length();
- bool const last_interval = min_interval->next() == NULL;
- bool const turn_left = edge->v0()->saddle_or_boundary();
- bool const turn_right = edge->v1()->saddle_or_boundary();
- for(unsigned i=0; i<edge->adjacent_faces().size(); ++i) //two possible faces to propagate
- {
- if(!edge->is_boundary()) //just in case, always propagate boundary edges
- {
- if((i == 0 && min_interval->direction() == Interval::FROM_FACE_0) ||
- (i == 1 && min_interval->direction() == Interval::FROM_FACE_1))
- {
- continue;
- }
- }
- face_pointer face = edge->adjacent_faces()[i]; //if we come from 1, go to 2
- edge_pointer next_edge = face->next_edge(edge,edge->v0());
- unsigned num_propagated = compute_propagated_parameters(min_interval->pseudo_x(),
- min_interval->pseudo_y(),
- min_interval->d(), //parameters of the interval
- min_interval->start(),
- min_interval->stop(), //start/end of the interval
- face->vertex_angle(edge->v0()), //corner angle
- next_edge->length(), //length of the new edge
- first_interval, //if it is the first interval on the edge
- last_interval,
- turn_left,
- turn_right,
- candidates); //if it is the last interval on the edge
- bool propagate_to_right = true;
- if(num_propagated)
- {
- if(candidates[num_propagated-1].stop() != next_edge->length())
- {
- propagate_to_right = false;
- }
- bool const invert = next_edge->v0()->id() != edge->v0()->id(); //if the origins coinside, do not invert intervals
- construct_propagated_intervals(invert, //do not inverse
- next_edge,
- face,
- candidates,
- num_propagated,
- min_interval);
- update_list_and_queue(interval_list(next_edge),
- candidates,
- num_propagated);
- }
- if(propagate_to_right)
- {
- //propogation to the right edge
- double length = edge->length();
- next_edge = face->next_edge(edge,edge->v1());
- num_propagated = compute_propagated_parameters(length - min_interval->pseudo_x(),
- min_interval->pseudo_y(),
- min_interval->d(), //parameters of the interval
- length - min_interval->stop(),
- length - min_interval->start(), //start/end of the interval
- face->vertex_angle(edge->v1()), //corner angle
- next_edge->length(), //length of the new edge
- last_interval, //if it is the first interval on the edge
- first_interval,
- turn_right,
- turn_left,
- candidates); //if it is the last interval on the edge
- if(num_propagated)
- {
- bool const invert = next_edge->v0()->id() != edge->v1()->id(); //if the origins coinside, do not invert intervals
- construct_propagated_intervals(invert, //do not inverse
- next_edge,
- face,
- candidates,
- num_propagated,
- min_interval);
- update_list_and_queue(interval_list(next_edge),
- candidates,
- num_propagated);
- }
- }
- }
- }
- m_propagation_distance_stopped = m_queue.empty() ? GEODESIC_INF : (*m_queue.begin())->min();
- clock_t stop = clock();
- m_time_consumed = (static_cast<double>(stop)-static_cast<double>(start))/CLOCKS_PER_SEC;
- /* for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
- {
- list_pointer list = &m_edge_interval_lists[i];
- interval_pointer p = list->first();
- assert(p->start() == 0.0);
- while(p->next())
- {
- assert(p->stop() == p->next()->start());
- assert(p->d() < GEODESIC_INF);
- p = p->next();
- }
- }*/
- }
- inline bool GeodesicAlgorithmExact::check_stop_conditions(unsigned& index)
- {
- double queue_distance = (*m_queue.begin())->min();
- if(queue_distance < stop_distance())
- {
- return false;
- }
- while(index < m_stop_vertices.size())
- {
- vertex_pointer v = m_stop_vertices[index].first;
- edge_pointer edge = v->adjacent_edges()[0]; //take any edge
- double distance = edge->v0()->id() == v->id() ?
- interval_list(edge)->signal(0.0) :
- interval_list(edge)->signal(edge->length());
- if(queue_distance < distance + m_stop_vertices[index].second)
- {
- return false;
- }
- ++index;
- }
- return true;
- }
- inline void GeodesicAlgorithmExact::update_list_and_queue(list_pointer list,
- IntervalWithStop* candidates, //up to two candidates
- unsigned num_candidates)
- {
- assert(num_candidates <= 2);
- //assert(list->first() != NULL);
- edge_pointer edge = list->edge();
- double const local_epsilon = SMALLEST_INTERVAL_RATIO * edge->length();
- if(list->first() == NULL)
- {
- interval_pointer* p = &list->first();
- IntervalWithStop* first;
- IntervalWithStop* second;
- if(num_candidates == 1)
- {
- first = candidates;
- second = candidates;
- first->compute_min_distance(first->stop());
- }
- else
- {
- if(candidates->start() <= (candidates+1)->start())
- {
- first = candidates;
- second = candidates+1;
- }
- else
- {
- first = candidates+1;
- second = candidates;
- }
- assert(first->stop() == second->start());
- first->compute_min_distance(first->stop());
- second->compute_min_distance(second->stop());
- }
- if(first->start() > 0.0)
- {
- *p = m_memory_allocator.allocate();
- (*p)->initialize(edge);
- p = &(*p)->next();
- }
- *p = m_memory_allocator.allocate();
- memcpy(*p,first,sizeof(Interval));
- m_queue.insert(*p);
- if(num_candidates == 2)
- {
- p = &(*p)->next();
- *p = m_memory_allocator.allocate();
- memcpy(*p,second,sizeof(Interval));
- m_queue.insert(*p);
- }
- if(second->stop() < edge->length())
- {
- p = &(*p)->next();
- *p = m_memory_allocator.allocate();
- (*p)->initialize(edge);
- (*p)->start() = second->stop();
- }
- else
- {
- (*p)->next() = NULL;
- }
- return;
- }
- bool propagate_flag;
- for(unsigned i=0; i<num_candidates; ++i) //for all new intervals
- {
- IntervalWithStop* q = &candidates[i];
- interval_pointer previous = NULL;
- interval_pointer p = list->first();
- assert(p->start() == 0.0);
- while(p != NULL && p->stop() - local_epsilon < q->start())
- {
- p = p->next();
- }
- while(p != NULL && p->start() < q->stop() - local_epsilon) //go through all old intervals
- {
- unsigned const N = intersect_intervals(p, q); //interset two intervals
- if(N == 1)
- {
- if(map[0]==OLD) //if "p" is always better, we do not need to update anything)
- {
- if(previous) //close previous interval and put in into the queue
- {
- previous->next() = p;
- previous->compute_min_distance(p->start());
- m_queue.insert(previous);
- previous = NULL;
- }
- p = p->next();
- }
- else if(previous) //extend previous interval to cover everything; remove p
- {
- previous->next() = p->next();
- erase_from_queue(p);
- m_memory_allocator.deallocate(p);
- p = previous->next();
- }
- else //p becomes "previous"
- {
- previous = p;
- interval_pointer next = p->next();
- erase_from_queue(p);
- memcpy(previous,q,sizeof(Interval));
- previous->start() = start[0];
- previous->next() = next;
- p = next;
- }
- continue;
- }
- //update_flag = true;
- Interval swap(*p); //used for swapping information
- propagate_flag = erase_from_queue(p);
- for(unsigned j=1; j<N; ++j) //no memory is needed for the first one
- {
- i_new[j] = m_memory_allocator.allocate(); //create new intervals
- }
- if(map[0]==OLD) //finish previous, if any
- {
- if(previous)
- {
- previous->next() = p;
- previous->compute_min_distance(previous->stop());
- m_queue.insert(previous);
- previous = NULL;
- }
- i_new[0] = p;
- p->next() = i_new[1];
- p->start() = start[0];
- }
- else if(previous) //extend previous interval to cover everything; remove p
- {
- i_new[0] = previous;
- previous->next() = i_new[1];
- m_memory_allocator.deallocate(p);
- previous = NULL;
- }
- else //p becomes "previous"
- {
- i_new[0] = p;
- memcpy(p,q,sizeof(Interval));
- p->next() = i_new[1];
- p->start() = start[0];
- }
- assert(!previous);
- for(unsigned j=1; j<N; ++j)
- {
- interval_pointer current_interval = i_new[j];
- if(map[j] == OLD)
- {
- memcpy(current_interval,&swap,sizeof(Interval));
- }
- else
- {
- memcpy(current_interval,q,sizeof(Interval));
- }
- if(j == N-1)
- {
- current_interval->next() = swap.next();
- }
- else
- {
- current_interval->next() = i_new[j+1];
- }
- current_interval->start() = start[j];
- }
- for(unsigned j=0; j<N; ++j) //find "min" and add the intervals to the queue
- {
- if(j==N-1 && map[j]==NEW)
- {
- previous = i_new[j];
- }
- else
- {
- interval_pointer current_interval = i_new[j];
- current_interval->compute_min_distance(current_interval->stop()); //compute minimal distance
- if(map[j]==NEW || (map[j]==OLD && propagate_flag))
- {
- m_queue.insert(current_interval);
- }
- }
- }
- p = swap.next();
- }
- if(previous) //close previous interval and put in into the queue
- {
- previous->compute_min_distance(previous->stop());
- m_queue.insert(previous);
- previous = NULL;
- }
- }
- }
- inline unsigned GeodesicAlgorithmExact::compute_propagated_parameters(double pseudo_x,
- double pseudo_y,
- double d, //parameters of the interval
- double begin,
- double end, //start/end of the interval
- double alpha, //corner angle
- double L, //length of the new edge
- bool first_interval, //if it is the first interval on the edge
- bool last_interval,
- bool turn_left,
- bool turn_right,
- IntervalWithStop* candidates) //if it is the last interval on the edge
- {
- assert(pseudo_y<=0.0);
- assert(d<GEODESIC_INF/10.0);
- assert(begin<=end);
- assert(first_interval ? (begin == 0.0) : true);
- IntervalWithStop* p = candidates;
- if(std::abs(pseudo_y) <= 1e-30) //pseudo-source is on the edge
- {
- if(first_interval && pseudo_x <= 0.0)
- {
- p->start() = 0.0;
- p->stop() = L;
- p->d() = d - pseudo_x;
- p->pseudo_x() = 0.0;
- p->pseudo_y() = 0.0;
- return 1;
- }
- else if(last_interval && pseudo_x >= end)
- {
- p->start() = 0.0;
- p->stop() = L;
- p->d() = d + pseudo_x-end;
- p->pseudo_x() = end*cos(alpha);
- p->pseudo_y() = -end*sin(alpha);
- return 1;
- }
- else if(pseudo_x >= begin && pseudo_x <= end)
- {
- p->start() = 0.0;
- p->stop() = L;
- p->d() = d;
- p->pseudo_x() = pseudo_x*cos(alpha);
- p->pseudo_y() = -pseudo_x*sin(alpha);
- return 1;
- }
- else
- {
- return 0;
- }
- }
- double sin_alpha = sin(alpha);
- double cos_alpha = cos(alpha);
- //important: for the first_interval, this function returns zero only if the new edge is "visible" from the source
- //if the new edge can be covered only after turn_over, the value is negative (-1.0)
- double L1 = compute_positive_intersection(begin,
- pseudo_x,
- pseudo_y,
- sin_alpha,
- cos_alpha);
- if(L1 < 0 || L1 >= L)
- {
- if(first_interval && turn_left)
- {
- p->start() = 0.0;
- p->stop() = L;
- p->d() = d + sqrt(pseudo_x*pseudo_x + pseudo_y*pseudo_y);
- p->pseudo_y() = 0.0;
- p->pseudo_x() = 0.0;
- return 1;
- }
- else
- {
- return 0;
- }
- }
- double L2 = compute_positive_intersection(end,
- pseudo_x,
- pseudo_y,
- sin_alpha,
- cos_alpha);
- if(L2 < 0 || L2 >= L)
- {
- p->start() = L1;
- p->stop() = L;
- p->d() = d;
- p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y;
- p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y;
- return 1;
- }
- p->start() = L1;
- p->stop() = L2;
- p->d() = d;
- p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y;
- p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y;
- assert(p->pseudo_y() <= 0.0);
- if(!(last_interval && turn_right))
- {
- return 1;
- }
- else
- {
- p = candidates + 1;
- p->start() = L2;
- p->stop() = L;
- double dx = pseudo_x - end;
- p->d() = d + sqrt(dx*dx + pseudo_y*pseudo_y);
- p->pseudo_x() = end*cos_alpha;
- p->pseudo_y() = -end*sin_alpha;
- return 2;
- }
- }
- inline void GeodesicAlgorithmExact::construct_propagated_intervals(bool invert,
- edge_pointer edge,
- face_pointer face, //constructs iNew from the rest of the data
- IntervalWithStop* candidates,
- unsigned& num_candidates,
- interval_pointer source_interval) //up to two candidates
- {
- double edge_length = edge->length();
- double local_epsilon = SMALLEST_INTERVAL_RATIO * edge_length;
- //kill very small intervals in order to avoid precision problems
- if(num_candidates == 2)
- {
- double start = std::min(candidates->start(), (candidates+1)->start());
- double stop = std::max(candidates->stop(), (candidates+1)->stop());
- if(candidates->stop()-candidates->start() < local_epsilon) // kill interval 0
- {
- *candidates = *(candidates+1);
- num_candidates = 1;
- candidates->start() = start;
- candidates->stop() = stop;
- }
- else if ((candidates+1)->stop() - (candidates+1)->start() < local_epsilon)
- {
- num_candidates = 1;
- candidates->start() = start;
- candidates->stop() = stop;
- }
- }
- IntervalWithStop* first;
- IntervalWithStop* second;
- if(num_candidates == 1)
- {
- first = candidates;
- second = candidates;
- }
- else
- {
- if(candidates->start() <= (candidates+1)->start())
- {
- first = candidates;
- second = candidates+1;
- }
- else
- {
- first = candidates+1;
- second = candidates;
- }
- assert(first->stop() == second->start());
- }
- if(first->start() < local_epsilon)
- {
- first->start() = 0.0;
- }
- if(edge_length - second->stop() < local_epsilon)
- {
- second->stop() = edge_length;
- }
- //invert intervals if necessary; fill missing data and set pointers correctly
- Interval::DirectionType direction = edge->adjacent_faces()[0]->id() == face->id() ?
- Interval::FROM_FACE_0 :
- Interval::FROM_FACE_1;
- if(!invert) //in this case everything is straighforward, we do not have to invert the intervals
- {
- for(unsigned i=0; i<num_candidates; ++i)
- {
- IntervalWithStop* p = candidates + i;
- p->next() = (i == num_candidates - 1) ? NULL : candidates + i + 1;
- p->edge() = edge;
- p->direction() = direction;
- p->source_index() = source_interval->source_index();
- p->min() = 0.0; //it will be changed later on
- assert(p->start() < p->stop());
- }
- }
- else //now we have to invert the intervals
- {
- for(unsigned i=0; i<num_candidates; ++i)
- {
- IntervalWithStop* p = candidates + i;
- p->next() = (i == 0) ? NULL : candidates + i - 1;
- p->edge() = edge;
- p->direction() = direction;
- p->source_index() = source_interval->source_index();
- double length = edge_length;
- p->pseudo_x() = length - p->pseudo_x();
- double start = length - p->stop();
- p->stop() = length - p->start();
- p->start() = start;
- p->min() = 0;
- assert(p->start() < p->stop());
- assert(p->start() >= 0.0);
- assert(p->stop() <= edge->length());
- }
- }
- }
- inline unsigned GeodesicAlgorithmExact::best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source
- double& best_source_distance)
- {
- double best_interval_position;
- unsigned best_source_index;
- best_first_interval(point,
- best_source_distance,
- best_interval_position,
- best_source_index);
- return best_source_index;
- }
- inline interval_pointer GeodesicAlgorithmExact::best_first_interval(SurfacePoint& point,
- double& best_total_distance,
- double& best_interval_position,
- unsigned& best_source_index)
- {
- assert(point.type() != UNDEFINED_POINT);
- interval_pointer best_interval = NULL;
- best_total_distance = GEODESIC_INF;
- if(point.type() == EDGE)
- {
- edge_pointer e = static_cast<edge_pointer>(point.base_element());
- list_pointer list = interval_list(e);
- best_interval_position = point.distance(e->v0());
- best_interval = list->covering_interval(best_interval_position);
- if(best_interval)
- {
- //assert(best_interval && best_interval->d() < GEODESIC_INF);
- best_total_distance = best_interval->signal(best_interval_position);
- best_source_index = best_interval->source_index();
- }
- }
- else if(point.type() == FACE)
- {
- face_pointer f = static_cast<face_pointer>(point.base_element());
- for(unsigned i=0; i<3; ++i)
- {
- edge_pointer e = f->adjacent_edges()[i];
- list_pointer list = interval_list(e);
- double offset;
- double distance;
- interval_pointer interval;
- list->find_closest_point(&point,
- offset,
- distance,
- interval);
- if(interval && distance < best_total_distance)
- {
- best_interval = interval;
- best_total_distance = distance;
- best_interval_position = offset;
- best_source_index = interval->source_index();
- }
- }
- //check for all sources that might be located inside this face
- SortedSources::sorted_iterator_pair local_sources = m_sources.sources(f);
- for(SortedSources::sorted_iterator it=local_sources.first; it != local_sources.second; ++it)
- {
- SurfacePointWithIndex* source = *it;
- double distance = point.distance(source);
- if(distance < best_total_distance)
- {
- best_interval = NULL;
- best_total_distance = distance;
- best_interval_position = 0.0;
- best_source_index = source->index();
- }
- }
- }
- else if(point.type() == VERTEX)
- {
- vertex_pointer v = static_cast<vertex_pointer>(point.base_element());
- for(unsigned i=0; i<v->adjacent_edges().size(); ++i)
- {
- edge_pointer e = v->adjacent_edges()[i];
- list_pointer list = interval_list(e);
- double position = e->v0()->id() == v->id() ? 0.0 : e->length();
- interval_pointer interval = list->covering_interval(position);
- if(interval)
- {
- double distance = interval->signal(position);
- if(distance < best_total_distance)
- {
- best_interval = interval;
- best_total_distance = distance;
- best_interval_position = position;
- best_source_index = interval->source_index();
- }
- }
- }
- }
- if(best_total_distance > m_propagation_distance_stopped) //result is unreliable
- {
- best_total_distance = GEODESIC_INF;
- return NULL;
- }
- else
- {
- return best_interval;
- }
- }
- inline void GeodesicAlgorithmExact::trace_back(SurfacePoint& destination, //trace back piecewise-linear path
- std::vector<SurfacePoint>& path)
- {
- path.clear();
- double best_total_distance;
- double best_interval_position;
- unsigned source_index = std::numeric_limits<unsigned>::max();
- interval_pointer best_interval = best_first_interval(destination,
- best_total_distance,
- best_interval_position,
- source_index);
- if(best_total_distance >= GEODESIC_INF/2.0) //unable to find the right path
- {
- return;
- }
- path.push_back(destination);
- if(best_interval) //if we did not hit the face source immediately
- {
- std::vector<edge_pointer> possible_edges;
- possible_edges.reserve(10);
- while(visible_from_source(path.back()) < 0) //while this point is not in the direct visibility of some source (if we are inside the FACE, we obviously hit the source)
- {
- SurfacePoint& q = path.back();
- possible_traceback_edges(q, possible_edges);
- interval_pointer interval;
- double total_distance;
- double position;
- best_point_on_the_edge_set(q,
- possible_edges,
- interval,
- total_distance,
- position);
- //std::cout << total_distance + length(path) << std::endl;
- assert(total_distance<GEODESIC_INF);
- source_index = interval->source_index();
- edge_pointer e = interval->edge();
- double local_epsilon = SMALLEST_INTERVAL_RATIO*e->length();
- if(position < local_epsilon)
- {
- path.push_back(SurfacePoint(e->v0()));
- }
- else if(position > e->length()-local_epsilon)
- {
- path.push_back(SurfacePoint(e->v1()));
- }
- else
- {
- double normalized_position = position/e->length();
- path.push_back(SurfacePoint(e, normalized_position));
- }
- }
- }
- SurfacePoint& source = static_cast<SurfacePoint&>(m_sources[source_index]);
- if(path.back().distance(&source) > 0)
- {
- path.push_back(source);
- }
- }
- inline void GeodesicAlgorithmExact::print_statistics()
- {
- GeodesicAlgorithmBase::print_statistics();
- unsigned interval_counter = 0;
- for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
- {
- interval_counter += m_edge_interval_lists[i].number_of_intervals();
- }
- double intervals_per_edge = (double)interval_counter/(double)m_edge_interval_lists.size();
- double memory = m_edge_interval_lists.size()*sizeof(IntervalList) +
- interval_counter*sizeof(Interval);
- std::cout << "uses about " << memory/1e6 << "Mb of memory" <<std::endl;
- std::cout << interval_counter << " total intervals, or "
- << intervals_per_edge << " intervals per edge"
- << std::endl;
- std::cout << "maximum interval queue size is " << m_queue_max_size << std::endl;
- std::cout << "number of interval propagations is " << m_iterations << std::endl;
- }
- } //geodesic
- }
- template <
- typename DerivedV,
- typename DerivedF,
- typename DerivedVS,
- typename DerivedFS,
- typename DerivedVT,
- typename DerivedFT,
- typename DerivedD>
- IGL_INLINE void igl::exact_geodesic(
- const Eigen::MatrixBase<DerivedV> &V,
- const Eigen::MatrixBase<DerivedF> &F,
- const Eigen::MatrixBase<DerivedVS> &VS,
- const Eigen::MatrixBase<DerivedFS> &FS,
- const Eigen::MatrixBase<DerivedVT> &VT,
- const Eigen::MatrixBase<DerivedFT> &FT,
- Eigen::PlainObjectBase<DerivedD> &D)
- {
- assert((V.cols() == 3 || V.cols() == 2) && F.cols() == 3 && "Only support 2D/3D triangle mesh");
- std::vector<typename DerivedV::Scalar> points(V.rows() * 3);
- std::vector<typename DerivedF::Scalar> faces(F.rows() * F.cols());
- for (int i = 0; i < points.size(); i++)
- {
- // Append 0s for 2D input
- points[i] = ((i%3)<2 || V.cols()==3) ? V(i / 3, i % 3) : 0.0;
- }
- for (int i = 0; i < faces.size(); i++)
- {
- faces[i] = F(i / 3, i % 3);
- }
- igl::geodesic::Mesh mesh;
- mesh.initialize_mesh_data(points, faces);
- igl::geodesic::GeodesicAlgorithmExact exact_algorithm(&mesh);
- std::vector<igl::geodesic::SurfacePoint> source;
- source.reserve(VS.rows() + FS.rows());
- // Vertex sources
- for(int i = 0;i < VS.rows(); i++)
- {
- for(int j = 0;j < VS.cols(); j++)
- {
- source.emplace_back(&mesh.vertices()[VS(i, j)]);
- }
- }
- // Face Sources
- for(int i = 0;i < FS.rows(); i++)
- {
- for(int j = 0;j < FS.cols(); j++)
- {
- source.emplace_back(&mesh.faces()[FS(i, j)]);
- }
- }
- std::vector<igl::geodesic::SurfacePoint> target;
- target.reserve(VT.rows() + FT.rows());
- //Vertex targets
- for(int i = 0;i < VT.rows(); i++)
- {
- for(int j = 0;j < VT.cols(); j++)
- {
- target.emplace_back(&mesh.vertices()[VT(i, j)]);
- }
- }
- // Face targets
- for(int i = 0;i < FT.rows(); i++)
- {
- for(int j = 0;j < FT.cols(); j++)
- {
- target.emplace_back(&mesh.faces()[FT(i, j)]);
- }
- }
- exact_algorithm.propagate(source);
- std::vector<igl::geodesic::SurfacePoint> path;
- D.resize(target.size());
- for (int i = 0; i < target.size(); i++)
- {
- exact_algorithm.trace_back(target[i], path);
- D(i) = igl::geodesic::length(path);
- }
- }
- #ifdef IGL_STATIC_LIBRARY
- template void igl::exact_geodesic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1>> &);
- #endif
|