[QGIS Commit] r15381 - in trunk/qgis: python/core src/app src/core

svn_qgis at osgeo.org svn_qgis at osgeo.org
Mon Mar 7 15:57:51 EST 2011


Author: jef
Date: 2011-03-07 12:57:51 -0800 (Mon, 07 Mar 2011)
New Revision: 15381

Modified:
   trunk/qgis/python/core/qgsdistancearea.sip
   trunk/qgis/src/app/qgsfieldcalculator.cpp
   trunk/qgis/src/core/qgsdistancearea.cpp
   trunk/qgis/src/core/qgsdistancearea.h
   trunk/qgis/src/core/qgssearchstringlexer.ll
   trunk/qgis/src/core/qgssearchstringparser.yy
   trunk/qgis/src/core/qgssearchtreenode.cpp
   trunk/qgis/src/core/qgssearchtreenode.h
Log:
[FEATURE] add $x, $y and $perimeter to field calculator


Modified: trunk/qgis/python/core/qgsdistancearea.sip
===================================================================
--- trunk/qgis/python/core/qgsdistancearea.sip	2011-03-07 16:45:27 UTC (rev 15380)
+++ trunk/qgis/python/core/qgsdistancearea.sip	2011-03-07 20:57:51 UTC (rev 15381)
@@ -49,6 +49,9 @@
     
     //! general measurement (line distance or polygon area)
     double measure(QgsGeometry* geometry);
+
+    //! measurement perimater of polygon
+    double measurePerimeter(QgsGeometry* geometry);
     
     //! measures line with more segments
     double measureLine(const QList<QgsPoint>& points);

Modified: trunk/qgis/src/app/qgsfieldcalculator.cpp
===================================================================
--- trunk/qgis/src/app/qgsfieldcalculator.cpp	2011-03-07 16:45:27 UTC (rev 15380)
+++ trunk/qgis/src/app/qgsfieldcalculator.cpp	2011-03-07 20:57:51 UTC (rev 15381)
@@ -35,6 +35,7 @@
   populateFields();
   populateOutputFieldTypes();
 
+
   //default values for field width and precision
   mOuputFieldWidthSpinBox->setValue( 10 );
   mOutputFieldPrecisionSpinBox->setValue( 3 );
@@ -42,6 +43,8 @@
   //disable ok button until there is text for output field and expression
   mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
 
+  mExistingFieldComboBox->setDisabled( true );
+
   // disable creation of new fields if not supported by data provider
   if ( !( vl->dataProvider()->capabilities() & QgsVectorDataProvider::AddAttributes ) )
   {
@@ -151,7 +154,12 @@
     // block layerModified signals (that would trigger table update)
     mVectorLayer->blockSignals( true );
 
-    bool useGeometry = calcString.contains( "$area" ) || calcString.contains( "$length" );
+    bool useGeometry =
+      calcString.contains( "$area" ) ||
+      calcString.contains( "$length" ) ||
+      calcString.contains( "$perimeter" ) ||
+      calcString.contains( "$x" ) ||
+      calcString.contains( "$y" );
     int rownum = 1;
 
     mVectorLayer->select( mVectorLayer->pendingAllAttributesList(), QgsRectangle(), useGeometry, false );
@@ -267,14 +275,8 @@
 
 void QgsFieldCalculator::on_mUpdateExistingFieldCheckBox_stateChanged( int state )
 {
-  if ( state == Qt::Checked )
-  {
-    mNewFieldGroupBox->setEnabled( false );
-  }
-  else
-  {
-    mNewFieldGroupBox->setEnabled( true );
-  }
+  mExistingFieldComboBox->setEnabled( state == Qt::Checked );
+  mNewFieldGroupBox->setDisabled( state == Qt::Checked );
   setOkButtonState();
 }
 

Modified: trunk/qgis/src/core/qgsdistancearea.cpp
===================================================================
--- trunk/qgis/src/core/qgsdistancearea.cpp	2011-03-07 16:45:27 UTC (rev 15380)
+++ trunk/qgis/src/core/qgsdistancearea.cpp	2011-03-07 20:57:51 UTC (rev 15381)
@@ -223,7 +223,7 @@
     case QGis::WKBPolygon25D:
       hasZptr = true;
     case QGis::WKBPolygon:
-      measurePolygon( wkb, &res, hasZptr );
+      measurePolygon( wkb, &res, 0, hasZptr );
       QgsDebugMsg( "returning " + QString::number( res ) );
       return res;
 
@@ -234,7 +234,7 @@
       ptr = wkb + 9;
       for ( i = 0; i < count; i++ )
       {
-        ptr = measurePolygon( ptr, &res, hasZptr );
+        ptr = measurePolygon( ptr, &res, 0, hasZptr );
         resTotal += res;
       }
       QgsDebugMsg( "returning " + QString::number( resTotal ) );
@@ -246,7 +246,60 @@
   }
 }
 
