bool LabelPosition::crossesBoundary( PointSet *polygon ) const { if ( !mGeos ) createGeosGeom(); if ( !polygon->mGeos ) polygon->createGeosGeom(); GEOSContextHandle_t geosctxt = geosContext(); try { if ( GEOSPreparedOverlaps_r( geosctxt, polygon->preparedGeom(), mGeos ) == 1 || GEOSPreparedTouches_r( geosctxt, polygon->preparedGeom(), mGeos ) == 1 ) { return true; } else if ( nextPart ) { return nextPart->crossesBoundary( polygon ); } } catch ( GEOSException &e ) { QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); return false; } return false; }
bool LabelPosition::crossesLine( PointSet* line ) const { if ( !mGeos ) createGeosGeom(); if ( !line->mGeos ) line->createGeosGeom(); GEOSContextHandle_t geosctxt = geosContext(); try { if ( GEOSPreparedIntersects_r( geosctxt, line->preparedGeom(), mGeos ) == 1 ) { return true; } else if ( nextPart ) { return nextPart->crossesLine( line ); } } catch ( GEOSException &e ) { QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); return false; } return false; }
bool LabelPosition::isInConflictSinglePart( LabelPosition* lp ) { if ( !mGeos ) createGeosGeom(); if ( !lp->mGeos ) lp->createGeosGeom(); GEOSContextHandle_t geosctxt = geosContext(); bool result = ( GEOSPreparedIntersects_r( geosctxt, preparedGeom(), lp->mGeos ) == 1 ); return result; }
int LabelPosition::polygonIntersectionCost( PointSet *polygon ) const { if ( !mGeos ) createGeosGeom(); if ( !polygon->mGeos ) polygon->createGeosGeom(); GEOSContextHandle_t geosctxt = geosContext(); int cost = 0; //check the label center. if covered by polygon, initial cost of 4 if ( polygon->containsPoint(( x[0] + x[2] ) / 2.0, ( y[0] + y[2] ) / 2.0 ) ) cost += 4; try { //calculate proportion of label candidate which is covered by polygon GEOSGeometry* intersectionGeom = GEOSIntersection_r( geosctxt, mGeos, polygon->mGeos ); if ( !intersectionGeom ) return cost; double positionArea = 0; if ( GEOSArea_r( geosctxt, mGeos, &positionArea ) != 1 ) { GEOSGeom_destroy_r( geosctxt, intersectionGeom ); return cost; } double intersectionArea = 0; if ( GEOSArea_r( geosctxt, intersectionGeom, &intersectionArea ) != 1 ) { intersectionArea = 0; } GEOSGeom_destroy_r( geosctxt, intersectionGeom ); double portionCovered = intersectionArea / positionArea; cost += ceil( portionCovered * 8.0 ); //cost of 8 if totally covered return cost; } catch ( GEOSException &e ) { QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); return cost; } }
QLinkedList<const GEOSGeometry *>* pal::Util::unmulti( const GEOSGeometry *the_geom ) { QLinkedList<const GEOSGeometry*> *queue = new QLinkedList<const GEOSGeometry*>; QLinkedList<const GEOSGeometry*> *final_queue = new QLinkedList<const GEOSGeometry*>; const GEOSGeometry *geom; queue->append( the_geom ); int nGeom; int i; GEOSContextHandle_t geosctxt = geosContext(); while ( !queue->isEmpty() ) { geom = queue->takeFirst(); int type = GEOSGeomTypeId_r( geosctxt, geom ); switch ( type ) { case GEOS_MULTIPOINT: case GEOS_MULTILINESTRING: case GEOS_MULTIPOLYGON: nGeom = GEOSGetNumGeometries_r( geosctxt, geom ); for ( i = 0; i < nGeom; i++ ) { queue->append( GEOSGetGeometryN_r( geosctxt, geom, i ) ); } break; case GEOS_POINT: case GEOS_LINESTRING: case GEOS_POLYGON: final_queue->append( geom ); break; default: QgsDebugMsg( QString( "unexpected geometry type:%1" ).arg( type ) ); delete final_queue; delete queue; return nullptr; } } delete queue; return final_queue; }
bool LabelPosition::isInConflictSinglePart( LabelPosition* lp ) { if ( !mGeos ) createGeosGeom(); if ( !lp->mGeos ) lp->createGeosGeom(); GEOSContextHandle_t geosctxt = geosContext(); try { bool result = ( GEOSPreparedIntersects_r( geosctxt, preparedGeom(), lp->mGeos ) == 1 ); return result; } catch ( GEOSException &e ) { QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) ); return false; } }
bool LabelPosition::crossesLine( PointSet* line ) const { if ( !mGeos ) createGeosGeom(); if ( !line->mGeos ) line->createGeosGeom(); GEOSContextHandle_t geosctxt = geosContext(); if ( GEOSPreparedIntersects_r( geosctxt, line->preparedGeom(), mGeos ) == 1 ) { return true; } else if ( nextPart ) { return nextPart->crossesLine( line ); } return false; }
QLinkedList<const GEOSGeometry *> *unmulti( const GEOSGeometry *the_geom ) { QLinkedList<const GEOSGeometry*> *queue = new QLinkedList<const GEOSGeometry*>; QLinkedList<const GEOSGeometry*> *final_queue = new QLinkedList<const GEOSGeometry*>; const GEOSGeometry *geom; queue->append( the_geom ); int nGeom; int i; while ( !queue->isEmpty() ) { geom = queue->takeFirst(); GEOSContextHandle_t geosctxt = geosContext(); switch ( GEOSGeomTypeId_r( geosctxt, geom ) ) { case GEOS_MULTIPOINT: case GEOS_MULTILINESTRING: case GEOS_MULTIPOLYGON: nGeom = GEOSGetNumGeometries_r( geosctxt, geom ); for ( i = 0; i < nGeom; i++ ) { queue->append( GEOSGetGeometryN_r( geosctxt, geom, i ) ); } break; case GEOS_POINT: case GEOS_LINESTRING: case GEOS_POLYGON: final_queue->append( geom ); break; default: delete final_queue; delete queue; return NULL; } } delete queue; return final_queue; }
bool LabelPosition::crossesBoundary( PointSet *polygon ) const { if ( !mGeos ) createGeosGeom(); if ( !polygon->mGeos ) polygon->createGeosGeom(); GEOSContextHandle_t geosctxt = geosContext(); if ( GEOSPreparedOverlaps_r( geosctxt, polygon->preparedGeom(), mGeos ) == 1 || GEOSPreparedTouches_r( geosctxt, polygon->preparedGeom(), mGeos ) == 1 ) { return true; } else if ( nextPart ) { return nextPart->crossesBoundary( polygon ); } return false; }
void Layer::chopFeaturesAtRepeatDistance() { GEOSContextHandle_t geosctxt = geosContext(); QLinkedList<FeaturePart*> * newFeatureParts = new QLinkedList<FeaturePart*>; while ( !featureParts->isEmpty() ) { FeaturePart* fpart = featureParts->takeFirst(); const GEOSGeometry* geom = fpart->geos(); double chopInterval = fpart->getFeature()->repeatDistance(); if ( chopInterval != 0. && GEOSGeomTypeId_r( geosctxt, geom ) == GEOS_LINESTRING ) { double bmin[2], bmax[2]; fpart->getBoundingBox( bmin, bmax ); rtree->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; std::vector<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 ( std::size_t 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->getFeature(), newgeom ); newFeatureParts->append( newfpart ); newfpart->getBoundingBox( bmin, bmax ); rtree->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 ( std::size_t 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->getFeature(), newgeom ); newFeatureParts->append( newfpart ); newfpart->getBoundingBox( bmin, bmax ); rtree->Insert( bmin, bmax, newfpart ); } else { newFeatureParts->append( fpart ); } } delete featureParts; featureParts = newFeatureParts; }
bool Layer::registerFeature( const QString& geom_id, PalGeometry *userGeom, double label_x, double label_y, const QString &labelText, double labelPosX, double labelPosY, bool fixedPos, double angle, bool fixedAngle, int xQuadOffset, int yQuadOffset, double xOffset, double yOffset, bool alwaysShow, double repeatDistance ) { if ( geom_id.isEmpty() || label_x < 0 || label_y < 0 ) return false; mMutex.lock(); if ( hashtable->contains( geom_id ) ) { mMutex.unlock(); //A feature with this id already exists. Don't throw an exception as sometimes, //the same feature is added twice (dateline split with otf-reprojection) return false; } // Split MULTI GEOM and Collection in simple geometries const GEOSGeometry *the_geom = userGeom->getGeosGeometry(); Feature* f = new Feature( this, geom_id, userGeom, label_x, label_y ); if ( fixedPos ) { f->setFixedPosition( labelPosX, labelPosY ); } if ( xQuadOffset != 0 || yQuadOffset != 0 ) { f->setQuadOffset( xQuadOffset, yQuadOffset ); } if ( xOffset != 0.0 || yOffset != 0.0 ) { f->setPosOffset( xOffset, yOffset ); } if ( fixedAngle ) { f->setFixedAngle( angle ); } // use layer-level defined rotation, but not if position fixed if ( !fixedPos && angle != 0.0 ) { f->setFixedAngle( angle ); } f->setRepeatDistance( repeatDistance ); f->setAlwaysShow( alwaysShow ); bool first_feat = true; double geom_size = -1, biggest_size = -1; FeaturePart* biggest_part = NULL; // break the (possibly multi-part) geometry into simple geometries QLinkedList<const GEOSGeometry*>* simpleGeometries = unmulti( the_geom ); if ( simpleGeometries == NULL ) // unmulti() failed? { mMutex.unlock(); throw InternalException::UnknownGeometry(); } GEOSContextHandle_t geosctxt = geosContext(); while ( simpleGeometries->size() > 0 ) { const GEOSGeometry* geom = simpleGeometries->takeFirst(); // ignore invalid geometries (e.g. polygons with self-intersecting rings) if ( GEOSisValid_r( geosctxt, geom ) != 1 ) // 0=invalid, 1=valid, 2=exception { // std::cerr << "ignoring invalid feature " << geom_id << std::endl; continue; } int type = GEOSGeomTypeId_r( geosctxt, geom ); if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON ) { mMutex.unlock(); throw InternalException::UnknownGeometry(); } FeaturePart* fpart = new FeaturePart( f, geom ); // ignore invalid geometries if (( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) || ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) ) { delete fpart; continue; } // polygons: reorder coordinates if ( type == GEOS_POLYGON && reorderPolygon( fpart->nbPoints, fpart->x, fpart->y ) != 0 ) { delete fpart; continue; } if ( mMode == LabelPerFeature && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) ) { if ( type == GEOS_LINESTRING ) GEOSLength_r( geosctxt, geom, &geom_size ); else if ( type == GEOS_POLYGON ) GEOSArea_r( geosctxt, geom, &geom_size ); if ( geom_size > biggest_size ) { biggest_size = geom_size; delete biggest_part; // safe with NULL part biggest_part = fpart; } continue; // don't add the feature part now, do it later // TODO: we should probably add also other parts to act just as obstacles } // feature part is ready! addFeaturePart( fpart, labelText ); first_feat = false; } delete simpleGeometries; userGeom->releaseGeosGeometry( the_geom ); mMutex.unlock(); // if using only biggest parts... if (( mMode == LabelPerFeature || f->fixedPosition() ) && biggest_part != NULL ) { addFeaturePart( biggest_part, labelText ); first_feat = false; } // add feature to layer if we have added something if ( !first_feat ) { features->append( f ); hashtable->insert( geom_id, f ); } else { delete f; } return !first_feat; // true if we've added something }