void Layer::joinConnectedFeatures() { // go through all label texts QString labelText; while ( !connectedTexts->isEmpty() ) { labelText = connectedTexts->takeFirst(); //std::cerr << "JOIN: " << labelText << std::endl; QHash< QString, QLinkedList<FeaturePart*>* >::const_iterator partsPtr = connectedHashtable->find( labelText ); if ( partsPtr == connectedHashtable->constEnd() ) continue; // shouldn't happen QLinkedList<FeaturePart*>* parts = *partsPtr; // go one-by-one part, try to merge while ( !parts->isEmpty() ) { // part we'll be checking against other in this round FeaturePart* partCheck = parts->takeFirst(); FeaturePart* otherPart = _findConnectedPart( partCheck, parts ); if ( otherPart ) { //std::cerr << "- connected " << partCheck << " with " << otherPart << std::endl; // remove partCheck from r-tree double bmin[2], bmax[2]; partCheck->getBoundingBox( bmin, bmax ); rtree->Remove( bmin, bmax, partCheck ); featureParts->removeOne( partCheck ); otherPart->getBoundingBox( bmin, bmax ); // merge points from partCheck to p->item if ( otherPart->mergeWithFeaturePart( partCheck ) ) { // reinsert p->item to r-tree (probably not needed) rtree->Remove( bmin, bmax, otherPart ); otherPart->getBoundingBox( bmin, bmax ); rtree->Insert( bmin, bmax, otherPart ); } } } // we're done processing feature parts with this particular label text delete parts; } // we're done processing connected fetures delete connectedHashtable; connectedHashtable = NULL; delete connectedTexts; connectedTexts = NULL; }
void Layer::chopFeaturesAtRepeatDistance() { GEOSContextHandle_t geosctxt = geosContext(); QLinkedList<FeaturePart*> newFeatureParts; while ( !mFeatureParts.isEmpty() ) { FeaturePart* fpart = mFeatureParts.takeFirst(); const GEOSGeometry* geom = fpart->geos(); double chopInterval = fpart->repeatDistance(); if ( chopInterval != 0. && GEOSGeomTypeId_r( geosctxt, geom ) == GEOS_LINESTRING ) { chopInterval *= ceil( fpart->getLabelWidth() / fpart->repeatDistance() ); double bmin[2], bmax[2]; fpart->getBoundingBox( bmin, bmax ); mFeatureIndex->Remove( bmin, bmax, fpart ); const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosctxt, geom ); // get number of points unsigned int n; GEOSCoordSeq_getSize_r( geosctxt, cs, &n ); // Read points std::vector<Point> points( n ); for ( unsigned int i = 0; i < n; ++i ) { GEOSCoordSeq_getX_r( geosctxt, cs, i, &points[i].x ); GEOSCoordSeq_getY_r( geosctxt, cs, i, &points[i].y ); } // Cumulative length vector std::vector<double> len( n, 0 ); for ( unsigned int i = 1; i < n; ++i ) { double dx = points[i].x - points[i - 1].x; double dy = points[i].y - points[i - 1].y; len[i] = len[i - 1] + std::sqrt( dx * dx + dy * dy ); } // Walk along line unsigned int cur = 0; double lambda = 0; QVector<Point> part; for ( ;; ) { lambda += chopInterval; for ( ; cur < n && lambda > len[cur]; ++cur ) { part.push_back( points[cur] ); } if ( cur >= n ) { break; } double c = ( lambda - len[cur - 1] ) / ( len[cur] - len[cur - 1] ); Point p; p.x = points[cur - 1].x + c * ( points[cur].x - points[cur - 1].x ); p.y = points[cur - 1].y + c * ( points[cur].y - points[cur - 1].y ); part.push_back( p ); GEOSCoordSequence* cooSeq = GEOSCoordSeq_create_r( geosctxt, part.size(), 2 ); for ( int i = 0; i < part.size(); ++i ) { GEOSCoordSeq_setX_r( geosctxt, cooSeq, i, part[i].x ); GEOSCoordSeq_setY_r( geosctxt, cooSeq, i, part[i].y ); } GEOSGeometry* newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq ); FeaturePart* newfpart = new FeaturePart( fpart->feature(), newgeom ); newFeatureParts.append( newfpart ); newfpart->getBoundingBox( bmin, bmax ); mFeatureIndex->Insert( bmin, bmax, newfpart ); part.clear(); part.push_back( p ); } // Create final part part.push_back( points[n - 1] ); GEOSCoordSequence* cooSeq = GEOSCoordSeq_create_r( geosctxt, part.size(), 2 ); for ( int i = 0; i < part.size(); ++i ) { GEOSCoordSeq_setX_r( geosctxt, cooSeq, i, part[i].x ); GEOSCoordSeq_setY_r( geosctxt, cooSeq, i, part[i].y ); } GEOSGeometry* newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq ); FeaturePart* newfpart = new FeaturePart( fpart->feature(), newgeom ); newFeatureParts.append( newfpart ); newfpart->getBoundingBox( bmin, bmax ); mFeatureIndex->Insert( bmin, bmax, newfpart ); delete fpart; } else { newFeatureParts.append( fpart ); } } mFeatureParts = newFeatureParts; }
void Layer::joinConnectedFeatures() { // go through all label texts int connectedFeaturesId = 0; Q_FOREACH ( const QString& labelText, mConnectedTexts ) { if ( !mConnectedHashtable.contains( labelText ) ) continue; // shouldn't happen connectedFeaturesId++; QLinkedList<FeaturePart*>* parts = mConnectedHashtable.value( labelText ); // go one-by-one part, try to merge while ( !parts->isEmpty() && parts->count() > 1 ) { // part we'll be checking against other in this round FeaturePart* partCheck = parts->takeFirst(); FeaturePart* otherPart = _findConnectedPart( partCheck, parts ); if ( otherPart ) { // remove partCheck from r-tree double checkpartBMin[2], checkpartBMax[2]; partCheck->getBoundingBox( checkpartBMin, checkpartBMax ); double otherPartBMin[2], otherPartBMax[2]; otherPart->getBoundingBox( otherPartBMin, otherPartBMax ); // merge points from partCheck to p->item if ( otherPart->mergeWithFeaturePart( partCheck ) ) { // remove the parts we are joining from the index mFeatureIndex->Remove( checkpartBMin, checkpartBMax, partCheck ); mFeatureIndex->Remove( otherPartBMin, otherPartBMax, otherPart ); // reinsert merged line to r-tree (probably not needed) otherPart->getBoundingBox( otherPartBMin, otherPartBMax ); mFeatureIndex->Insert( otherPartBMin, otherPartBMax, otherPart ); mConnectedFeaturesIds.insert( partCheck->featureId(), connectedFeaturesId ); mConnectedFeaturesIds.insert( otherPart->featureId(), connectedFeaturesId ); mFeatureParts.removeOne( partCheck ); delete partCheck; } } } // we're done processing feature parts with this particular label text delete parts; mConnectedHashtable.remove( labelText ); } // we're done processing connected features //should be empty, but clear to be safe qDeleteAll( mConnectedHashtable ); mConnectedHashtable.clear(); mConnectedTexts.clear(); }