+double QgsDistanceArea::measurePerimeter( QgsGeometry* geometry )
+{
+  if ( !geometry )
+    return 0.0;
 
+  unsigned char* wkb = geometry->asWkb();
+  if ( !wkb )
+    return 0.0;
+
+  unsigned char* ptr;
+  unsigned int wkbType;
+  double res, resTotal = 0;
+  int count, i;
+
+  memcpy( &wkbType, ( wkb + 1 ), sizeof( wkbType ) );
+
+  // measure distance or area based on what is the type of geometry
+  bool hasZptr = false;
+
+  switch ( wkbType )
+  {
+    case QGis::WKBLineString25D:
+    case QGis::WKBLineString:
+    case QGis::WKBMultiLineString25D:
+    case QGis::WKBMultiLineString:
+      return 0.0;
+
+    case QGis::WKBPolygon25D:
+      hasZptr = true;
+    case QGis::WKBPolygon:
+      measurePolygon( wkb, 0, &res, hasZptr );
+      QgsDebugMsg( "returning " + QString::number( res ) );
+      return res;
+
+    case QGis::WKBMultiPolygon25D:
+      hasZptr = true;
+    case QGis::WKBMultiPolygon:
+      count = *(( int* )( wkb + 5 ) );
+      ptr = wkb + 9;
+      for ( i = 0; i < count; i++ )
+      {
+        ptr = measurePolygon( ptr, 0, &res, hasZptr );
+        resTotal += res;
+      }
+      QgsDebugMsg( "returning " + QString::number( resTotal ) );
+      return resTotal;
+
+    default:
+      QgsDebugMsg( QString( "measure: unexpected geometry type: %1" ).arg( wkbType ) );
+      return 0;
+  }
+}
+
+
 unsigned char* QgsDistanceArea::measureLine( unsigned char* feature, double* area, bool hasZptr )
 {
   unsigned char *ptr = feature + 5;
@@ -344,7 +397,7 @@
 }
 
 
-unsigned char* QgsDistanceArea::measurePolygon( unsigned char* feature, double* area, bool hasZptr )
+unsigned char* QgsDistanceArea::measurePolygon( unsigned char* feature, double* area, double* perimeter, bool hasZptr )
 {
   // get number of rings in the polygon
   unsigned int numRings = *(( int* )( feature + 1 + sizeof( int ) ) );
@@ -357,8 +410,11 @@
 
   QList<QgsPoint> points;
   QgsPoint pnt;
-  double x, y, areaTmp;
-  *area = 0;
+  double x, y;
+  if ( area )
+    *area = 0;
+  if ( perimeter )
+    *perimeter = 0;
 
   try
   {
@@ -392,20 +448,38 @@
 
       if ( points.size() > 2 )
       {
-        areaTmp = computePolygonArea( points );
-        if ( idx == 0 )
-          *area += areaTmp; // exterior ring
-        else
-          *area -= areaTmp; // interior rings
+        if ( area )
+        {
+          double areaTmp = computePolygonArea( points );
+          if ( idx == 0 )
+          {
+            // exterior ring
+            *area += areaTmp;
+          }
+          else
+          {
+            *area -= areaTmp; // interior rings
+          }
+        }
+
+        if ( perimeter )
+        {
+          *perimeter += measureLine( points );
+        }
       }
 
       points.clear();
+
+      if ( !area )
+      {
+        break;
+      }
     }
   }
   catch ( QgsCsException &cse )
   {
     Q_UNUSED( cse );
-    QgsLogger::warning( QObject::tr( "Caught a coordinate system exception while trying to transform a point. Unable to calculate polygon area." ) );
+    QgsLogger::warning( QObject::tr( "Caught a coordinate system exception while trying to transform a point. Unable to calculate polygon area or perimeter." ) );
   }
 
   return ptr;
