BOOKS i'm reading |
/* * Module ID: clqtree.cpp * Titre : Definition de la classe ClusteringQuadTree. * Utilite : Structure de donnees inventee par moi-meme pour * resoudre efficacement les problemes de clustering. * Le raisonnement qui a guide le design de cette structure, * c'est qu'il est plus efficace de manipuler une collection * d'objets (dans ce cas ci, ce sont des points) que tous les * objets individuellement. * Les performances sont encore a analyser. * * Auteur : Olivier Langlois (olivier@olivierlanglois.net) * Date : 1 Mars 1998 * * Revision : * * 001 03-Sep-1998 - Olivier Langlois * Modifications pour s'adapter a la nouvelle classe geoVector. */ #include "collect/idlist.h" #include "geo/point.h" #include "geo/segment.h" #include "geo/line.h" #include "geo/polygon.h" #include "geo/clqtree.h" #include "debug.h" #include "../math/mathvec.cpp" DEFINE_COLLECTABLE(ClusteringQuadTree, __CQUADTREE) ClusteringQuadTree::ClusteringQuadTree( IDList &pl, size_t numLvls ) : numEntries(0), levels(numLvls) { if( levels == 1 ) root = new CQTBucketNode( pl ); else root = new CQTNode( pl, levels ); } void ClusteringQuadTree::clear( void ) { if(root) { IDList &pl = const_cast<IDList &>(root->vertices()); root->removeReference(); numEntries = 0; if( levels == 1 ) root = new CQTBucketNode( pl ); else root = new CQTNode( pl, levels ); } } ClusteringQuadTree::~ClusteringQuadTree() { if( root && !root->removeReference()) delete root; } /****************************************************************************** * * Nom : splitTree * * Utilite : Construit 2 sous-QuadTree, l'un contenant tous les noeuds * a gauche de la ligne, l'autre tous les noeud a droite. * * Reference : cqtree.h * ****************************************************************************/ void ClusteringQuadTree::splitTree( const line &l, ClusteringQuadTree **lTree, ClusteringQuadTree **rTree ) { *lTree = new ClusteringQuadTree; *rTree = new ClusteringQuadTree; root->split( l, &(*lTree)->root, &(*rTree)->root ); } /****************************************************************************** * * Nom : insertPoint * * Reference : cqtree.h * ****************************************************************************/ void ClusteringQuadTree::insertPoint( point *p ) { if( root ) { if( root->insertPoint( p ) == BOOL_FALSE ) { D( cout << "Polygon: " << *root; ) D( cout << "Point : " << *p; ) throw CQTreeEx(QTX_INSERT); } else numEntries++; } } CQTNode::CQTNode( IDList &pl, size_t numLvls ) : polygon(pl), moy(NULL) { if( pl.entries() == 4 ) { addReference(); point *p1 = (point *)pl.get(); point *p2 = (point *)pl.get(); point *p3 = (point *)pl.get(); point *p4 = (point *)pl.get(); *p2 = midpoint(*p1, *p2 ); *p4 = midpoint(*p1, *p4 ); mathVector<double> v1 = *p2 - *p1; mathVector<double> v2 = *p4 - *p1; if( segment(*p1,*p2).is_horizontal() == BOOL_TRUE ) *p3 = point( p2->xcoord(), p4->ycoord() ); else *p3 = point( p4->xcoord(), p2->ycoord() ); pl.insert(p1); pl.insert(p2); pl.insert(p3); pl.insert(p4); IDListIterator it(pl); point *pTmp; // Une copie de la liste de points est passee au constructeur des // enfants car eux aussi modifient la liste. if( numLvls > 1 ) { IDList node1PL(pl); node1 = new CQTNode(node1PL, numLvls-1 ); } else node1 = new CQTBucketNode(pl); while( pTmp = (point *)++it ) *pTmp = pTmp->translate(v1); if( numLvls > 1 ) { IDList node2PL(pl); node2 = new CQTNode(node2PL, numLvls-1 ); } else node2 = new CQTBucketNode(pl); it.reset(); while( pTmp = (point *)++it ) *pTmp = pTmp->translate(v2); if( numLvls > 1 ) { IDList node3PL(pl); node3 = new CQTNode(node3PL, numLvls-1 ); } else node3 = new CQTBucketNode(pl); it.reset(); while( pTmp = (point *)++it ) *pTmp = pTmp->translate(-v1); if( numLvls > 1 ) // La liste courante peut etre directement passee au constructeur // du dernier enfant car apres, la liste n'est plus utilisee. node4 = new CQTNode(pl, numLvls-1 ); else node4 = new CQTBucketNode(pl); } else throw CQTreeEx(QTX_LIST_SIZE); } CQTNode::~CQTNode() { if(node1 && !node1->removeReference()) delete node1; if(node2 && !node2->removeReference()) delete node2; if(node3 && !node3->removeReference()) delete node3; if(node4 && !node4->removeReference()) delete node4; delete moy; } Boolean CQTNode::insertPoint( point *p ) { if( inside(*p) == BOOL_TRUE || contains(*p) == BOOL_TRUE ) { if( !moy ) moy = new point(*p); else *moy = midpoint(*moy, *p); // Le point ne peut etre insere que dans un seul bucket if( node1->insertPoint(p) == BOOL_FALSE ) if( node2->insertPoint(p) == BOOL_FALSE ) if( node3->insertPoint(p) == BOOL_FALSE ) if( node4->insertPoint(p) == BOOL_FALSE ) { D( cout << "Polygon: " << *this; ) D( cout << "node1 : " << *node1; ) D( cout << "node2 : " << *node2; ) D( cout << "node3 : " << *node3; ) D( cout << "node4 : " << *node4; ) D( cout << "Point : " << *p; ) throw CQTreeEx(QTX_INSERT); } return BOOL_TRUE; } else return BOOL_FALSE; } void CQTNode::calculateMoy() { if( node1->moy ) { if( moy ) *moy = midpoint( *moy, *node1->moy ); else moy = new point(*node1->moy ); } if( node2->moy ) { if( moy ) *moy = midpoint( *moy, *node2->moy ); else moy = new point(*node2->moy ); } if( node3->moy ) { if( moy ) *moy = midpoint( *moy, *node3->moy ); else moy = new point(*node3->moy ); } if( node4->moy ) { if( moy ) *moy = midpoint( *moy, *node4->moy ); else moy = new point(*node4->moy ); } } void CQTNode::split( const line &l, CQTNode **lNode, CQTNode **rNode ) { const IDList &pl = vertices(); if( moy && (intersection(l).isEmpty() == BOOL_FALSE) ) { // On doit 'splitter' encore plus *lNode = new CQTNode(IDList(pl)); *rNode = new CQTNode(const_cast< IDList & >(pl)); node1->split( l, &(*lNode)->node1, &(*rNode)->node1 ); node2->split( l, &(*lNode)->node2, &(*rNode)->node2 ); node3->split( l, &(*lNode)->node3, &(*rNode)->node3 ); node4->split( l, &(*lNode)->node4, &(*rNode)->node4 ); (*lNode)->calculateMoy(); (*rNode)->calculateMoy(); } // Sinon le noeud se trouve soit a gauche ou a droite de la ligne. else { addReference(); if( left_turn(l.point1(), l.point2(), *(point *)pl.first()) == BOOL_TRUE ) { *lNode = this; *rNode = new CQTBucketNode(pl); } else { *lNode = new CQTBucketNode(pl); *rNode = this; } } } Boolean CQTBucketNode::insertPoint( point *p ) { if( inside(*p) == BOOL_TRUE || contains(*p) == BOOL_TRUE ) { if( !moy ) moy = new point(*p); else *moy = midpoint(*moy, *p); pointList.insert(p); return BOOL_TRUE; } else return BOOL_FALSE; } void CQTBucketNode::split( const line &l, CQTNode **lNode, CQTNode **rNode ) { const IDList &pl = vertices(); if( moy && (intersection(l).isEmpty() == BOOL_FALSE) ) { // On doit 'splitter' encore plus *lNode = new CQTBucketNode(IDList(pl)); *rNode = new CQTBucketNode(pl); IDListIterator it(pointList); point *p; while( p = (point *)++it ) { if( left_turn( l.point1(), l.point2(), *p ) == BOOL_TRUE ) { (*lNode)->insertPoint( new point(*p) ); } else { (*rNode)->insertPoint( new point(*p) ); } } } // Sinon le noeud se trouve soit a gauche ou a droite de la ligne. else { addReference(); if( left_turn(l.point1(), l.point2(), *(point *)pl.first()) == BOOL_TRUE ) { *lNode = this; *rNode = new CQTBucketNode(pl); } else { *lNode = new CQTBucketNode(pl); *rNode = this; } } } |