[QGIS Commit] r11293 - in branches/symbology-ng-branch/src:
core/pal plugins/labeling
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Sat Aug 8 19:41:34 EDT 2009
Author: wonder
Date: 2009-08-08 19:41:33 -0400 (Sat, 08 Aug 2009)
New Revision: 11293
Modified:
branches/symbology-ng-branch/src/core/pal/feature.cpp
branches/symbology-ng-branch/src/core/pal/feature.h
branches/symbology-ng-branch/src/core/pal/layer.cpp
branches/symbology-ng-branch/src/core/pal/layer.h
branches/symbology-ng-branch/src/core/pal/pal.cpp
branches/symbology-ng-branch/src/core/pal/pointset.cpp
branches/symbology-ng-branch/src/core/pal/pointset.h
branches/symbology-ng-branch/src/plugins/labeling/labelinggui.cpp
branches/symbology-ng-branch/src/plugins/labeling/labelingguibase.ui
branches/symbology-ng-branch/src/plugins/labeling/pallabeling.cpp
branches/symbology-ng-branch/src/plugins/labeling/pallabeling.h
Log:
Added possibility to merge adjacent lines with the same label text so they're labeled only once.
Modified: branches/symbology-ng-branch/src/core/pal/feature.cpp
===================================================================
--- branches/symbology-ng-branch/src/core/pal/feature.cpp 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/core/pal/feature.cpp 2009-08-08 23:41:33 UTC (rev 11293)
@@ -77,6 +77,10 @@
FeaturePart::FeaturePart( Feature *feat, const GEOSGeometry* geom )
: f(feat), nbHoles(0), holes(NULL)
{
+ // we'll remove const, but we won't modify that geometry
+ the_geom = const_cast<GEOSGeometry*>(geom);
+ ownsGeom = false; // geometry is owned by Feature class
+
extractCoords(geom);
holeOf = NULL;
@@ -98,6 +102,12 @@
delete [] holes;
holes = NULL;
}
+
+ if (ownsGeom)
+ {
+ GEOSGeom_destroy(the_geom);
+ the_geom = NULL;
+ }
}
@@ -581,7 +591,7 @@
#endif
if ( f->layer->arrangement == P_LINE )
{
- std::cout << alpha*180/M_PI << std::endl;
+ //std::cout << alpha*180/M_PI << std::endl;
if ( flags & FLAG_MAP_ORIENTATION )
reversed = ( alpha >= M_PI/2 || alpha < -M_PI/2 );
@@ -1260,5 +1270,36 @@
}
+ bool FeaturePart::isConnected(FeaturePart* p2)
+ {
+ return (GEOSTouches(the_geom, p2->the_geom) == 1);
+ }
+ bool FeaturePart::mergeWithFeaturePart(FeaturePart* other)
+ {
+ GEOSGeometry* g1 = GEOSGeom_clone(the_geom);
+ GEOSGeometry* g2 = GEOSGeom_clone(other->the_geom);
+ GEOSGeometry* geoms[2] = { g1, g2 };
+ GEOSGeometry* g = GEOSGeom_createCollection(GEOS_MULTILINESTRING, geoms, 2);
+ GEOSGeometry* gTmp = GEOSLineMerge(g);
+ GEOSGeom_destroy(g);
+
+ if (GEOSGeomTypeId(gTmp) != GEOS_LINESTRING)
+ {
+ // sometimes it's not possible to merge lines (e.g. they don't touch at endpoints)
+ GEOSGeom_destroy(gTmp);
+ return false;
+ }
+
+ if (ownsGeom) // delete old geometry if we own it
+ GEOSGeom_destroy(the_geom);
+ // set up new geometry
+ the_geom = gTmp;
+ ownsGeom = true;
+
+ deleteCoords();
+ extractCoords(the_geom);
+ return true;
+ }
+
} // end namespace pal
Modified: branches/symbology-ng-branch/src/core/pal/feature.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/feature.h 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/core/pal/feature.h 2009-08-08 23:41:33 UTC (rev 11293)
@@ -117,6 +117,7 @@
PointSet **holes;
GEOSGeometry *the_geom;
+ bool ownsGeom;
/** \brief read coordinates from a GEOS geom */
void extractCoords( const GEOSGeometry* geom );
@@ -259,6 +260,12 @@
int getNumSelfObstacles() const { return nbHoles; }
PointSet* getSelfObstacle(int i) { return holes[i]; }
+ /** check whether this part is connected with some other part */
+ bool isConnected(FeaturePart* p2);
+
+ /** merge other (connected) part with this one and save the result in this part (other is unchanged).
+ * Return true on success, false if the feature wasn't modified */
+ bool mergeWithFeaturePart(FeaturePart* other);
};
} // end namespace pal
Modified: branches/symbology-ng-branch/src/core/pal/layer.cpp
===================================================================
--- branches/symbology-ng-branch/src/core/pal/layer.cpp 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/core/pal/layer.cpp 2009-08-08 23:41:33 UTC (rev 11293)
@@ -62,7 +62,7 @@
: pal( pal ), obstacle( obstacle ), active( active ),
toLabel( toLabel ), label_unit( label_unit ),
min_scale( min_scale ), max_scale( max_scale ),
- arrangement( arrangement ), arrangementFlags( 0 ), mode(LabelPerFeature)
+ arrangement( arrangement ), arrangementFlags( 0 ), mode(LabelPerFeature), mergeLines(false)
{
this->name = new char[strlen( lyrName ) +1];
@@ -73,6 +73,9 @@
rtree = new RTree<FeaturePart*, double, 2, double>();
hashtable = new HashTable<Feature*> ( 5281 );
+ connectedHashtable = new HashTable< LinkedList<FeaturePart*>* > ( 5391 );
+ connectedTexts = new LinkedList< char* >( strCompare );
+
if ( defaultPriority < 0.0001 )
this->defaultPriority = 0.0001;
else if ( defaultPriority > 1.0 )
@@ -95,8 +98,13 @@
delete featureParts->pop_front();
}
delete featureParts;
+
}
+ // this hashtable and list should be empty if they still exist
+ delete connectedHashtable;
+ double connectedTexts;
+
// features in the hashtable
if ( features )
{
@@ -219,7 +227,7 @@
-bool Layer::registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x, double label_y )
+bool Layer::registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x, double label_y, const char* labelText )
{
if ( !geom_id || label_x < 0 || label_y < 0 )
return false;
@@ -297,7 +305,7 @@
}
// feature part is ready!
- addFeaturePart(fpart);
+ addFeaturePart(fpart, labelText);
first_feat = false;
}
@@ -310,7 +318,7 @@
// if using only biggest parts...
if (mode == LabelPerFeature && biggest_part != NULL)
{
- addFeaturePart(biggest_part);
+ addFeaturePart(biggest_part, labelText);
first_feat = false;
}
@@ -328,7 +336,7 @@
return !first_feat; // true if we've added something
}
-void Layer::addFeaturePart( FeaturePart* fpart )
+void Layer::addFeaturePart( FeaturePart* fpart, const char* labelText )
{
double bmin[2];
double bmax[2];
@@ -339,6 +347,28 @@
// add to r-tree for fast spatial access
rtree->Insert( bmin, bmax, fpart );
+
+ // add to hashtable with equally named feature parts
+ if (mergeLines && labelText)
+ {
+ LinkedList< FeaturePart*>** lstPtr = connectedHashtable->find(labelText);
+ LinkedList< FeaturePart*>* lst;
+ if (lstPtr == NULL)
+ {
+ // entry doesn't exist yet
+ lst = new LinkedList<FeaturePart*>( ptrFeaturePartCompare );
+ connectedHashtable->insertItem(labelText, lst);
+
+ char* txt = new char[strlen(labelText) +1];
+ strcpy(txt, labelText);
+ connectedTexts->push_back(txt);
+ }
+ else
+ {
+ lst = *lstPtr;
+ }
+ lst->push_back(fpart); // add to the list
+ }
}
@@ -354,6 +384,78 @@
}
+static FeaturePart* _findConnectedPart(FeaturePart* partCheck, LinkedList<FeaturePart*>* otherParts)
+{
+ // iterate in the rest of the parts with the same label
+ Cell<FeaturePart*>* p = otherParts->getFirst();
+ while (p)
+ {
+ if (partCheck->isConnected(p->item))
+ {
+ // stop checking for other connected parts
+ return p->item;
+ }
+ p = p->next;
+ }
+ return NULL; // no connected part found...
+}
+
+void Layer::joinConnectedFeatures()
+{
+ // go through all label texts
+ char* labelText;
+ while ( labelText = connectedTexts->pop_front() )
+ {
+ //std::cerr << "JOIN: " << labelText << std::endl;
+ LinkedList<FeaturePart*>** partsPtr = connectedHashtable->find(labelText);
+ if (!partsPtr)
+ continue; // shouldn't happen
+ LinkedList<FeaturePart*>* parts = *partsPtr;
+
+ // go one-by-one part, try to merge
+ while (parts->size())
+ {
+ // part we'll be checking against other in this round
+ FeaturePart* partCheck = parts->pop_front();
+
+ 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);
+
+ 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;
+ *partsPtr = NULL;
+ delete labelText;
+ }
+
+ // we're done processing connected fetures
+ delete connectedHashtable;
+ connectedHashtable = NULL;
+ delete connectedTexts;
+ connectedTexts = NULL;
+}
+
+
+
} // end namespace
Modified: branches/symbology-ng-branch/src/core/pal/layer.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/layer.h 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/core/pal/layer.h 2009-08-08 23:41:33 UTC (rev 11293)
@@ -101,6 +101,7 @@
Arrangement arrangement;
LabelMode mode;
+ bool mergeLines;
/** optional flags used for some placement methods */
unsigned long arrangementFlags;
@@ -109,6 +110,9 @@
RTree<FeaturePart*, double, 2, double, 8, 4> *rtree;
HashTable<Feature*> *hashtable;
+ HashTable< LinkedList<FeaturePart*>* > * connectedHashtable;
+ LinkedList< char* >* connectedTexts;
+
SimpleMutex *modMutex;
/**
@@ -140,7 +144,7 @@
bool isScaleValid( double scale );
/** add newly creted feature part into r tree and to the list */
- void addFeaturePart( FeaturePart* fpart );
+ void addFeaturePart( FeaturePart* fpart, const char* labelText = NULL );
public:
/**
@@ -271,6 +275,9 @@
void setLabelMode( LabelMode m ) { mode = m; }
LabelMode getLabelMode() const { return mode; }
+ void setMergeConnectedLines(bool m) { mergeLines = m; }
+ bool getMergeConnectedLines() const { return mergeLines; }
+
/**
* \brief register a feature in the layer
*
@@ -283,11 +290,14 @@
*
* @return true on success (i.e. valid geometry)
*/
- bool registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x = -1, double label_y = -1 );
+ bool registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x = -1, double label_y = -1, const char* labelText = NULL );
/** return pointer to feature or NULL if doesn't exist */
Feature* getFeature( const char* geom_id );
+ /** join connected features with the same label text */
+ void joinConnectedFeatures();
+
};
} // end namespace pal
Modified: branches/symbology-ng-branch/src/core/pal/pal.cpp
===================================================================
--- branches/symbology-ng-branch/src/core/pal/pal.cpp 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/core/pal/pal.cpp 2009-08-08 23:41:33 UTC (rev 11293)
@@ -500,6 +500,10 @@
// check if this selected layers has been selected by user
if ( strcmp( layersName[i], layer->name ) == 0 )
{
+ // check for connected features with the same label text and join them
+ if (layer->getMergeConnectedLines())
+ layer->joinConnectedFeatures();
+
context->layer = layer;
context->priority = layersFactor[i];
// lookup for feature (and generates candidates list)
Modified: branches/symbology-ng-branch/src/core/pal/pointset.cpp
===================================================================
--- branches/symbology-ng-branch/src/core/pal/pointset.cpp 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/core/pal/pointset.cpp 2009-08-08 23:41:33 UTC (rev 11293)
@@ -136,10 +136,7 @@
PointSet::~PointSet()
{
- if ( x )
- delete[] x;
- if ( y )
- delete[] y;
+ deleteCoords();
if ( status )
delete[] status;
@@ -147,7 +144,17 @@
delete[] cHull;
}
+ void PointSet::deleteCoords()
+ {
+ if ( x )
+ delete[] x;
+ if ( y )
+ delete[] y;
+ x = NULL;
+ y = NULL;
+ }
+
int PointSet::getPath( int start, int stop, int *path_val )
{
int nbPt = 0;
Modified: branches/symbology-ng-branch/src/core/pal/pointset.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/pointset.h 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/core/pal/pointset.h 2009-08-08 23:41:33 UTC (rev 11293)
@@ -115,6 +115,8 @@
PointSet( PointSet &ps );
+ void deleteCoords();
+
double xmin;
double xmax;
double ymin;
Modified: branches/symbology-ng-branch/src/plugins/labeling/labelinggui.cpp
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/labelinggui.cpp 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/plugins/labeling/labelinggui.cpp 2009-08-08 23:41:33 UTC (rev 11293)
@@ -60,6 +60,8 @@
Q_ASSERT(0 && "NOOOO!");
}
+ chkMergeLines->setEnabled(layer->geometryType() == QGis::Line);
+
populateFieldNames();
// load labeling settings from layer
@@ -111,6 +113,7 @@
sliderPriority->setValue( lyr.priority );
chkNoObstacle->setChecked( !lyr.obstacle );
chkLabelPerFeaturePart->setChecked( lyr.labelPerPart );
+ chkMergeLines->setChecked( lyr.mergeLines );
bool scaleBased = (lyr.scaleMin != 0 && lyr.scaleMax != 0);
chkScaleBasedVisibility->setChecked(scaleBased);
@@ -207,6 +210,7 @@
lyr.priority = sliderPriority->value();
lyr.obstacle = !chkNoObstacle->isChecked();
lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
+ lyr.mergeLines = chkMergeLines->isChecked();
if (chkScaleBasedVisibility->isChecked())
{
lyr.scaleMin = spinScaleMin->value();
Modified: branches/symbology-ng-branch/src/plugins/labeling/labelingguibase.ui
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/labelingguibase.ui 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/plugins/labeling/labelingguibase.ui 2009-08-08 23:41:33 UTC (rev 11293)
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>454</width>
- <height>526</height>
+ <width>480</width>
+ <height>610</height>
</rect>
</property>
<property name="windowTitle">
@@ -656,6 +656,13 @@
</widget>
</item>
<item>
+ <widget class="QCheckBox" name="chkMergeLines">
+ <property name="text">
+ <string>merge connected lines to avoid duplicate labels</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="chkNoObstacle">
@@ -663,7 +670,7 @@
<bool>true</bool>
</property>
<property name="text">
- <string>not an obstacle</string>
+ <string>features don't act as obstacles for labels</string>
</property>
</widget>
</item>
Modified: branches/symbology-ng-branch/src/plugins/labeling/pallabeling.cpp
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/pallabeling.cpp 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/plugins/labeling/pallabeling.cpp 2009-08-08 23:41:33 UTC (rev 11293)
@@ -102,6 +102,7 @@
bufferSize = 1;
bufferColor = Qt::white;
labelPerPart = false;
+ mergeLines = false;
}
LayerSettings::LayerSettings(const LayerSettings& s)
@@ -121,6 +122,7 @@
bufferSize = s.bufferSize;
bufferColor = s.bufferColor;
labelPerPart = s.labelPerPart;
+ mergeLines = s.mergeLines;
fontMetrics = NULL;
ct = NULL;
@@ -172,7 +174,8 @@
scaleMax = layer->customProperty("labeling/scaleMax").toInt();
bufferSize = layer->customProperty("labeling/bufferSize").toInt();
bufferColor = _readColor(layer, "labeling/bufferColor");
- labelPerPart = layer->customProperty("labeling/labelPerPart").toInt();
+ labelPerPart = layer->customProperty("labeling/labelPerPart").toBool();
+ mergeLines = layer->customProperty("labeling/mergeLines").toBool();
}
void LayerSettings::writeToLayer(QgsVectorLayer* layer)
@@ -199,6 +202,7 @@
layer->setCustomProperty("labeling/bufferSize", bufferSize);
_writeColor(layer, "labeling/bufferColor", bufferColor);
layer->setCustomProperty("labeling/labelPerPart", labelPerPart);
+ layer->setCustomProperty("labeling/mergeLines", mergeLines);
}
void LayerSettings::calculateLabelSize(QString text, double& labelX, double& labelY)
@@ -228,7 +232,7 @@
geometries.append(lbl);
// register feature to the layer
- if (!palLayer->registerFeature(lbl->strId(), lbl, labelX, labelY))
+ if (!palLayer->registerFeature(lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData()))
return;
// TODO: only for placement which needs character info
@@ -326,6 +330,9 @@
// set label mode (label per feature is the default)
l->setLabelMode( lyr.labelPerPart ? Layer::LabelPerFeaturePart : Layer::LabelPerFeature );
+ // set whether adjacent lines should be merged
+ l->setMergeConnectedLines( lyr.mergeLines );
+
// save the pal layer to our layer context (with some additional info)
lyr.palLayer = l;
lyr.fieldIndex = fldIndex;
Modified: branches/symbology-ng-branch/src/plugins/labeling/pallabeling.h
===================================================================
--- branches/symbology-ng-branch/src/plugins/labeling/pallabeling.h 2009-08-08 18:45:24 UTC (rev 11292)
+++ branches/symbology-ng-branch/src/plugins/labeling/pallabeling.h 2009-08-08 23:41:33 UTC (rev 11293)
@@ -65,6 +65,7 @@
int bufferSize;
QColor bufferColor;
bool labelPerPart; // whether to label every feature's part or only the biggest one
+ bool mergeLines;
// called from register feature hook
void calculateLabelSize(QString text, double& labelX, double& labelY);
More information about the QGIS-commit
mailing list