@@ -679,7 +753,6 @@
 {
   QString unitLabel;
 
-
   switch ( u )
   {
     case QGis::Meters:
@@ -785,5 +858,4 @@
 
 
   return QLocale::system().toString( value, 'f', decimals ) + unitLabel;
-
 }

Modified: trunk/qgis/src/core/qgsdistancearea.h
===================================================================
--- trunk/qgis/src/core/qgsdistancearea.h	2011-03-07 16:45:27 UTC (rev 15380)
+++ trunk/qgis/src/core/qgsdistancearea.h	2011-03-07 20:57:51 UTC (rev 15381)
@@ -77,8 +77,12 @@
     //! general measurement (line distance or polygon area)
     double measure( QgsGeometry* geometry );
 
-    //! measures line with more segments
+    //! measures perimeter of polygon
+    double measurePerimeter( QgsGeometry* geometry );
+
+    //! measures line
     double measureLine( const QList<QgsPoint>& points );
+
     //! measures line with one segment
     double measureLine( const QgsPoint& p1, const QgsPoint& p2 );
 
@@ -91,11 +95,10 @@
     static QString textUnit( double value, int decimals, QGis::UnitType u, bool isArea, bool keepBaseUnit = false );
 
   protected:
-
     //! measures line distance, line points are extracted from WKB
     unsigned char* measureLine( unsigned char* feature, double* area, bool hasZptr = false );
-    //! measures polygon area, vertices are extracted from WKB
-    unsigned char* measurePolygon( unsigned char* feature, double* area, bool hasZptr = false );
+    //! measures polygon area and perimeter, vertices are extracted from WKB
+    unsigned char* measurePolygon( unsigned char* feature, double* area, double* perimeter, bool hasZptr = false );
 
     /**
       calculates distance from two points on ellipsoid

Modified: trunk/qgis/src/core/qgssearchstringlexer.ll
===================================================================
--- trunk/qgis/src/core/qgssearchstringlexer.ll	2011-03-07 16:45:27 UTC (rev 15380)
+++ trunk/qgis/src/core/qgssearchstringlexer.ll	2011-03-07 20:57:51 UTC (rev 15381)
@@ -121,6 +121,9 @@
 
 "$area" { return AREA; }
 "$length" { return LENGTH; }
+"$perimeter" { return PERIMETER; }
+"$x" { return X; }
+"$y" { return Y; }
 "$id" { return ID; }
 
 {column_ref}   { return COLUMN_REF; }

Modified: trunk/qgis/src/core/qgssearchstringparser.yy
===================================================================
--- trunk/qgis/src/core/qgssearchstringparser.yy	2011-03-07 16:45:27 UTC (rev 15380)
+++ trunk/qgis/src/core/qgssearchstringparser.yy	2011-03-07 20:57:51 UTC (rev 15381)
@@ -74,7 +74,10 @@
 %token IN
 %token ROWNUM
 %token AREA
+%token PERIMETER 
 %token LENGTH
+%token X
+%token Y
 %token ID
 %token NULLVALUE
 
@@ -177,7 +180,10 @@
     | scalar_exp CONCAT scalar_exp { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opCONCAT, $1, $3); joinTmpNodes($$, $1, $3); }
     | ROWNUM                      { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opROWNUM, 0, 0); addToTmpNodes($$); }
     | AREA                        { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opAREA, 0, 0); addToTmpNodes($$); }
+    | PERIMETER                   { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opPERIMETER, 0, 0); addToTmpNodes($$); }
     | LENGTH                      { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opLENGTH, 0, 0); addToTmpNodes($$); }
+    | X                           { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opX, 0, 0); addToTmpNodes($$); }
+    | Y                           { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opY, 0, 0); addToTmpNodes($$); }
     | ID                          { $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opID, 0, 0); addToTmpNodes($$); }
     | NUMBER                      { $$ = new QgsSearchTreeNode($1); addToTmpNodes($$); }
     | STRING                      { $$ = new QgsSearchTreeNode(QString::fromUtf8(yytext), 0); addToTmpNodes($$); }

Modified: trunk/qgis/src/core/qgssearchtreenode.cpp
===================================================================
--- trunk/qgis/src/core/qgssearchtreenode.cpp	2011-03-07 16:45:27 UTC (rev 15380)
+++ trunk/qgis/src/core/qgssearchtreenode.cpp	2011-03-07 20:57:51 UTC (rev 15381)
@@ -139,7 +139,7 @@
 {
   mCalc = NULL;
 
-  if ( mType == tOperator && ( mOp == opLENGTH || mOp == opAREA ) )
+  if ( mType == tOperator && ( mOp == opLENGTH || mOp == opAREA || mOp == opPERIMETER ) )
   {
     //initialize QgsDistanceArea
     mCalc = new QgsDistanceArea;
@@ -232,14 +232,17 @@
       // currently all functions take one parameter
       str += QString( "(%1)" ).arg( mLeft->makeSearchString() );
     }
-    else if ( mOp == opLENGTH || mOp == opAREA || mOp == opROWNUM || mOp == opID )
+    else if ( mOp == opLENGTH || mOp == opAREA || mOp == opPERIMETER || mOp == opROWNUM || mOp == opID || mOp == opX || mOp == opY )
     {
       // special nullary opeators
       switch ( mOp )
       {
         case opLENGTH: str += "$length"; break;
         case opAREA: str += "$area"; break;
+        case opPERIMETER: str += "$perimeter"; break;
         case opROWNUM: str += "$rownum"; break;
+        case opX: str += "$x"; break;
+        case opY: str += "$y"; break;
         case opID: str += "$id"; break;
         default: str += "?";
       }
@@ -361,7 +364,7 @@
 {
   if ( mType == tOperator )
   {
-    if ( mOp == opLENGTH || mOp == opAREA )
+    if ( mOp == opLENGTH || mOp == opAREA || mOp == opPERIMETER || mOp == opX || mOp == opY )
       return true;
 
     if ( mLeft && mLeft->needsGeometry() )
@@ -656,7 +659,7 @@
         if ( !getValue( value2, mRight, fields, f ) ) return value2;
       }
 
-      if ( mOp == opLENGTH || mOp == opAREA )
+      if ( mOp == opLENGTH || mOp == opAREA || mOp == opPERIMETER || mOp == opX || mOp == opY )
       {
         if ( !f.geometry() )
         {
@@ -664,15 +667,27 @@
         }
 
         //check that we don't use area for lines or length for polygons
-        if ( mOp == opLENGTH && f.geometry()->type() != QGis::Line )
+        if ( mOp == opLENGTH && f.geometry()->type() == QGis::Line )
         {
-          return QgsSearchTreeValue( 0 );
+          return QgsSearchTreeValue( mCalc->measure( f.geometry() ) );
         }
-        if ( mOp == opAREA && f.geometry()->type() != QGis::Polygon )
+        if ( mOp == opAREA && f.geometry()->type() == QGis::Polygon )
         {
-          return QgsSearchTreeValue( 0 );
+          return QgsSearchTreeValue( mCalc->measure( f.geometry() ) );
         }
-        return QgsSearchTreeValue( mCalc->measure( f.geometry() ) );
+        if ( mOp == opPERIMETER && f.geometry()->type() == QGis::Polygon )
+        {
+          return QgsSearchTreeValue( mCalc->measurePerimeter( f.geometry() ) );
+        }
+        if ( mOp == opX && f.geometry()->type() == QGis::Point )
+        {
+          return QgsSearchTreeValue( f.geometry()->asPoint().x() );
+        }
+        if ( mOp == opY && f.geometry()->type() == QGis::Point )
+        {
+          return QgsSearchTreeValue( f.geometry()->asPoint().y() );
+        }
+        return QgsSearchTreeValue( 0 );
       }
 
       if ( mOp == opID )

Modified: trunk/qgis/src/core/qgssearchtreenode.h
===================================================================
--- trunk/qgis/src/core/qgssearchtreenode.h	2011-03-07 16:45:27 UTC (rev 15380)
+++ trunk/qgis/src/core/qgssearchtreenode.h	2011-03-07 20:57:51 UTC (rev 15381)
@@ -82,9 +82,14 @@
       opTOREAL,
       opTOSTRING,
 
+      // coordinates
+      opX,
+      opY,
+
       // measuring
       opLENGTH,
       opAREA,
+      opPERIMETER,
 
       // feature id
       opID,



More information about the QGIS-commit mailing list