[QGIS Commit] r12749 - in trunk/qgis/src: app core
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Tue Jan 12 13:17:34 EST 2010
Author: jef
Date: 2010-01-12 13:17:34 -0500 (Tue, 12 Jan 2010)
New Revision: 12749
Modified:
trunk/qgis/src/app/qgsmaptoolnodetool.cpp
trunk/qgis/src/app/qgsmaptoolnodetool.h
trunk/qgis/src/core/qgsgeometry.cpp
trunk/qgis/src/core/qgsgeometry.h
trunk/qgis/src/core/qgspoint.cpp
trunk/qgis/src/core/qgspoint.h
Log:
[FEATURE] allow editing of invalid geometry in node tool
Modified: trunk/qgis/src/app/qgsmaptoolnodetool.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolnodetool.cpp 2010-01-12 18:15:55 UTC (rev 12748)
+++ trunk/qgis/src/app/qgsmaptoolnodetool.cpp 2010-01-12 18:17:34 UTC (rev 12749)
@@ -24,8 +24,12 @@
#include <math.h>
#include <QMouseEvent>
#include <QMessageBox>
+#include "qgslogger.h"
+#include "qgisapp.h"
+#include <QStatusBar>
+
QgsRubberBand* QgsMapToolNodeTool::createRubberBandMarker( QgsPoint center, QgsVectorLayer* vlayer )
{
//create rubber band marker for moving points
@@ -128,7 +132,7 @@
catch ( ... )
{
//GEOS is throwing exception when polygon is not valid to be able to edit it
- //Only possibility to fix this operation sice node tool doesn't allow to strore invalid geometry after editing
+ //Only possibility to fix this operation since node tool doesn't allow to store invalid geometry after editing
mSelectionFeature->updateFromFeature();
//if it does update markers just to be sure of correctness
}
@@ -148,7 +152,7 @@
for ( int i = 0; i < vertexMap.size(); i++ )
{
//create rubber band
- if ( vertexMap[i].selected && !( vertexMap[i].inRubberBand ) )
+ if ( vertexMap[i].selected && !vertexMap[i].inRubberBand )
{
geometry->adjacentVertices( i, beforeVertex, afterVertex );
vertex = i;
@@ -774,7 +778,7 @@
mTopologyMovingVertexes.clear();
mTopologyRubberBandVertexes.clear();
- //remove all data from selected feature (no change to rubber bands itself
+ //remove all data from selected feature (no change to rubber bands itself)
if ( mSelectionFeature != NULL )
mSelectionFeature->cleanRubberBandsData();
}
@@ -936,10 +940,48 @@
{
mFeature = feature;
}
+
//createvertexmap
createVertexMap();
+
+ validateGeometry();
}
+void SelectionFeature::validateGeometry( QgsGeometry *g )
+{
+ QgsDebugMsg( "validating geometry" );
+
+ if ( g == NULL )
+ g = mFeature->geometry();
+
+ g->validateGeometry( mGeomErrors );
+
+ while ( !mGeomErrorMarkers.isEmpty() )
+ {
+ delete mGeomErrorMarkers.takeFirst();
+ }
+
+ QString tip;
+
+ for ( int i = 0; i < mGeomErrors.size(); i++ )
+ {
+ tip += mGeomErrors[i].what() + "\n";
+ if ( !mGeomErrors[i].hasWhere() )
+ continue;
+
+ QgsVertexMarker *vm = createVertexMarker( mGeomErrors[i].where(), QgsVertexMarker::ICON_X );
+ vm->setToolTip( mGeomErrors[i].what() );
+ vm->setColor( Qt::green );
+ vm->setZValue( vm->zValue() + 1 );
+ mGeomErrorMarkers << vm;
+ }
+
+ QStatusBar *sb = QgisApp::instance()->statusBar();
+ sb->showMessage( QObject::tr( "%n geometry error(s) found.", "number of geometry errors", mGeomErrors.size() ) );
+ if ( !tip.isEmpty() )
+ sb->setToolTip( tip );
+}
+
void SelectionFeature::deleteSelectedVertexes()
{
int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
@@ -983,7 +1025,10 @@
}
QgsFeature f;
mVlayer->featureAtId( mFeatureId, f, true, false );
- if ( !GEOSisValid( f.geometry()->asGeos() ) )
+
+ bool wasValid = false; // mGeomErrors.isEmpty();
+ bool isValid = GEOSisValid( f.geometry()->asGeos() );
+ if ( wasValid && !isValid )
{
QMessageBox::warning( NULL,
tr( "Node tool" ),
@@ -992,7 +1037,7 @@
QMessageBox::Ok );
}
- if ( count != 0 && GEOSisValid( f.geometry()->asGeos() ) )
+ if ( count != 0 && ( !wasValid || isValid ) )
{
mVlayer->endEditCommand();
}
@@ -1054,7 +1099,9 @@
}
QgsFeature f;
mVlayer->featureAtId( mFeatureId, f, true, false );
- if ( !GEOSisValid( f.geometry()->asGeos() ) )
+ bool wasValid = false; // mGeomErrors.isEmpty();
+ bool isValid = GEOSisValid( f.geometry()->asGeos() );
+ if ( wasValid && !isValid )
{
QMessageBox::warning( NULL,
tr( "Node tool" ),
@@ -1068,17 +1115,18 @@
else
{
mVlayer->endEditCommand();
+ validateGeometry( f.geometry() );
}
updateFeature();
}
-QgsVertexMarker* SelectionFeature::createVertexMarker( QgsPoint center )
+QgsVertexMarker *SelectionFeature::createVertexMarker( QgsPoint center, QgsVertexMarker::IconType type )
{
- QgsVertexMarker* marker = new QgsVertexMarker( mCanvas );
+ QgsVertexMarker *marker = new QgsVertexMarker( mCanvas );
QgsPoint newCenter = mCanvas->mapRenderer()->layerToMapCoordinates( mVlayer, center );
marker->setCenter( newCenter );
- marker->setIconType( QgsVertexMarker::ICON_BOX );
+ marker->setIconType( type );
marker->setColor( Qt::red );
@@ -1103,6 +1151,11 @@
VertexEntry entry = mVertexMap.takeLast();
delete entry.vertexMarker;
}
+
+ while ( !mGeomErrorMarkers.isEmpty() )
+ {
+ delete mGeomErrorMarkers.takeFirst();
+ }
}
bool SelectionFeature::isSelected( int vertexNr )
@@ -1134,6 +1187,7 @@
entry.originalIndex = i;
entry.inRubberBand = false;
QgsVertexMarker* marker = createVertexMarker( poly[i] );
+ marker->setToolTip( tr( "ring %1, vertex %2" ).arg( i2 ).arg( i ) );
entry.vertexMarker = marker;
mVertexMap.insert( y + i, entry );
}
@@ -1161,7 +1215,7 @@
entry.originalIndex = y + i - 1;
entry.inRubberBand = false;
QgsVertexMarker* marker = createVertexMarker( poly[i] );
-
+ marker->setToolTip( tr( "polygon %1, ring %2, vertex %3" ).arg( i2 ).arg( i3 ).arg( i ) );
entry.vertexMarker = marker;
mVertexMap.insert( y + i, entry );
}
@@ -1194,6 +1248,7 @@
entry.originalIndex = i;
entry.inRubberBand = false;
QgsVertexMarker* marker = createVertexMarker( poly[i] );
+ marker->setToolTip( tr( "polyline %1, vertex %2" ).arg( i2 ).arg( i ) );
entry.vertexMarker = marker;
mVertexMap.insert( y + i, entry );
}
@@ -1214,6 +1269,7 @@
entry.originalIndex = i;
entry.inRubberBand = false;
QgsVertexMarker* marker = createVertexMarker( poly[i] );
+ marker->setToolTip( tr( "vertex %1" ).arg( i ) );
entry.vertexMarker = marker;
mVertexMap.insert( i, entry );
}
@@ -1236,6 +1292,7 @@
entry.originalIndex = 1;
entry.inRubberBand = false;
QgsVertexMarker* marker = createVertexMarker( poly[i] );
+ marker->setToolTip( tr( "point %1" ).arg( i ) );
entry.vertexMarker = marker;
mVertexMap.insert( i, entry );
}
@@ -1251,6 +1308,7 @@
entry.originalIndex = 1;
entry.inRubberBand = false;
QgsVertexMarker* marker = createVertexMarker( poly );
+ marker->setToolTip( tr( "single point" ) );
entry.vertexMarker = marker;
mVertexMap.insert( 1, entry );
}
@@ -1372,4 +1430,3 @@
{
return mVlayer;
}
-
Modified: trunk/qgis/src/app/qgsmaptoolnodetool.h
===================================================================
--- trunk/qgis/src/app/qgsmaptoolnodetool.h 2010-01-12 18:15:55 UTC (rev 12748)
+++ trunk/qgis/src/app/qgsmaptoolnodetool.h 2010-01-12 18:17:34 UTC (rev 12749)
@@ -161,7 +161,7 @@
* @param center center of marker
* @return created vertex marker
*/
- QgsVertexMarker* createVertexMarker( QgsPoint center );
+ QgsVertexMarker* createVertexMarker( QgsPoint center, QgsVertexMarker::IconType type = QgsVertexMarker::ICON_BOX );
/**
* Getter for getting vector layer which selection is working
@@ -171,7 +171,6 @@
private:
-
/**
* Deletes whole vertex map.
*/
@@ -198,10 +197,15 @@
void createVertexMapPoint();
/**
- * Updates stored feauture to actual one loaded from layer
+ * Updates stored feature to actual one loaded from layer
*/
void updateFeature();
+ /**
+ * Validates the geometry
+ */
+ void validateGeometry( QgsGeometry *g = NULL );
+
QgsFeature* mFeature;
int mFeatureId;
bool mFeatureSelected;
@@ -209,6 +213,9 @@
QgsRubberBand* mRubberBand;
QList<VertexEntry> mVertexMap;
QgsMapCanvas* mCanvas;
+
+ QList< QgsGeometry::Error > mGeomErrors;
+ QList< QgsVertexMarker * > mGeomErrorMarkers;
};
/**A maptool to move/deletes/adds vertices of line or polygon features*/
@@ -367,7 +374,6 @@
/** flag to tell if edition points */
bool mIsPoint;
-
};
Modified: trunk/qgis/src/core/qgsgeometry.cpp
===================================================================
--- trunk/qgis/src/core/qgsgeometry.cpp 2010-01-12 18:15:55 UTC (rev 12748)
+++ trunk/qgis/src/core/qgsgeometry.cpp 2010-01-12 18:17:34 UTC (rev 12749)
@@ -2360,7 +2360,7 @@
return -1;
const GEOSGeometry *g = GEOSGetExteriorRing( mGeos );
- if ( g == NULL )
+ if ( !g )
return -1;
const GEOSCoordSequence *sequence = GEOSGeom_getCoordSeq( g );
@@ -5442,7 +5442,7 @@
testPoints.clear();
GEOSGeometry* intersectionGeom = GEOSIntersection( mGeos, splitLine );
- if ( intersectionGeom == NULL )
+ if ( !intersectionGeom )
{
return 1;
}
@@ -5853,17 +5853,17 @@
double QgsGeometry::distance( QgsGeometry& geom )
{
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
}
- if ( geom.mGeos == NULL )
+ if ( !geom.mGeos )
{
geom.exportWkbToGeos();
}
- if ( mGeos == NULL || geom.mGeos == NULL )
+ if ( !mGeos || !geom.mGeos )
return -1.0;
double dist = -1.0;
@@ -5880,7 +5880,7 @@
QgsGeometry* QgsGeometry::buffer( double distance, int segments )
{
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
}
@@ -5898,7 +5898,7 @@
QgsGeometry* QgsGeometry::simplify( double tolerance )
{
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
}
@@ -5915,7 +5915,7 @@
QgsGeometry* QgsGeometry::centroid()
{
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
}
@@ -5932,7 +5932,7 @@
QgsGeometry* QgsGeometry::convexHull()
{
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
}
@@ -5950,15 +5950,15 @@
QgsGeometry* QgsGeometry::intersection( QgsGeometry* geometry )
{
- if ( geometry == NULL )
+ if ( !geometry )
{
return NULL;
}
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
}
- if ( geometry->mGeos == NULL )
+ if ( !geometry->mGeos )
{
geometry->exportWkbToGeos();
}
@@ -5976,15 +5976,15 @@
QgsGeometry* QgsGeometry::combine( QgsGeometry* geometry )
{
- if ( geometry == NULL )
+ if ( !geometry )
{
return NULL;
}
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
}
- if ( geometry->mGeos == NULL )
+ if ( !geometry->mGeos )
{
geometry->exportWkbToGeos();
}
@@ -6015,15 +6015,15 @@
QgsGeometry* QgsGeometry::difference( QgsGeometry* geometry )
{
- if ( geometry == NULL )
+ if ( !geometry )
{
return NULL;
}
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
}
- if ( geometry->mGeos == NULL )
+ if ( !geometry->mGeos )
{
geometry->exportWkbToGeos();
}
@@ -6041,15 +6041,15 @@
QgsGeometry* QgsGeometry::symDifference( QgsGeometry* geometry )
{
- if ( geometry == NULL )
+ if ( !geometry )
{
return NULL;
}
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
}
- if ( geometry->mGeos == NULL )
+ if ( !geometry->mGeos )
{
geometry->exportWkbToGeos();
}
@@ -6067,10 +6067,10 @@
QList<QgsGeometry*> QgsGeometry::asGeometryCollection()
{
- if ( mGeos == NULL )
+ if ( !mGeos )
{
exportWkbToGeos();
- if ( mGeos == NULL )
+ if ( !mGeos )
return QList<QgsGeometry*>();
}
@@ -6258,3 +6258,228 @@
return returnValue;
}
+
+//
+// distance of point q from line through p in direction v
+// return >0 => q lies left of the line
+// <0 => q lies right of the line
+//
+static double distLine2Point( QgsPoint p, QgsVector v, QgsPoint q )
+{
+ if ( v.length() == 0 )
+ {
+ throw QgsException( QObject::tr( "invalid line" ) );
+ }
+
+ return ( v.x()*( q.y() - p.y() ) - v.y()*( q.x() - p.x() ) ) / v.length();
+}
+
+static bool intersectLines( QgsPoint p, QgsVector v, QgsPoint q, QgsVector w, QgsPoint &s )
+{
+ double d = v.y() * w.x() - v.x() * w.y();
+
+ if ( d == 0 )
+ return false;
+
+ double dx = q.x() - p.x();
+ double dy = q.y() - p.y();
+ double k = ( dy * w.x() - dx * w.y() ) / d;
+
+ s = p + v * k;
+
+ return true;
+}
+
+bool pointInRing( const QgsPolyline &ring, const QgsPoint &p )
+{
+ bool inside = false;
+ int j = ring.size() - 1;
+
+ for ( int i = 0; i < ring.size(); i++ )
+ {
+ if ( ring[i].x() == p.x() && ring[i].y() == p.y() )
+ return true;
+
+ if (( ring[i].y() < p.y() && ring[j].y() >= p.y() ) ||
+ ( ring[j].y() < p.y() && ring[i].y() >= p.y() ) )
+ {
+ if ( ring[i].x() + ( p.y() - ring[i].y() ) / ( ring[j].y() - ring[i].y() )*( ring[j].x() - ring[i].x() ) <= p.x() )
+ inside = !inside;
+ }
+
+ j = i;
+ }
+
+ return inside;
+}
+
+static bool ringInRing( const QgsPolyline &inside, const QgsPolyline &outside )
+{
+ for ( int i = 0; i < inside.size(); i++ )
+ {
+ if ( !pointInRing( outside, inside[i] ) )
+ return false;
+ }
+
+ return true;
+}
+
+bool ringIntersectsRing( const QgsPolyline &ring0, const QgsPolyline &ring1 )
+{
+ bool inside = false;
+ bool outside = false;
+
+ for ( int i = 0; i < ring0.size(); i++ )
+ {
+ if ( pointInRing( ring1, ring0[i] ) )
+ {
+ inside = true;
+ }
+ else
+ {
+ outside = true;
+ }
+
+ if ( outside && inside )
+ return true;
+ }
+
+ return false;
+}
+
+void QgsGeometry::validatePolyline( QList<Error> &errors, int i, const QgsPolyline &line )
+{
+ if ( line.size() < 2 )
+ {
+ QString msg = QObject::tr( "line %1 with less than two points" ).arg( i );
+ QgsDebugMsg( msg );
+ errors << Error( msg );
+ return;
+ }
+
+ bool closed = line[0] == line[ line.size()-1 ];
+
+ if ( closed && line.size() < 3 )
+ {
+ QString msg = QObject::tr( "ring %1 with less than three points" ).arg( i );
+ QgsDebugMsg( msg );
+ errors << Error( msg );
+ return;
+ }
+
+ for ( int j = 0; j < line.size() - 3; j++ )
+ {
+ QgsVector v = line[j+1] - line[j];
+
+ int n = j == 0 && closed ? line.size() - 2 : line.size() - 1;
+
+ for ( int k = j + 2; k < n; k++ )
+ {
+ QgsVector w = line[k+1] - line[k];
+
+ QgsPoint s;
+ if ( intersectLines( line[j], v, line[k], w, s ) )
+ {
+ double d = -distLine2Point( line[j], v.perpVector(), s );
+
+ if ( d >= 0 && d <= v.length() )
+ {
+ d = -distLine2Point( line[k], w.perpVector(), s );
+ if ( d >= 0 && d <= w.length() )
+ {
+ QString msg = QObject::tr( "segments %1 and %2 of line %3 intersect at %4" ).arg( j ).arg( k ).arg( i ).arg( s.toString() );
+ QgsDebugMsg( msg );
+ errors << Error( msg, s );
+ if ( errors.size() > 100 )
+ {
+ QString msg = QObject::tr( "stopping validation after more than 100 errors" );
+ QgsDebugMsg( msg );
+ errors << Error( msg );
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void QgsGeometry::validatePolygon( QList<Error> &errors, int idx, const QgsPolygon &polygon )
+{
+ for ( int i = 1; i < polygon.size(); i++ )
+ {
+ if ( !ringInRing( polygon[i], polygon[0] ) )
+ {
+ QString msg = QObject::tr( "ring %1 of polygon %2 not in exterior ring" ).arg( i ).arg( idx );
+ QgsDebugMsg( msg );
+ errors << Error( msg );
+ }
+ }
+
+ for ( int i = 1; i < polygon.size(); i++ )
+ {
+ for ( int j = i + 1; j < polygon.size(); j++ )
+ {
+ if ( ringIntersectsRing( polygon[i], polygon[j] ) )
+ {
+ QString msg = QObject::tr( "interior rings %1 and %2 of polygon %3 intersect" ).arg( i ).arg( j ).arg( idx );
+ QgsDebugMsg( msg );
+ errors << Error( msg );
+ }
+ }
+ }
+
+ for ( int i = 0; i < polygon.size(); i++ )
+ {
+ validatePolyline( errors, i, polygon[i] );
+ }
+}
+
+void QgsGeometry::validateGeometry( QList<Error> &errors )
+{
+ errors.clear();
+
+ switch ( wkbType() )
+ {
+ case QGis::WKBPoint:
+ case QGis::WKBPoint25D:
+ case QGis::WKBMultiPoint:
+ case QGis::WKBMultiPoint25D:
+ break;
+
+ case QGis::WKBLineString:
+ case QGis::WKBLineString25D:
+ validatePolyline( errors, 0, asPolyline() );
+ break;
+
+ case QGis::WKBMultiLineString:
+ case QGis::WKBMultiLineString25D:
+ {
+ QgsMultiPolyline mp = asMultiPolyline();
+ for ( int i = 0; i < mp.size(); i++ )
+ validatePolyline( errors, i, mp[i] );
+ }
+ break;
+
+ case QGis::WKBPolygon:
+ case QGis::WKBPolygon25D:
+ {
+ validatePolygon( errors, 0, asPolygon() );
+ }
+ break;
+
+ case QGis::WKBMultiPolygon:
+ case QGis::WKBMultiPolygon25D:
+ {
+ QgsMultiPolygon mp = asMultiPolygon();
+ for ( int i = 0; i < mp.size(); i++ )
+ validatePolygon( errors, i, mp[i] );
+ }
+ break;
+
+ case QGis::WKBUnknown:
+ QgsDebugMsg( QObject::tr( "Unknown geometry type" ) );
+ errors << Error( QObject::tr( "Unknown geometry type" ) );
+ break;
+ }
+}
Modified: trunk/qgis/src/core/qgsgeometry.h
===================================================================
--- trunk/qgis/src/core/qgsgeometry.h 2010-01-12 18:15:55 UTC (rev 12748)
+++ trunk/qgis/src/core/qgsgeometry.h 2010-01-12 18:17:34 UTC (rev 12749)
@@ -362,6 +362,23 @@
*/
int avoidIntersections();
+
+ class Error
+ {
+ QString message;
+ QgsPoint location;
+ bool hasLocation;
+ public:
+ Error( QString m ) : message( m ), hasLocation( false ) {}
+ Error( QString m, QgsPoint p ) : message( m ), location( p ), hasLocation( true ) {}
+
+ QString what() { return message; };
+ QgsPoint where() { return location; }
+ bool hasWhere() { return hasLocation; }
+ };
+
+ void validateGeometry( QList<Error> &errors );
+
private:
// Private variables
@@ -494,6 +511,9 @@
/** return polygon from wkb */
QgsPolygon asPolygon( unsigned char*& ptr, bool hasZValue );
+ void validatePolyline( QList<Error> &errors, int i, const QgsPolyline &polygon );
+ void validatePolygon( QList<Error> &errors, int i, const QgsPolygon &polygon );
+
static int refcount;
}; // class QgsGeometry
Modified: trunk/qgis/src/core/qgspoint.cpp
===================================================================
--- trunk/qgis/src/core/qgspoint.cpp 2010-01-12 18:15:55 UTC (rev 12748)
+++ trunk/qgis/src/core/qgspoint.cpp 2010-01-12 18:17:34 UTC (rev 12749)
@@ -22,7 +22,96 @@
#include <QTextStream>
#include <QObject> // for tr()
+#include "qgsexception.h"
+//
+// QgsVector
+//
+
+QgsVector::QgsVector() : m_x( 0.0 ), m_y( 0.0 )
+{
+}
+
+QgsVector::QgsVector( double x, double y ) : m_x( x ), m_y( y )
+{
+}
+
+QgsVector QgsVector::operator-( void ) const
+{
+ return QgsVector( -m_x, -m_y );
+}
+
+QgsVector QgsVector::operator*( double scalar ) const
+{
+ return QgsVector( m_x*scalar, m_y*scalar );
+}
+
+QgsVector QgsVector::operator/( double scalar ) const
+{
+ return *this * ( 1.0 / scalar );
+}
+
+double QgsVector::operator*( QgsVector v ) const
+{
+ return m_x*v.m_x + m_y*v.m_y;
+}
+
+double QgsVector::length() const
+{
+ return sqrt( m_x*m_x + m_y*m_y );
+}
+
+double QgsVector::x() const
+{
+ return m_x;
+}
+
+double QgsVector::y() const
+{
+ return m_y;
+}
+
+// perpendicular vector (rotated 90° counter-clockwise)
+QgsVector QgsVector::perpVector() const
+{
+ return QgsVector( -m_y, m_x );
+}
+
+double QgsVector::angle( void ) const
+{
+ double ang = atan2( m_y, m_x );
+ return ang < 0.0 ? ang + 2.0*M_PI : ang;
+}
+
+double QgsVector::angle( QgsVector v ) const
+{
+ return v.angle() - angle();
+}
+
+QgsVector QgsVector::rotateBy( double rot ) const
+{
+ double ang = atan2( m_y, m_x ) + rot;
+ double len = length();
+ return QgsVector( len*cos( ang ), len*sin( ang ) );
+}
+
+QgsVector QgsVector::normal() const
+{
+ double len = length();
+
+ if ( len == 0.0 )
+ {
+ throw QgsException( "normal vector of null vector undefined" );
+ }
+
+ return *this / len;
+}
+
+
+//
+// QgsPoint
+//
+
QgsPoint::QgsPoint( const QgsPoint& p )
{
m_x = p.x();
Modified: trunk/qgis/src/core/qgspoint.h
===================================================================
--- trunk/qgis/src/core/qgspoint.h 2010-01-12 18:15:55 UTC (rev 12748)
+++ trunk/qgis/src/core/qgspoint.h 2010-01-12 18:17:34 UTC (rev 12749)
@@ -20,10 +20,41 @@
#define QGSPOINT_H
#include <iostream>
-
#include <QString>
/** \ingroup core
+ * A class to represent a vector.
+ * Currently no Z axis / 2.5D support is implemented.
+ */
+
+class CORE_EXPORT QgsVector
+{
+ double m_x, m_y;
+
+ public:
+ QgsVector();
+ QgsVector( double x, double y );
+
+ QgsVector operator-( void ) const;
+ QgsVector operator*( double scalar ) const;
+ QgsVector operator/( double scalar ) const;
+ double operator*( QgsVector v ) const;
+ double length() const;
+
+ double x() const;
+ double y() const;
+
+ // perpendicular vector (rotated 90° counter-clockwise)
+ QgsVector perpVector() const;
+
+ double angle( void ) const;
+ double angle( QgsVector v ) const;
+ QgsVector rotateBy( double rot ) const;
+ QgsVector normal() const;
+
+};
+
+/** \ingroup core
* A class to represent a point geometry.
* Currently no Z axis / 2.5D support is implemented.
*/
@@ -131,6 +162,12 @@
//! 3 if point is on open ray b.
int onSegment( const QgsPoint& a, const QgsPoint& b ) const;
+ QgsVector operator-( QgsPoint p ) const { return QgsVector( m_x - p.m_x, m_y - p.m_y ); }
+ QgsPoint &operator+=( const QgsVector &v ) { *this = *this + v; return *this; }
+ QgsPoint &operator-=( const QgsVector &v ) { *this = *this - v; return *this; }
+ QgsPoint operator+( const QgsVector &v ) const { return QgsPoint( m_x + v.x(), m_y + v.y() ); }
+ QgsPoint operator-( const QgsVector &v ) const { return QgsPoint( m_x - v.x(), m_y - v.y() ); }
+
private:
//! x coordinate
@@ -158,6 +195,4 @@
return os;
}
-
#endif //QGSPOINT_H
-
More information about the QGIS-commit
mailing list