Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgspalobjectpositionmanager.cpp - description 00003 --------------------------------- 00004 begin : October 2008 00005 copyright : (C) 2008 by Marco Hugentobler 00006 email : marco dot hugentobler at karto dot baug dot ethz dot ch 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include "qgspalobjectpositionmanager.h" 00019 #include "qgsgeometry.h" 00020 #include "qgspalgeometry.h" 00021 #include "qgsoverlayobject.h" 00022 #include "qgsrendercontext.h" 00023 #include "qgsvectorlayer.h" 00024 #include "qgsvectoroverlay.h" 00025 #include "pal.h" 00026 #include "labelposition.h" 00027 #include "feature.h" 00028 #include "layer.h" 00029 00030 QgsPALObjectPositionManager::QgsPALObjectPositionManager(): mNumberOfLayers( 0 ) 00031 { 00032 00033 } 00034 00035 QgsPALObjectPositionManager::~QgsPALObjectPositionManager() 00036 { 00037 deletePALGeometries(); 00038 } 00039 00040 void QgsPALObjectPositionManager::addLayer( QgsVectorLayer* vl, QList<QgsVectorOverlay*>& overlays ) 00041 { 00042 if ( overlays.size() < 1 ) 00043 { 00044 return; 00045 } 00046 00047 //set arrangement based on vector type 00048 pal::Arrangement labelArrangement; 00049 switch ( vl->geometryType() ) 00050 { 00051 case QGis::Point: 00052 labelArrangement = pal::P_POINT; 00053 break; 00054 case QGis::Line: 00055 labelArrangement = pal::P_LINE; 00056 break; 00057 case QGis::Polygon: 00058 labelArrangement = pal::P_HORIZ; 00059 break; 00060 default: 00061 return; //error 00062 } 00063 00064 pal::Layer* positionLayer = mPositionEngine.addLayer( QString::number( mNumberOfLayers ).toLocal8Bit().data(), -1, -1, labelArrangement, pal::PIXEL, 0.5, true, true, true ); 00065 ++mNumberOfLayers; 00066 00067 if ( !positionLayer ) 00068 { 00069 return; 00070 } 00071 00072 //register the labeling objects in the layer 00073 int objectNr = 0; 00074 QList<QgsVectorOverlay*>::const_iterator overlayIt = overlays.begin(); 00075 for ( ; overlayIt != overlays.end(); ++overlayIt ) 00076 { 00077 if ( !( *overlayIt ) ) 00078 { 00079 continue; 00080 } 00081 00082 QMap<QgsFeatureId, QgsOverlayObject*>* positionObjects = ( *overlayIt )->overlayObjects(); 00083 if ( !positionObjects ) 00084 { 00085 continue; 00086 } 00087 00088 QMap<QgsFeatureId, QgsOverlayObject*>::const_iterator objectIt = positionObjects->begin(); 00089 for ( ; objectIt != positionObjects->end(); ++objectIt ) 00090 { 00091 QgsPALGeometry* palGeom = new QgsPALGeometry( objectIt.value() ); 00092 mPALGeometries.push_back( palGeom ); //insert object into list to delete memory later 00093 char* featureLabel = QString::number( objectNr ).toAscii().data(); 00094 positionLayer->registerFeature( featureLabel, palGeom, objectIt.value()->width(), objectIt.value()->height() ); 00095 ++objectNr; 00096 } 00097 } 00098 } 00099 00100 void QgsPALObjectPositionManager::findObjectPositions( const QgsRenderContext& renderContext, QGis::UnitType unitType ) 00101 { 00102 //trigger label placement 00103 QgsRectangle viewExtent = renderContext.extent(); 00104 //PAL needs projected view extent 00105 if ( renderContext.coordinateTransform() ) 00106 { 00107 viewExtent = renderContext.coordinateTransform()->transformBoundingBox( viewExtent ); 00108 } 00109 double bbox[4]; bbox[0] = viewExtent.xMinimum(); bbox[1] = viewExtent.yMinimum(); bbox[2] = viewExtent.xMaximum(); bbox[3] = viewExtent.yMaximum(); 00110 00111 00112 //set map units 00113 pal::Units mapUnits; 00114 switch ( unitType ) 00115 { 00116 case QGis::Meters: 00117 mapUnits = pal::METER; 00118 break; 00119 00120 case QGis::Feet: 00121 mapUnits = pal::FOOT; 00122 break; 00123 00124 case QGis::Degrees: 00125 mapUnits = pal::DEGREE; 00126 break; 00127 default: 00128 return; 00129 } 00130 00131 mPositionEngine.setMapUnit( mapUnits ); 00132 mPositionEngine.setDpi( renderContext.scaleFactor() * 25.4 ); 00133 00134 std::list<pal::LabelPosition*>* resultLabelList = mPositionEngine.labeller( renderContext.rendererScale(), bbox, NULL, false ); 00135 00136 //and read the positions back to the overlay objects 00137 if ( !resultLabelList ) 00138 { 00139 return; 00140 } 00141 00142 //pal geometry that the current label object refers to 00143 QgsPALGeometry* referredGeometry = 0; 00144 QgsOverlayObject* referredOverlayObject = 0; 00145 pal::FeaturePart* referredPart = 0; 00146 00147 std::list<pal::LabelPosition*>::iterator labelIt = resultLabelList->begin(); 00148 for ( ; labelIt != resultLabelList->end(); ++labelIt ) 00149 { 00150 if ( !*labelIt ) 00151 { 00152 continue; 00153 } 00154 00155 referredPart = ( *labelIt )->getFeaturePart(); 00156 if ( !referredPart ) 00157 { 00158 continue; 00159 } 00160 referredGeometry = dynamic_cast<QgsPALGeometry*>( referredPart->getUserGeometry() ); 00161 if ( !referredGeometry ) 00162 { 00163 continue; 00164 } 00165 referredOverlayObject = referredGeometry->overlayObjectPtr(); 00166 if ( !referredOverlayObject ) 00167 { 00168 continue; 00169 } 00170 00171 pal::LabelPosition* lp = *labelIt; 00172 00173 //QGIS takes the coordinates of the middle points 00174 double x = ( lp->getX( 0 ) + lp->getX( 1 ) + lp->getX( 2 ) + lp->getX( 3 ) ) / 4; 00175 double y = ( lp->getY( 0 ) + lp->getY( 1 ) + lp->getY( 2 ) + lp->getY( 3 ) ) / 4; 00176 referredOverlayObject->addPosition( QgsPoint( x, y ) ); 00177 } 00178 00179 //release memory for QgsPALGeometries 00180 deletePALGeometries(); 00181 } 00182 00183 void QgsPALObjectPositionManager::removeLayers() 00184 { 00185 std::list<pal::Layer*>* layerList = mPositionEngine.getLayers(); 00186 if ( !layerList ) 00187 { 00188 return; 00189 } 00190 00191 //Iterators get invalid if elements are deleted in a std::list 00192 //Therefore we have to get the layer pointers in a first step and remove them in a second 00193 QList<pal::Layer*> layersToRemove; 00194 std::list<pal::Layer*>::iterator layerIt = layerList->begin(); 00195 for ( ; layerIt != layerList->end(); ++layerIt ) 00196 { 00197 layersToRemove.push_back( *layerIt ); 00198 } 00199 00200 QList<pal::Layer*>::iterator removeIt = layersToRemove.begin(); 00201 for ( ; removeIt != layersToRemove.end(); ++removeIt ) 00202 { 00203 mPositionEngine.removeLayer( *removeIt ); 00204 } 00205 } 00206 //Chain, Popmusic tabu chain, Popmusic tabu, Popmusic chain 00207 void QgsPALObjectPositionManager::setPlacementAlgorithm( const QString& algorithmName ) 00208 { 00209 if ( algorithmName == "Popmusic tabu chain" ) 00210 { 00211 mPositionEngine.setSearch( pal::POPMUSIC_TABU_CHAIN ); 00212 } 00213 else if ( algorithmName == "Popmusic tabu" ) 00214 { 00215 mPositionEngine.setSearch( pal::POPMUSIC_TABU ); 00216 } 00217 else if ( algorithmName == "Popmusic chain" ) 00218 { 00219 mPositionEngine.setSearch( pal::POPMUSIC_CHAIN ); 00220 } 00221 else //default is "Chain" 00222 { 00223 mPositionEngine.setSearch( pal::CHAIN ); 00224 } 00225 } 00226 00227 void QgsPALObjectPositionManager::deletePALGeometries() 00228 { 00229 QList<QgsPALGeometry*>::iterator geomIt = mPALGeometries.begin(); 00230 for ( ; geomIt != mPALGeometries.end(); ++geomIt ) 00231 { 00232 delete( *geomIt ); 00233 } 00234 mPALGeometries.clear(); 00235 }