static void _makeWalls( const QgsCurve &ring, bool ccw, float extrusionHeight, QVector<float> &data, bool addNormals, double originX, double originY ) { // we need to find out orientation of the ring so that the triangles we generate // face the right direction // (for exterior we want clockwise order, for holes we want counter-clockwise order) bool is_counter_clockwise = _isRingCounterClockWise( ring ); QgsVertexId::VertexType vt; QgsPoint pt; QgsPoint ptPrev; ring.pointAt( is_counter_clockwise == ccw ? 0 : ring.numPoints() - 1, ptPrev, vt ); for ( int i = 1; i < ring.numPoints(); ++i ) { ring.pointAt( is_counter_clockwise == ccw ? i : ring.numPoints() - i - 1, pt, vt ); float x0 = ptPrev.x() - originX, y0 = ptPrev.y() - originY; float x1 = pt.x() - originX, y1 = pt.y() - originY; float z0 = ptPrev.z(); float z1 = pt.z(); // make a quad make_quad( x0, y0, z0, x1, y1, z1, extrusionHeight, data, addNormals ); ptPrev = pt; } }
bool QgsCurvePolygon::insertVertex( QgsVertexId vId, const QgsPoint &vertex ) { if ( !mExteriorRing || vId.ring < 0 || vId.ring >= 1 + mInteriorRings.size() ) { return false; } QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings.at( vId.ring - 1 ); int n = ring->numPoints(); bool success = ring->insertVertex( QgsVertexId( 0, 0, vId.vertex ), vertex ); if ( !success ) { return false; } // If first or last vertex is inserted, re-sync the last/first vertex if ( vId.vertex == 0 ) ring->moveVertex( QgsVertexId( 0, 0, n ), vertex ); else if ( vId.vertex == n ) ring->moveVertex( QgsVertexId( 0, 0, 0 ), vertex ); clearCache(); return true; }
bool QgsTriangle::moveVertex( QgsVertexId vId, const QgsPointV2 &newPos ) { if ( !mExteriorRing || vId.part != 0 || vId.ring != 0 || vId.vertex < 0 || vId.vertex > 4 ) { return false; } if ( vId.vertex == 4 ) { vId.vertex = 0; } QgsPointV2 p1( vId.vertex == 0 ? newPos : vertexAt( 0 ) ); QgsPointV2 p2( vId.vertex == 1 ? newPos : vertexAt( 1 ) ); QgsPointV2 p3( vId.vertex == 2 ? newPos : vertexAt( 2 ) ); if ( !validateGeom( p1, p2, p3 ) ) { return false; } QgsCurve *ring = mExteriorRing; int n = ring->numPoints(); bool success = ring->moveVertex( vId, newPos ); if ( success ) { // If first or last vertex is moved, also move the last/first vertex if ( vId.vertex == 0 ) ring->moveVertex( QgsVertexId( vId.part, vId.ring, n - 1 ), newPos ); clearCache(); } return success; }
bool QgsCurvePolygon::deleteVertex( QgsVertexId vId ) { if ( !mExteriorRing || vId.ring < 0 || vId.ring >= 1 + mInteriorRings.size() ) { return false; } QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings.at( vId.ring - 1 ); int n = ring->numPoints(); if ( n <= 4 ) { //no points will be left in ring, so remove whole ring if ( vId.ring == 0 ) { mExteriorRing.reset(); if ( !mInteriorRings.isEmpty() ) { mExteriorRing.reset( mInteriorRings.takeFirst() ); } } else { removeInteriorRing( vId.ring - 1 ); } clearCache(); return true; } bool success = ring->deleteVertex( vId ); if ( success ) { // If first or last vertex is removed, re-sync the last/first vertex // Do not use "n - 2", but "ring->numPoints() - 1" as more than one vertex // may have been deleted (e.g. with CircularString) if ( vId.vertex == 0 ) ring->moveVertex( QgsVertexId( 0, 0, ring->numPoints() - 1 ), ring->vertexAt( QgsVertexId( 0, 0, 0 ) ) ); else if ( vId.vertex == n - 1 ) ring->moveVertex( QgsVertexId( 0, 0, 0 ), ring->vertexAt( QgsVertexId( 0, 0, ring->numPoints() - 1 ) ) ); clearCache(); } return success; }
static bool _isRingCounterClockWise( const QgsCurve &ring ) { double a = 0; int count = ring.numPoints(); QgsVertexId::VertexType vt; QgsPoint pt, ptPrev; ring.pointAt( 0, ptPrev, vt ); for ( int i = 1; i < count + 1; ++i ) { ring.pointAt( i % count, pt, vt ); a += ptPrev.x() * pt.y() - ptPrev.y() * pt.x(); ptPrev = pt; } return a > 0; // clockwise if a is negative }
bool QgsCurvePolygon::moveVertex( QgsVertexId vId, const QgsPoint &newPos ) { if ( !mExteriorRing || vId.ring < 0 || vId.ring >= 1 + mInteriorRings.size() ) { return false; } QgsCurve *ring = vId.ring == 0 ? mExteriorRing.get() : mInteriorRings.at( vId.ring - 1 ); int n = ring->numPoints(); bool success = ring->moveVertex( vId, newPos ); if ( success ) { // If first or last vertex is moved, also move the last/first vertex if ( vId.vertex == 0 ) ring->moveVertex( QgsVertexId( vId.part, vId.ring, n - 1 ), newPos ); else if ( vId.vertex == n - 1 ) ring->moveVertex( QgsVertexId( vId.part, vId.ring, 0 ), newPos ); clearCache(); } return success; }
QgsGeometry::OperationResult QgsGeometryEditUtils::addPart( QgsAbstractGeometry *geom, std::unique_ptr<QgsAbstractGeometry> part ) { if ( !geom ) { return QgsGeometry::InvalidBaseGeometry; } if ( !part ) { return QgsGeometry::InvalidInput; } //multitype? QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( geom ); if ( !geomCollection ) { return QgsGeometry::AddPartNotMultiGeometry; } bool added = false; if ( QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::MultiSurface || QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::MultiPolygon ) { QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( part.get() ); if ( curve && curve->isClosed() && curve->numPoints() >= 4 ) { std::unique_ptr<QgsCurvePolygon> poly; if ( QgsWkbTypes::flatType( curve->wkbType() ) == QgsWkbTypes::LineString ) { poly = qgis::make_unique< QgsPolygonV2 >(); } else { poly = qgis::make_unique< QgsCurvePolygon >(); } // Ownership is still with part, curve points to the same object and is transferred // to poly here. part.release(); poly->setExteriorRing( curve ); added = geomCollection->addGeometry( poly.release() ); } else if ( QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::Polygon ) { added = geomCollection->addGeometry( part.release() ); } else if ( QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::MultiPolygon ) { std::unique_ptr<QgsGeometryCollection> parts( static_cast<QgsGeometryCollection *>( part.release() ) ); int i; int n = geomCollection->numGeometries(); for ( i = 0; i < parts->numGeometries() && geomCollection->addGeometry( parts->geometryN( i )->clone() ); i++ ) ; added = i == parts->numGeometries(); if ( !added ) { while ( geomCollection->numGeometries() > n ) geomCollection->removeGeometry( n ); return QgsGeometry::InvalidInput; } } else { return QgsGeometry::InvalidInput; } } else { added = geomCollection->addGeometry( part.release() ); } return added ? QgsGeometry::Success : QgsGeometry::InvalidInput; }