[QGIS Commit] r11045 - branches/symbology-ng-branch/src/core/pal
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Sat Jul 11 16:06:00 EDT 2009
Author: wonder
Date: 2009-07-11 16:05:59 -0400 (Sat, 11 Jul 2009)
New Revision: 11045
Added:
branches/symbology-ng-branch/src/core/pal/costcalculator.cpp
branches/symbology-ng-branch/src/core/pal/costcalculator.h
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/geomfunction.h
branches/symbology-ng-branch/src/core/pal/labelposition.cpp
branches/symbology-ng-branch/src/core/pal/labelposition.h
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/pal.h
branches/symbology-ng-branch/src/core/pal/pointset.h
branches/symbology-ng-branch/src/core/pal/util.h
Log:
Another round of refactoring.
Moved most of the candidate cost handling code to separate CostCalculator source.
Some more "friend class" removals.
Added: branches/symbology-ng-branch/src/core/pal/costcalculator.cpp
===================================================================
--- branches/symbology-ng-branch/src/core/pal/costcalculator.cpp (rev 0)
+++ branches/symbology-ng-branch/src/core/pal/costcalculator.cpp 2009-07-11 20:05:59 UTC (rev 11045)
@@ -0,0 +1,344 @@
+
+#include <iostream>
+#include <fstream>
+#include <cmath>
+#include <cstring>
+#include <cfloat>
+
+#include <pal/layer.h>
+#include <pal/pal.h>
+#include <pal/label.h>
+
+#include "feature.h"
+#include "geomfunction.h"
+#include "labelposition.h"
+#include "util.h"
+
+#include "costcalculator.h"
+
+namespace pal
+{
+
+ void CostCalculator::addObstacleCostPenalty(LabelPosition* lp, PointSet* feat)
+ {
+ int n = 0;
+ double dist;
+ double distlabel = lp->feature->getLabelDistance();
+ /*unit_convert( double( lp->feature->distlabel ),
+ pal::PIXEL,
+ pal->map_unit,
+ pal->dpi, scale, 1 );*/
+
+ switch ( feat->getGeosType() )
+ {
+ case GEOS_POINT:
+
+ dist = lp->getDistanceToPoint( feat->x[0], feat->y[0] );
+ if ( dist < 0 )
+ n = 2;
+ else if ( dist < distlabel )
+ n = 1;
+ else
+ n = 0;
+ break;
+
+ case GEOS_LINESTRING:
+
+ // Is one of label's borders crossing the line ?
+ n = ( lp->isBorderCrossingLine( feat ) ? 1 : 0 );
+ break;
+
+ case GEOS_POLYGON:
+ n = lp->getNumPointsInPolygon( feat->getNumPoints(), feat->x, feat->y );
+ break;
+ }
+
+ // label cost is penalized
+ lp->setCost( lp->getCost() + double( n ) );
+ }
+
+
+ ////////
+
+ void CostCalculator::setPolygonCandidatesCost( int nblp, LabelPosition **lPos, int max_p, RTree<PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
+ {
+ int i;
+
+ double normalizer;
+ // compute raw cost
+#ifdef _DEBUG_
+ std::cout << "LabelPosition for feat: " << lPos[0]->feature->uid << std::endl;
+#endif
+
+ for ( i = 0;i < nblp;i++ )
+ setCandidateCostFromPolygon( lPos[i], obstacles, bbx, bby );
+
+ // lPos with big values came fisrts (value = min distance from label to Polygon's Perimeter)
+ //sort ( (void**) lPos, nblp, costGrow);
+ sort(( void** ) lPos, nblp, LabelPosition::costShrink );
+
+
+ // define the value's range
+ double cost_max = lPos[0]->getCost();
+ double cost_min = lPos[max_p-1]->getCost();
+
+ cost_max -= cost_min;
+
+ if ( cost_max > EPSILON )
+ {
+ normalizer = 0.0020 / cost_max;
+ }
+ else
+ {
+ normalizer = 1;
+ }
+
+ // adjust cost => the best is 0.0001, the worst is 0.0021
+ // others are set proportionally between best and worst
+ for ( i = 0;i < max_p;i++ )
+ {
+#ifdef _DEBUG_
+ std::cout << " lpos[" << i << "] = " << lPos[i]->cost;
+#endif
+ //if (cost_max - cost_min < EPSILON)
+ if ( cost_max > EPSILON )
+ {
+ lPos[i]->cost = 0.0021 - ( lPos[i]->getCost() - cost_min ) * normalizer;
+ }
+ else
+ {
+ //lPos[i]->cost = 0.0001 + (lPos[i]->cost - cost_min) * normalizer;
+ lPos[i]->cost = 0.0001;
+ }
+
+#ifdef _DEBUG_
+ std::cout << " ==> " << lPos[i]->cost << std::endl;
+#endif
+ }
+ }
+
+
+ void CostCalculator::setCandidateCostFromPolygon( LabelPosition* lp, RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
+ {
+
+ double amin[2];
+ double amax[2];
+
+ PolygonCostCalculator *pCost = new PolygonCostCalculator( lp );
+
+ // center
+ //cost = feat->getDistInside((this->x[0] + this->x[2])/2.0, (this->y[0] + this->y[2])/2.0 );
+
+ lp->feature->fetchCoordinates();
+ pCost->update( lp->feature );
+
+ PointSet *extent = new PointSet( 4, bbx, bby );
+
+ pCost->update( extent );
+
+ delete extent;
+
+ lp->feature->getBoundingBox(amin, amax);
+
+ obstacles->Search( amin, amax, LabelPosition::polygonObstacleCallback, pCost );
+
+ lp->setCost( pCost->getCost() );
+
+ lp->feature->releaseCoordinates();
+ delete pCost;
+ }
+
+
+ int CostCalculator::finalizeCandidatesCosts( Feats* feat, int max_p, RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
+ {
+ // If candidates list is smaller than expected
+ if ( max_p > feat->nblp )
+ max_p = feat->nblp;
+ //
+ // sort candidates list, best label to worst
+ sort(( void** ) feat->lPos, feat->nblp, LabelPosition::costGrow );
+
+ // try to exclude all conflitual labels (good ones have cost < 1 by pruning)
+ double discrim = 0.0;
+ int stop;
+ do
+ {
+ discrim += 1.0;
+ for ( stop = 0;stop < feat->nblp && feat->lPos[stop]->getCost() < discrim;stop++ );
+ }
+ while ( stop == 0 && discrim < feat->lPos[feat->nblp-1]->getCost() + 2.0 );
+
+ if ( discrim > 1.5 )
+ {
+ int k;
+ for ( k = 0;k < stop;k++ )
+ feat->lPos[k]->setCost( 0.0021 );
+ }
+
+ if ( max_p > stop )
+ max_p = stop;
+
+#ifdef _DEBUG_FULL_
+ std::cout << "Nblabel kept for feat " << feat->feature->uid << "/" << feat->feature->layer->name << ": " << max_p << "/" << feat->nblp << std::endl;
+#endif
+
+ // Sets costs for candidates of polygon
+
+ if ( feat->feature->getGeosType() == GEOS_POLYGON )
+ {
+ int arrangement = feat->feature->getLayer()->getArrangement();
+ if ( arrangement == P_FREE || arrangement == P_HORIZ )
+ setPolygonCandidatesCost( stop, feat->lPos, max_p, obstacles, bbx, bby );
+ }
+
+ return max_p;
+ }
+
+
+
+ //////////
+
+ PolygonCostCalculator::PolygonCostCalculator( LabelPosition *lp ) : lp( lp )
+ {
+ int i;
+ double hyp = max( lp->feature->xmax - lp->feature->xmin, lp->feature->ymax - lp->feature->ymin );
+ hyp *= 10;
+
+ px = ( lp->x[0] + lp->x[2] ) / 2.0;
+ py = ( lp->y[0] + lp->y[2] ) / 2.0;
+ dLp[0] = lp->w / 2;
+ dLp[1] = lp->h / 2;
+ dLp[2] = dLp[0] / cos( M_PI / 4 );
+
+ /*
+ 3 2 1
+ \ | /
+ 4 --x -- 0
+ / | \
+ 5 6 7
+ */
+
+ double alpha = lp->getAlpha();
+ for ( i = 0;i < 8;i++, alpha += M_PI / 4 )
+ {
+ dist[i] = DBL_MAX;
+ ok[i] = false;
+ rpx[i] = px + cos( alpha ) * hyp;
+ rpy[i] = py + sin( alpha ) * hyp;
+ }
+ }
+
+ void PolygonCostCalculator::update( PointSet *pset )
+ {
+ if ( pset->type == GEOS_POINT )
+ {
+ updatePoint( pset );
+ }
+ else
+ {
+ double rx, ry;
+ if ( pset->getDist( px, py, &rx, &ry ) < updateLinePoly( pset ) )
+ {
+ PointSet *point = new PointSet( ry, ry );
+ update( point );
+ delete point;
+ }
+ }
+ }
+
+ void PolygonCostCalculator::updatePoint( PointSet *pset )
+ {
+ double beta = atan2( pset->y[0] - py, pset->x[0] - px ) - lp->getAlpha();
+
+ while ( beta < 0 )
+ {
+ beta += 2 * M_PI;
+ }
+
+ double a45 = M_PI / 4;
+
+ int i = ( int )( beta / a45 );
+
+ for ( int j = 0;j < 2;j++, i = ( i + 1 ) % 8 )
+ {
+ double rx, ry;
+ rx = px - rpy[i] + py;
+ ry = py + rpx[i] - px;
+ double ix, iy; // the point that we look for
+ if ( computeLineIntersection( px, py, rpx[i], rpy[i], pset->x[0], pset->y[0], rx, ry, &ix, &iy ) )
+ {
+ double d = dist_euc2d_sq( px, py, ix, iy );
+ if ( d < dist[i] )
+ {
+ dist[i] = d;
+ ok[i] = true;
+ }
+ }
+ else
+ {
+ std::cout << "this shouldn't occurs !!!" << std::endl;
+ }
+ }
+ }
+
+ double PolygonCostCalculator::updateLinePoly( PointSet *pset )
+ {
+ int i, j, k;
+ int nbP = ( pset->type == GEOS_POLYGON ? pset->nbPoints : pset->nbPoints - 1 );
+ double min_dist = DBL_MAX;
+
+ for ( i = 0;i < nbP;i++ )
+ {
+ j = ( i + 1 ) % pset->nbPoints;
+
+ for ( k = 0;k < 8;k++ )
+ {
+ double ix, iy;
+ if ( computeSegIntersection( px, py, rpx[k], rpy[k], pset->x[i], pset->y[i], pset->x[j], pset->y[j], &ix, &iy ) )
+ {
+ double d = dist_euc2d_sq( px, py, ix, iy );
+ if ( d < dist[k] )
+ {
+ dist[k] = d;
+ ok[k] = true;
+ }
+ if ( d < min_dist )
+ {
+ min_dist = d;
+ }
+ }
+ }
+ }
+ return min_dist;
+ }
+
+ LabelPosition* PolygonCostCalculator::getLabel()
+ {
+ return lp;
+ }
+
+ double PolygonCostCalculator::getCost()
+ {
+ int i;
+
+ for ( i = 0;i < 8;i++ )
+ {
+ dist[i] -= (( i % 2 ) ? dLp[2] : (( i == 0 || i == 4 ) ? dLp[0] : dLp[1] ) );
+ if ( !ok[i] || dist[i] < 0.1 )
+ {
+ dist[i] = 0.1;
+ }
+ }
+
+ double a, b, c, d;
+
+ a = min( dist[0], dist[4] );
+ b = min( dist[1], dist[5] );
+ c = min( dist[2], dist[6] );
+ d = min( dist[3], dist[7] );
+
+ //return (a+b+c+d);
+ return ( a*b*c*d );
+ }
+
+}
Added: branches/symbology-ng-branch/src/core/pal/costcalculator.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/costcalculator.h (rev 0)
+++ branches/symbology-ng-branch/src/core/pal/costcalculator.h 2009-07-11 20:05:59 UTC (rev 11045)
@@ -0,0 +1,56 @@
+#ifndef COSTCALCULATOR_H
+#define COSTCALCULATOR_H
+
+#include "rtree.hpp"
+
+namespace pal
+{
+ class Feats;
+
+ class CostCalculator
+ {
+ public:
+ /** increase candidate's cost according to its collision with passed feature */
+ static void addObstacleCostPenalty(LabelPosition* lp, PointSet* feat);
+
+ static void setPolygonCandidatesCost( int nblp, LabelPosition **lPos, int max_p, RTree<PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] );
+
+ /** Set cost to the smallest distance between lPos's centroid and a polygon stored in geoetry field */
+ static void setCandidateCostFromPolygon( LabelPosition* lp, RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] );
+
+ /** sort candidates by costs, skip the worse ones, evaluate polygon candidates */
+ static int finalizeCandidatesCosts( Feats* feat, int max_p, RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] );
+ };
+
+ /**
+ * \brief Data structure to compute polygon's candidates costs
+ *
+ * eight segment from center of candidat to (rpx,rpy) points (0°, 45°, 90°, ..., 315°)
+ * dist store the shortest square distance from the center to an object
+ * ok[i] is the to true whether the corresponding dist[i] is set
+ */
+ class PolygonCostCalculator
+ {
+ LabelPosition *lp;
+ double px, py;
+ double dist[8];
+ double rpx[8];
+ double rpy[8];
+ bool ok[8];
+
+ double dLp[3];
+
+ void updatePoint( PointSet *pset );
+ double updateLinePoly( PointSet *pset );
+ public:
+ PolygonCostCalculator( LabelPosition *lp );
+
+ void update( PointSet *pset );
+
+ double getCost();
+
+ LabelPosition *getLabel();
+ };
+}
+
+#endif // COSTCALCULATOR_H
Modified: branches/symbology-ng-branch/src/core/pal/feature.cpp
===================================================================
--- branches/symbology-ng-branch/src/core/pal/feature.cpp 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/feature.cpp 2009-07-11 20:05:59 UTC (rev 11045)
@@ -579,6 +579,7 @@
LinkedList<LabelPosition*> *positions = new LinkedList<LabelPosition*> ( ptrLPosCompare );
int it;
+ int id = 0; // ids for candidates
double dlx, dly; // delta from label center and bottom-left corner
double alpha = 0.0; // rotation for the label
double px, py;
@@ -719,7 +720,8 @@
// Only accept candidate that center is in the polygon
if ( isPointInPolygon( mapShape->nbPoints, mapShape->x, mapShape->y, rx, ry ) )
{
- positions->push_back( new LabelPosition( 0, rx - dlx, ry - dly , xrm, yrm, alpha, 0.0001, this ) ); // Polygon
+ // cost is set to minimal value, evaluated later
+ positions->push_back( new LabelPosition( id++, rx - dlx, ry - dly , xrm, yrm, alpha, 0.0001, this ) ); // Polygon
}
}
}
@@ -741,7 +743,6 @@
for ( i = 0;i < nbp;i++ )
{
( *lPos )[i] = positions->pop_front();
- ( *lPos )[i]->id = i;
}
for ( bbid = 0;bbid < j;bbid++ )
@@ -838,7 +839,7 @@
case P_POINT_OVER:
double cx, cy;
mapShape->getCentroid( cx, cy );
- if (P_POINT_OVER)
+ if ( layer->getArrangement() == P_POINT_OVER )
nbp = setPositionOverPoint( cx, cy, scale, lPos, delta );
else
nbp = setPositionForPoint( cx, cy, scale, lPos, delta );
@@ -861,7 +862,7 @@
if ( !( *lPos )[i]->isIn( bbox ) )
{
rnbp--;
- ( *lPos )[i]->cost = DBL_MAX;
+ ( *lPos )[i]->setCost( DBL_MAX ); // infinite cost => do not use
}
else // this one is OK
{
Modified: branches/symbology-ng-branch/src/core/pal/feature.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/feature.h 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/feature.h 2009-07-11 20:05:59 UTC (rev 11045)
@@ -49,11 +49,6 @@
namespace pal
{
- class Pal;
- class Layer;
- class LabelPosition;
- class SimpleMutex;
-
/**
* \brief Main class to handle feature
*/
Modified: branches/symbology-ng-branch/src/core/pal/geomfunction.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/geomfunction.h 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/geomfunction.h 2009-07-11 20:05:59 UTC (rev 11045)
@@ -80,38 +80,9 @@
}*/
- inline int nbLabelPointInPolygon( int npol, double *xp, double *yp, double x[4], double y[4] )
- {
- int a, k, count = 0;
- double px, py;
- // cheack each corner
- for ( k = 0;k < 4;k++ )
- {
- px = x[k];
- py = y[k];
- for ( a = 0;a < 2;a++ ) // and each middle of segment
- {
- if ( isPointInPolygon( npol, xp, yp, px, py ) )
- count++;
- px = ( x[k] + x[( k+1 ) %4] ) / 2.0;
- py = ( y[k] + y[( k+1 ) %4] ) / 2.0;
- }
- }
- px = ( x[0] + x[2] ) / 2.0;
- py = ( y[0] + y[2] ) / 2.0;
-
- // and the label center
- if ( isPointInPolygon( npol, xp, yp, px, py ) )
- count += 4; // virtually 4 points
-
- return count;
- }
-
-
-
int convexHull( int *id, const double* const x, const double* const y, int n );
Modified: branches/symbology-ng-branch/src/core/pal/labelposition.cpp
===================================================================
--- branches/symbology-ng-branch/src/core/pal/labelposition.cpp 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/labelposition.cpp 2009-07-11 20:05:59 UTC (rev 11045)
@@ -43,6 +43,7 @@
#include <pal/pal.h>
#include <pal/label.h>
+#include "costcalculator.h"
#include "feature.h"
#include "geomfunction.h"
#include "labelposition.h"
@@ -188,27 +189,27 @@
return true;
}
- int LabelPosition::getId()
+ int LabelPosition::getId() const
{
return id;
}
- double LabelPosition::getX()
+ double LabelPosition::getX() const
{
return x[0];
}
- double LabelPosition::getY()
+ double LabelPosition::getY() const
{
return y[0];
}
- double LabelPosition::getAlpha()
+ double LabelPosition::getAlpha() const
{
return alpha;
}
- double LabelPosition::getCost()
+ double LabelPosition::getCost() const
{
return cost;
}
@@ -261,34 +262,16 @@
return (( LabelPosition* ) l )->cost > (( LabelPosition* ) r )->cost;
}
- /*
- bool workingCostShrink (void *l, void *r){
- return ((LabelPosition*)l)->workingCost < ((LabelPosition*)r)->workingCost;
- }
- bool workingCostGrow (void *l, void *r){
- return ((LabelPosition*)l)->workingCost > ((LabelPosition*)r)->workingCost;
- }
- */
-
Label *LabelPosition::toLabel( bool active )
{
-
- //double x[4], y;
-
- //x = this->x[0];
- //y = this->y[0];
-
-//#warning retourner les coord projeté ou pas ?
- //feature->layer->pal->proj->getLatLong(this->x[0], this->y[0], &x, &y);
-
return new Label( this->x, this->y, alpha, feature->getUID(), feature->getLayer()->getName(), feature->getUserGeometry() );
}
- bool LabelPosition::obstacleCallback( PointSet *feat, void *ctx )
+ bool LabelPosition::polygonObstacleCallback( PointSet *feat, void *ctx )
{
- LabelPosition::PolygonCostCalculator *pCost = ( LabelPosition::PolygonCostCalculator* ) ctx;
+ PolygonCostCalculator *pCost = ( PolygonCostCalculator* ) ctx;
LabelPosition *lp = pCost->getLabel();
if (( feat == lp->feature ) || ( feat->getHoleOf() && feat->getHoleOf() != lp->feature ) )
@@ -315,48 +298,7 @@
return true;
}
- void LabelPosition::setCostFromPolygon( RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
- {
- double amin[2];
- double amax[2];
-
-
- LabelPosition::PolygonCostCalculator *pCost = new LabelPosition::PolygonCostCalculator( this );
- //cost = getCostFromPolygon (feat, dist_sq);
-
- // center
- //cost = feat->getDistInside((this->x[0] + this->x[2])/2.0, (this->y[0] + this->y[2])/2.0 );
-
- feature->fetchCoordinates();
- pCost->update( feature );
-
- PointSet *extent = new PointSet( 4, bbx, bby );
-
- pCost->update( extent );
-
- delete extent;
-
- // TODO Comment
- /*if (cost > (w*w + h*h) / 4.0) {
- double dist = sqrt (cost);
- amin[0] = (x[0] + x[2]) / 2.0 - dist;
- amin[1] = (y[0] + y[2]) / 2.0 - dist;
- amax[0] = amin[0] + 2 * dist;
- amax[1] = amin[1] + 2 * dist;
- } else {*/
- feature->getBoundingBox(amin, amax);
- //}
-
- //std::cout << amin[0] << " " << amin[1] << " " << amax[0] << " " << amax[1] << std::endl;
- obstacles->Search( amin, amax, obstacleCallback, pCost );
-
- cost = pCost->getCost();
-
- feature->releaseCoordinates();
- delete pCost;
- }
-
void LabelPosition::removeFromIndex( RTree<LabelPosition*, double, 2, double> *index )
{
double amin[2];
@@ -375,213 +317,25 @@
}
- void LabelPosition::setCost( int nblp, LabelPosition **lPos, int max_p, RTree<PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
- {
- //std::cout << "setCost:" << std::endl;
- //clock_t clock_start = clock();
+ //////////
- int i;
-
- double normalizer;
- // compute raw cost
-#ifdef _DEBUG_
- std::cout << "LabelPosition for feat: " << lPos[0]->feature->uid << std::endl;
-#endif
-
- for ( i = 0;i < nblp;i++ )
- lPos[i]->setCostFromPolygon( obstacles, bbx, bby );
-
- // lPos with big values came fisrts (value = min distance from label to Polygon's Perimeter)
- //sort ( (void**) lPos, nblp, costGrow);
- sort(( void** ) lPos, nblp, costShrink );
-
-
- // define the value's range
- double cost_max = lPos[0]->cost;
- double cost_min = lPos[max_p-1]->cost;
-
- cost_max -= cost_min;
-
- if ( cost_max > EPSILON )
- {
- normalizer = 0.0020 / cost_max;
- }
- else
- {
- normalizer = 1;
- }
-
- // adjust cost => the best is 0.0001, the sorst is 0.0021
- // others are set proportionally between best and worst
- for ( i = 0;i < max_p;i++ )
- {
-#ifdef _DEBUG_
- std::cout << " lpos[" << i << "] = " << lPos[i]->cost;
-#endif
- //if (cost_max - cost_min < EPSILON)
- if ( cost_max > EPSILON )
- {
- lPos[i]->cost = 0.0021 - ( lPos[i]->cost - cost_min ) * normalizer;
- }
- else
- {
- //lPos[i]->cost = 0.0001 + (lPos[i]->cost - cost_min) * normalizer;
- lPos[i]->cost = 0.0001;
- }
-
-#ifdef _DEBUG_
- std::cout << " ==> " << lPos[i]->cost << std::endl;
-#endif
- }
- //clock_t clock_2;
- //std::cout << "AfterSetCostFromPolygon (" << nblp << "x): " << clock_2 = (clock() - clock_1) << std::endl;
- }
-
- LabelPosition::PolygonCostCalculator::PolygonCostCalculator( LabelPosition *lp ) : lp( lp )
+ bool LabelPosition::pruneCallback( LabelPosition *lp, void *ctx )
{
- int i;
- double hyp = max( lp->feature->xmax - lp->feature->xmin, lp->feature->ymax - lp->feature->ymin );
- hyp *= 10;
+ PointSet *feat = (( PruneCtx* ) ctx )->obstacle;
+ double scale = (( PruneCtx* ) ctx )->scale;
+ Pal* pal = (( PruneCtx* ) ctx )->pal;
- px = ( lp->x[0] + lp->x[2] ) / 2.0;
- py = ( lp->y[0] + lp->y[2] ) / 2.0;
- dLp[0] = lp->w / 2;
- dLp[1] = lp->h / 2;
- dLp[2] = dLp[0] / cos( M_PI / 4 );
-
- /*
- 3 2 1
- \ | /
- 4 --x -- 0
- / | \
- 5 6 7
- */
-
- double alpha = lp->getAlpha();
- for ( i = 0;i < 8;i++, alpha += M_PI / 4 )
+ if (( feat == lp->feature ) || ( feat->getHoleOf() && feat->getHoleOf() != lp->feature ) )
{
- dist[i] = DBL_MAX;
- ok[i] = false;
- rpx[i] = px + cos( alpha ) * hyp;
- rpy[i] = py + sin( alpha ) * hyp;
+ return true;
}
- }
- void LabelPosition::PolygonCostCalculator::update( PointSet *pset )
- {
- if ( pset->type == GEOS_POINT )
- {
- updatePoint( pset );
- }
- else
- {
- double rx, ry;
- if ( pset->getDist( px, py, &rx, &ry ) < updateLinePoly( pset ) )
- {
- PointSet *point = new PointSet( ry, ry );
- update( point );
- delete point;
- }
- }
- }
+ CostCalculator::addObstacleCostPenalty(lp, feat);
- void LabelPosition::PolygonCostCalculator::updatePoint( PointSet *pset )
- {
- double beta = atan2( pset->y[0] - py, pset->x[0] - px ) - lp->getAlpha();
-
- while ( beta < 0 )
- {
- beta += 2 * M_PI;
- }
-
- double a45 = M_PI / 4;
-
- int i = ( int )( beta / a45 );
-
- for ( int j = 0;j < 2;j++, i = ( i + 1 ) % 8 )
- {
- double rx, ry;
- rx = px - rpy[i] + py;
- ry = py + rpx[i] - px;
- double ix, iy; // the point that we look for
- if ( computeLineIntersection( px, py, rpx[i], rpy[i], pset->x[0], pset->y[0], rx, ry, &ix, &iy ) )
- {
- double d = dist_euc2d_sq( px, py, ix, iy );
- if ( d < dist[i] )
- {
- dist[i] = d;
- ok[i] = true;
- }
- }
- else
- {
- std::cout << "this shouldn't occurs !!!" << std::endl;
- }
- }
+ return true;
}
- double LabelPosition::PolygonCostCalculator::updateLinePoly( PointSet *pset )
- {
- int i, j, k;
- int nbP = ( pset->type == GEOS_POLYGON ? pset->nbPoints : pset->nbPoints - 1 );
- double min_dist = DBL_MAX;
- for ( i = 0;i < nbP;i++ )
- {
- j = ( i + 1 ) % pset->nbPoints;
-
- for ( k = 0;k < 8;k++ )
- {
- double ix, iy;
- if ( computeSegIntersection( px, py, rpx[k], rpy[k], pset->x[i], pset->y[i], pset->x[j], pset->y[j], &ix, &iy ) )
- {
- double d = dist_euc2d_sq( px, py, ix, iy );
- if ( d < dist[k] )
- {
- dist[k] = d;
- ok[k] = true;
- }
- if ( d < min_dist )
- {
- min_dist = d;
- }
- }
- }
- }
- return min_dist;
- }
-
- LabelPosition* LabelPosition::PolygonCostCalculator::getLabel()
- {
- return lp;
- }
-
- double LabelPosition::PolygonCostCalculator::getCost()
- {
- int i;
-
- for ( i = 0;i < 8;i++ )
- {
- dist[i] -= (( i % 2 ) ? dLp[2] : (( i == 0 || i == 4 ) ? dLp[0] : dLp[1] ) );
- if ( !ok[i] || dist[i] < 0.1 )
- {
- dist[i] = 0.1;
- }
- }
-
- double a, b, c, d;
-
- a = min( dist[0], dist[4] );
- b = min( dist[1], dist[5] );
- c = min( dist[2], dist[6] );
- d = min( dist[3], dist[7] );
-
- //return (a+b+c+d);
- return ( a*b*c*d );
- }
-
- //////////
-
bool LabelPosition::countOverlapCallback( LabelPosition *lp, void *ctx )
{
LabelPosition *lp2 = ( LabelPosition* ) ctx;
@@ -630,5 +384,114 @@
}
+
+ double LabelPosition::getDistanceToPoint( double xp, double yp )
+ {
+ int i;
+ int j;
+
+ double mx[4];
+ double my[4];
+
+ double dist_min = DBL_MAX;
+ double dist;
+
+ for ( i = 0;i < 4;i++ )
+ {
+ j = ( i + 1 ) % 4;
+ mx[i] = ( x[i] + x[j] ) / 2.0;
+ my[i] = ( y[i] + y[j] ) / 2.0;
+ }
+
+
+ if ( vabs( cross_product( mx[0], my[0], my[2], my[2], xp, yp ) / h ) < w / 2 )
+ {
+ dist = cross_product( x[0], y[0], x[1], y[1], xp, yp ) / w;
+ if ( vabs( dist ) < vabs( dist_min ) )
+ dist_min = dist;
+
+ dist = cross_product( x[2], y[2], x[3], y[3], xp, yp ) / w;
+ if ( vabs( dist ) < vabs( dist_min ) )
+ dist_min = dist;
+ }
+
+ if ( vabs( cross_product( mx[1], my[1], my[3], my[3], xp, yp ) / w ) < h / 2 )
+ {
+ dist = cross_product( x[1], y[1], x[2], y[2], xp, yp ) / h;
+ if ( vabs( dist ) < vabs( dist_min ) )
+ dist_min = dist;
+
+ dist = cross_product( x[3], y[3], x[0], y[0], xp, yp ) / h;
+ if ( vabs( dist ) < vabs( dist_min ) )
+ dist_min = dist;
+ }
+
+ for ( i = 0;i < 4;i++ )
+ {
+ dist = dist_euc2d( x[i], y[i], xp, yp );
+ if ( vabs( dist ) < vabs( dist_min ) )
+ dist_min = dist;
+ }
+
+ return dist_min;
+ }
+
+
+ bool LabelPosition::isBorderCrossingLine( PointSet* feat )
+ {
+ double ca, cb;
+ for ( int i = 0;i < 4;i++ )
+ {
+ for ( int j = 0;j < feat->getNumPoints() - 1;j++ )
+ {
+ ca = cross_product( x[i], y[i], x[( i+1 ) %4], y[( i+1 ) %4],
+ feat->x[j], feat->y[j] );
+ cb = cross_product( x[i], y[i], x[( i+1 ) %4], y[( i+1 ) %4],
+ feat->x[j+1], feat->y[j+1] );
+
+ if (( ca < 0 && cb > 0 ) || ( ca > 0 && cb < 0 ) )
+ {
+ ca = cross_product( feat->x[j], feat->y[j], feat->x[j+1], feat->y[j+1],
+ x[i], y[i] );
+ cb = cross_product( feat->x[j], feat->y[j], feat->x[j+1], feat->y[j+1],
+ x[( i+1 ) %4], y[( i+1 ) %4] );
+ if (( ca < 0 && cb > 0 ) || ( ca > 0 && cb < 0 ) )
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ int LabelPosition::getNumPointsInPolygon( int npol, double *xp, double *yp )
+ {
+ int a, k, count = 0;
+ double px, py;
+
+ // cheack each corner
+ for ( k = 0;k < 4;k++ )
+ {
+ px = x[k];
+ py = y[k];
+
+ for ( a = 0;a < 2;a++ ) // and each middle of segment
+ {
+ if ( isPointInPolygon( npol, xp, yp, px, py ) )
+ count++;
+ px = ( x[k] + x[( k+1 ) %4] ) / 2.0;
+ py = ( y[k] + y[( k+1 ) %4] ) / 2.0;
+ }
+ }
+
+ px = ( x[0] + x[2] ) / 2.0;
+ py = ( y[0] + y[2] ) / 2.0;
+
+ // and the label center
+ if ( isPointInPolygon( npol, xp, yp, px, py ) )
+ count += 4; // virtually 4 points
+
+ return count;
+ }
+
} // end namespace
Modified: branches/symbology-ng-branch/src/core/pal/labelposition.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/labelposition.h 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/labelposition.h 2009-07-11 20:05:59 UTC (rev 11045)
@@ -45,7 +45,6 @@
class Feature;
class Pal;
class Label;
- class PriorityQueue;
/**
@@ -54,10 +53,8 @@
class LabelPosition
{
- friend bool pruneLabelPositionCallback( LabelPosition *lp, void *ctx );
- friend double dist_pointToLabel( double, double, LabelPosition* );
- friend class Pal;
- friend class Feature;
+ friend class CostCalculator;
+ friend class PolygonCostCalculator;
private:
@@ -105,15 +102,6 @@
LabelPosition( int id, Feature *feature, std::ifstream *file );
/**
- * \brief Set cost to the smallest distance between lPos's centroid and a polygon stored in geoetry field
- */
- void setCostFromPolygon( RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] );
-
- static void setCost( int nblp, LabelPosition **lPos, int max_p, RTree<PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] );
-
-
-
- /**
* \brief is the labelposition in the bounding-box ?
*
*\param bbox the bounding-box double[4] = {xmin, ymin, xmax, ymax}
@@ -131,7 +119,7 @@
/** \brief return id
* \return id
*/
- int getId();
+ int getId() const;
/** \brief return the feature corresponding to this labelposition
@@ -143,22 +131,23 @@
* \brief get the down-left x coordinate
* \return x coordinate
*/
- double getX();
+ double getX() const;
/**
* \brief get the down-left y coordinate
* \return y coordinate
*/
- double getY();
+ double getY() const;
- double getWidth() { return w; }
- double getHeight() { return h; }
+ double getWidth() const { return w; }
+ double getHeight() const { return h; }
double getNumOverlaps() const { return nbOverlap; }
void resetNumOverlaps() { nbOverlap = 0; } // called from problem.cpp, pal.cpp
int getProblemFeatureId() const { return probFeat; }
- /** set problem feature ID. called from pal.cpp during extraction */
- void setProblemFeatureId( int probFid ) { probFeat = probFid; }
+ /** set problem feature ID and assigned label candidate ID.
+ * called from pal.cpp during extraction */
+ void setProblemIds( int probFid, int lpId ) { probFeat = probFid; id = lpId; }
/** return pointer to layer's name. used for stats */
char* getLayerName() const;
@@ -167,13 +156,17 @@
* \brief get alpha
* \return alpha to rotate text (in rad)
*/
- double getAlpha();
+ double getAlpha() const;
+
/**
* \brief get the position geographical cost
* \return geographical cost
*/
- double getCost();
+ double getCost() const;
+ /** Modify candidate's cost */
+ void setCost( double newCost ) { cost = newCost; }
+
/** Make sure the cost is less than 1 */
void validateCost();
@@ -191,37 +184,16 @@
void removeFromIndex( RTree<LabelPosition*, double, 2, double> *index );
void insertIntoIndex( RTree<LabelPosition*, double, 2, double> *index );
- /**
- * \brief Data structure to compute polygon's candidates costs
- *
- * eight segment from center of candidat to (rpx,rpy) points (0°, 45°, 90°, ..., 315°)
- * dist store the shortest square distance from the center to an object
- * ok[i] is the to true whether the corresponding dist[i] is set
- */
- class PolygonCostCalculator
+ typedef struct
{
- LabelPosition *lp;
- double px, py;
- double dist[8];
- double rpx[8];
- double rpy[8];
- bool ok[8];
+ double scale;
+ Pal* pal;
+ PointSet *obstacle;
+ } PruneCtx;
- double dLp[3];
+ /** Check wheter the candidate in ctx overlap with obstacle feat */
+ static bool pruneCallback( LabelPosition *lp, void *ctx );
- void updatePoint( PointSet *pset );
- double updateLinePoly( PointSet *pset );
- public:
- PolygonCostCalculator( LabelPosition *lp );
-
- void update( PointSet *pset );
-
- double getCost();
-
- LabelPosition *getLabel();
- };
-
-
// for sorting
static bool costShrink( void *l, void *r );
static bool costGrow( void *l, void *r );
@@ -246,8 +218,17 @@
static bool removeOverlapCallback( LabelPosition *lp, void *ctx );
// for polygon cost calculation
- static bool obstacleCallback( PointSet *feat, void *ctx );
+ static bool polygonObstacleCallback( PointSet *feat, void *ctx );
+ /** get distance from this label to a point */
+ double getDistanceToPoint( double xp, double yp );
+
+ /** returns true if this label crosses the specified line */
+ bool isBorderCrossingLine( PointSet* feat );
+
+ /** returns number of intersections with polygon (testing border and center) */
+ int getNumPointsInPolygon( int npol, double *xp, double *yp );
+
};
} // end namespac
Modified: branches/symbology-ng-branch/src/core/pal/layer.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/layer.h 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/layer.h 2009-07-11 20:05:59 UTC (rev 11045)
@@ -72,10 +72,7 @@
friend class LabelPosition;
friend bool extractFeatCallback( Feature *ft_ptr, void *ctx );
- friend bool pruneLabelPositionCallback( LabelPosition *lp, void *ctx );
- friend bool obstacleCallback( PointSet *feat, void *ctx );
friend void toSVGPath( int nbPoints, double *x, double *y, int dpi, Layer *layer, int type, char *uid, std::ostream &out, double scale, int xmin, int ymax, bool exportInfo, char *color );
- friend bool filteringCallback( PointSet*, void* );
protected:
char *name; /* unique */
Modified: branches/symbology-ng-branch/src/core/pal/pal.cpp
===================================================================
--- branches/symbology-ng-branch/src/core/pal/pal.cpp 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/pal.cpp 2009-07-11 20:05:59 UTC (rev 11045)
@@ -53,6 +53,7 @@
#include "linkedlist.hpp"
#include "rtree.hpp"
+#include "costcalculator.h"
#include "feature.h"
#include "geomfunction.h"
#include "labelposition.h"
@@ -64,14 +65,6 @@
namespace pal
{
- typedef struct
- {
- //LabelPosition *lp;
- double scale;
- Pal* pal;
- PointSet *obstacle;
- } PruneCtx;
-
void geosError( const char *fmt, ... )
{
va_list list;
@@ -393,165 +386,7 @@
}
- double dist_pointToLabel( double xp, double yp, LabelPosition *lp )
- {
- int i;
- int j;
-
- double mx[4];
- double my[4];
-
- double dist_min = DBL_MAX;
- double dist;
-
- for ( i = 0;i < 4;i++ )
- {
- j = ( i + 1 ) % 4;
- mx[i] = ( lp->x[i] + lp->x[j] ) / 2.0;
- my[i] = ( lp->y[i] + lp->y[j] ) / 2.0;
- }
-
-
- if ( vabs( cross_product( mx[0], my[0], my[2], my[2], xp, yp ) / lp->h ) < lp->w / 2 )
- {
- dist = cross_product( lp->x[0], lp->y[0], lp->x[1], lp->y[1], xp, yp ) / lp->w;
- if ( vabs( dist ) < vabs( dist_min ) )
- dist_min = dist;
-
- dist = cross_product( lp->x[2], lp->y[2], lp->x[3], lp->y[3], xp, yp ) / lp->w;
- if ( vabs( dist ) < vabs( dist_min ) )
- dist_min = dist;
- }
-
- if ( vabs( cross_product( mx[1], my[1], my[3], my[3], xp, yp ) / lp->w ) < lp->h / 2 )
- {
- dist = cross_product( lp->x[1], lp->y[1], lp->x[2], lp->y[2], xp, yp ) / lp->h;
- if ( vabs( dist ) < vabs( dist_min ) )
- dist_min = dist;
-
- dist = cross_product( lp->x[3], lp->y[3], lp->x[0], lp->y[0], xp, yp ) / lp->h;
- if ( vabs( dist ) < vabs( dist_min ) )
- dist_min = dist;
- }
-
- for ( i = 0;i < 4;i++ )
- {
- dist = dist_euc2d( lp->x[i], lp->y[i], xp, yp );
- if ( vabs( dist ) < vabs( dist_min ) )
- dist_min = dist;
- }
-
- return dist_min;
- }
-
-
- /*
- * Check wheter the candidate in ctx overlap with obstacle feat
- */
- bool pruneLabelPositionCallback( LabelPosition *lp, void *ctx )
- {
-
- PointSet *feat = (( PruneCtx* ) ctx )->obstacle;
- double scale = (( PruneCtx* ) ctx )->scale;
- Pal* pal = (( PruneCtx* ) ctx )->pal;
-
- if (( feat == lp->feature ) || ( feat->getHoleOf() && feat->getHoleOf() != lp->feature ) )
- {
- return true;
- }
-
- int n;
-
- int i, j;
- double ca, cb;
-
- n = 0;
-
- //if (!feat->holeOf)
- //((Feature*)feat)->fetchCoordinates();
-
- double dist;
-
- double distlabel = lp->feature->getLabelDistance();
- /*unit_convert( double( lp->feature->distlabel ),
- pal::PIXEL,
- pal->map_unit,
- pal->dpi, scale, 1 );*/
-
-
-
- switch ( feat->getGeosType() )
- {
- //case geos::geom::GEOS_POINT:
- case GEOS_POINT:
-
-#ifdef _DEBUG_FULL
- std::cout << " POINT" << std::endl;
-#endif
-
- dist = dist_pointToLabel( feat->x[0], feat->y[0], lp );
-
- if ( dist < 0 )
- n = 2;
- else if ( dist < distlabel )
- n = 1;
- else
- n = 0;
-
- break;
-
- //case geos::geom::GEOS_LINESTRING:
- case GEOS_LINESTRING:
-#ifdef _DEBUG_FULL
- std::cout << " LINE" << std::endl;
-#endif
- // Is one of label's boarder cross the line ?
- for ( i = 0;i < 4;i++ )
- {
- for ( j = 0;j < feat->getNumPoints() - 1;j++ )
- {
- ca = cross_product( lp->x[i], lp->y[i], lp->x[( i+1 ) %4], lp->y[( i+1 ) %4],
- feat->x[j], feat->y[j] );
- cb = cross_product( lp->x[i], lp->y[i], lp->x[( i+1 ) %4], lp->y[( i+1 ) %4],
- feat->x[j+1], feat->y[j+1] );
-
- if (( ca < 0 && cb > 0 ) || ( ca > 0 && cb < 0 ) )
- {
- ca = cross_product( feat->x[j], feat->y[j], feat->x[j+1], feat->y[j+1],
- lp->x[i], lp->y[i] );
- cb = cross_product( feat->x[j], feat->y[j], feat->x[j+1], feat->y[j+1],
- lp->x[( i+1 ) %4], lp->y[( i+1 ) %4] );
- if (( ca < 0 && cb > 0 ) || ( ca > 0 && cb < 0 ) )
- {
- n = 1;
- i = 4;
- break;
- }
- }
- }
- }
- break;
- //case geos::geom::GEOS_POLYGON:
- case GEOS_POLYGON:
-#ifdef _DEBUG_FULL
- std::cout << " POLY" << std::endl;
-#endif
- n = nbLabelPointInPolygon( feat->getNumPoints(), feat->x, feat->y, lp->x, lp->y );
-
- //n<1?n=0:n=1;
- break;
- }
-
- // label cost is penalized
- lp->cost += double( n );
-
- //if (!feat->holeOf)
- //((Feature*)feat)->releaseCoordinates();
-
- return true;
- }
-
bool releaseCallback( PointSet *pset, void *ctx )
{
if ( pset->getHoleOf() == NULL )
@@ -611,12 +446,12 @@
double amin[2], amax[2];
pset->getBoundingBox(amin, amax);
- PruneCtx pruneContext;
+ LabelPosition::PruneCtx pruneContext;
pruneContext.scale = scale;
pruneContext.obstacle = pset;
pruneContext.pal = pal;
- cdtsIndex->Search( amin, amax, pruneLabelPositionCallback, ( void* ) &pruneContext );
+ cdtsIndex->Search( amin, amax, LabelPosition::pruneCallback, ( void* ) &pruneContext );
if ( pset->getHoleOf() == NULL )
{
@@ -828,42 +663,10 @@
break;
}
- // If candidates list is smaller than expected
- if ( max_p > feat->nblp )
- max_p = feat->nblp;
- //
- // sort candidates list, best label to worst
- sort(( void** ) feat->lPos, feat->nblp, LabelPosition::costGrow );
+ // sort candidates by cost, skip less interesting ones, calculate polygon costs (if using polygons)
+ max_p = CostCalculator::finalizeCandidatesCosts( feat, max_p, obstacles, bbx, bby );
- // try to exclude all conflitual labels (good ones have cost < 1 by pruning)
- double discrim = 0.0;
- int stop;
- do
- {
- discrim += 1.0;
- for ( stop = 0;stop < feat->nblp && feat->lPos[stop]->getCost() < discrim;stop++ );
- }
- while ( stop == 0 && discrim < feat->lPos[feat->nblp-1]->getCost() + 2.0 );
-
- if ( discrim > 1.5 )
- {
- int k;
- for ( k = 0;k < stop;k++ )
- feat->lPos[k]->cost = 0.0021;
- }
-
- if ( max_p > stop )
- max_p = stop;
-
#ifdef _DEBUG_FULL_
- std::cout << "Nblabel kept for feat " << feat->feature->uid << "/" << feat->feature->layer->name << ": " << max_p << "/" << feat->nblp << std::endl;
-#endif
-
- // Sets costs for candidates of polygon
- if ( feat->feature->getGeosType() == GEOS_POLYGON && ( feat->feature->getLayer()->arrangement == P_FREE || feat->feature->getLayer()->arrangement == P_HORIZ ) )
- LabelPosition::setCost( stop, feat->lPos, max_p, obstacles, bbx, bby );
-
-#ifdef _DEBUG_FULL_
std::cout << "All Cost are setted" << std::endl;
#endif
// only keep the 'max_p' best candidates
@@ -884,8 +687,7 @@
{
lp = feat->lPos[j];
//lp->insertIntoIndex(prob->candidates);
- lp->id = idlp;
- lp->setProblemFeatureId( i ); // bugfix #1 (maxence 10/23/2008)
+ lp->setProblemIds( i, idlp ); // bugfix #1 (maxence 10/23/2008)
}
fFeats->push_back( feat );
}
Modified: branches/symbology-ng-branch/src/core/pal/pal.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/pal.h 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/pal.h 2009-07-11 20:05:59 UTC (rev 11045)
@@ -122,9 +122,6 @@
friend class Problem;
friend class Feature;
friend class Layer;
- friend class LabelPosition;
- friend class PointSet;
- friend bool pruneLabelPositionCallback( LabelPosition *lp, void *ctx );
private:
std::list<Layer*> * layers;
Modified: branches/symbology-ng-branch/src/core/pal/pointset.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/pointset.h 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/pointset.h 2009-07-11 20:05:59 UTC (rev 11045)
@@ -94,7 +94,8 @@
{
friend class Feature;
friend class LabelPosition;
- friend bool pruneLabelPositionCallback( LabelPosition *lp, void *ctx );
+ friend class CostCalculator;
+ friend class PolygonCostCalculator;
friend void extractXYCoord( Feat *f );
protected:
Modified: branches/symbology-ng-branch/src/core/pal/util.h
===================================================================
--- branches/symbology-ng-branch/src/core/pal/util.h 2009-07-11 16:32:37 UTC (rev 11044)
+++ branches/symbology-ng-branch/src/core/pal/util.h 2009-07-11 20:05:59 UTC (rev 11045)
@@ -84,14 +84,15 @@
*/
LinkedList<Feat*> * splitGeom( GEOSGeometry *the_geom, const char *geom_id, bool check_valid );
- typedef struct _feats
+ class Feats
{
+ public:
Feature *feature;
PointSet *shape;
double priority;
int nblp;
LabelPosition **lPos;
- } Feats;
+ };
typedef struct _elementary_transformation
More information about the QGIS-commit
mailing list