Пример #1
0
QgsAbstractGeometry *densifyGeometry( const QgsAbstractGeometry *geom, int extraNodesPerSegment = 1, double distance = 1 )
{
  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
  if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) )
  {
    segmentizedCopy.reset( geom->segmentize() );
    geom = segmentizedCopy.get();
  }

  if ( QgsWkbTypes::geometryType( geom->wkbType() ) == QgsWkbTypes::LineGeometry )
  {
    return doDensify( static_cast< const QgsLineString * >( geom ), extraNodesPerSegment, distance );
  }
  else
  {
    // polygon
    const QgsPolygon *polygon = static_cast< const QgsPolygon * >( geom );
    QgsPolygon *result = new QgsPolygon();

    result->setExteriorRing( doDensify( static_cast< const QgsLineString * >( polygon->exteriorRing() ),
                                        extraNodesPerSegment, distance ) );
    for ( int i = 0; i < polygon->numInteriorRings(); ++i )
    {
      result->addInteriorRing( doDensify( static_cast< const QgsLineString * >( polygon->interiorRing( i ) ),
                                          extraNodesPerSegment, distance ) );
    }

    return result;
  }
}
Пример #2
0
QDomElement QgsWFSServer::createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const
{
  if ( !geom )
  {
    return QDomElement();
  }

  QDomElement polygonElem = doc.createElement( "gml:Polygon" );
  QgsPolygon poly = geom->asPolygon();
  for ( int i = 0; i < poly.size(); ++i )
  {
    QString boundaryName;
    if ( i == 0 )
    {
      boundaryName = "outerBoundaryIs";
    }
    else
    {
      boundaryName = "innerBoundaryIs";
    }
    QDomElement boundaryElem = doc.createElementNS( "http://www.opengis.net/gml", boundaryName );
    QDomElement ringElem = doc.createElement( "gml:LinearRing" );
    QDomElement coordElem = createCoordinateElem( poly.at( i ), doc );
    ringElem.appendChild( coordElem );
    boundaryElem.appendChild( ringElem );
    polygonElem.appendChild( boundaryElem );
  }
  return polygonElem;
}
Пример #3
0
QgsAbstractGeometry *orthogonalizeGeom( const QgsAbstractGeometry *geom, int maxIterations, double tolerance, double lowerThreshold, double upperThreshold )
{
  std::unique_ptr< QgsAbstractGeometry > segmentizedCopy;
  if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) )
  {
    segmentizedCopy.reset( geom->segmentize() );
    geom = segmentizedCopy.get();
  }

  if ( QgsWkbTypes::geometryType( geom->wkbType() ) == QgsWkbTypes::LineGeometry )
  {
    return doOrthogonalize( static_cast< QgsLineString * >( geom->clone() ),
                            maxIterations, tolerance, lowerThreshold, upperThreshold );
  }
  else
  {
    // polygon
    const QgsPolygon *polygon = static_cast< const QgsPolygon * >( geom );
    QgsPolygon *result = new QgsPolygon();

    result->setExteriorRing( doOrthogonalize( static_cast< QgsLineString * >( polygon->exteriorRing()->clone() ),
                             maxIterations, tolerance, lowerThreshold, upperThreshold ) );
    for ( int i = 0; i < polygon->numInteriorRings(); ++i )
    {
      result->addInteriorRing( doOrthogonalize( static_cast< QgsLineString * >( polygon->interiorRing( i )->clone() ),
                               maxIterations, tolerance, lowerThreshold, upperThreshold ) );
    }

    return result;
  }
}
Пример #4
0
double QgsGeometryAnalyzer::perimeterMeasure( QgsGeometry* geometry, QgsDistanceArea& measure )
{
  double value = 0.00;
  if ( geometry->isMultipart() )
  {
    QgsMultiPolygon poly = geometry->asMultiPolygon();
    QgsMultiPolygon::iterator it;
    QgsPolygon::iterator jt;
    for ( it = poly.begin(); it != poly.end(); ++it )
    {
      for ( jt = it->begin(); jt != it->end(); ++jt )
      {
        value = value + measure.measure( QgsGeometry::fromPolyline( *jt ) );
      }
    }
  }
  else
  {
    QgsPolygon::iterator jt;
    QgsPolygon poly = geometry->asPolygon();
    for ( jt = poly.begin(); jt != poly.end(); ++jt )
    {
      value = value + measure.measure( QgsGeometry::fromPolyline( *jt ) );
    }
  }
  return value;
}
Пример #5
0
static bool _check_intersecting_rings( const QgsPolygon &polygon )
{
  // At this point we assume that input polygons are valid according to the OGC definition.
  // This means e.g. no duplicate points, polygons are simple (no butterfly shaped polygon with self-intersection),
  // internal rings are inside exterior rings, rings do not cross each other, no dangles.

  // There is however an issue with polygons where rings touch:
  //  +---+
  //  |   |
  //  | +-+-+
  //  | | | |
  //  | +-+ |
  //  |     |
  //  +-----+
  // This is a valid polygon with one exterior and one interior ring that touch at one point,
  // but poly2tri library does not allow interior rings touch each other or exterior ring.
  // TODO: Handle the situation better - rather than just detecting the problem, try to fix
  // it by converting touching rings into one ring.

  if ( polygon.numInteriorRings() > 0 )
  {
    QList<QgsGeometry> geomRings;
    geomRings << QgsGeometry( polygon.exteriorRing()->clone() );
    for ( int i = 0; i < polygon.numInteriorRings(); ++i )
      geomRings << QgsGeometry( polygon.interiorRing( i )->clone() );

    for ( int i = 0; i < geomRings.count(); ++i )
      for ( int j = i + 1; j < geomRings.count(); ++j )
      {
        if ( geomRings[i].intersects( geomRings[j] ) )
          return false;
      }
  }
  return true;
}
Пример #6
0
void QgsGeometryValidator::validatePolygon( int idx, const QgsPolygon &polygon )
{
  // check if holes are inside polygon
  for ( int i = 1; !mStop && 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 );
      emit errorFound( QgsGeometry::Error( msg ) );
      mErrorCount++;
    }
  }

  // check holes for intersections
  for ( int i = 1; !mStop && i < polygon.size(); i++ )
  {
    for ( int j = i + 1; !mStop && j < polygon.size(); j++ )
    {
      checkRingIntersections( idx, i, polygon[i], idx, j, polygon[j] );
    }
  }

  // check if rings are self-intersecting
  for ( int i = 0; !mStop && i < polygon.size(); i++ )
  {
    validatePolyline( i, polygon[i], true );
  }
}
Пример #7
0
static QgsPolygon *_transform_polygon_to_new_base( const QgsPolygon &polygon, const QgsPoint &pt0, const QMatrix4x4 *toNewBase )
{
  QgsPolygon *p = new QgsPolygon;
  p->setExteriorRing( _transform_ring_to_new_base( *polygon.exteriorRing(), pt0, toNewBase ) );
  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
    p->addInteriorRing( _transform_ring_to_new_base( *polygon.interiorRing( i ), pt0, toNewBase ) );
  return p;
}
Пример #8
0
QgsGeometry *QgsRubberBand::asGeometry()
{
  QgsGeometry *geom = NULL;

  switch ( mGeometryType )
  {
    case QGis::Polygon:
    {
      QgsPolygon polygon;
      QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
      for ( ; it != mPoints.constEnd(); ++it )
      {
        polygon.append( getPolyline( *it ) );
      }
      geom = QgsGeometry::fromPolygon( polygon );
      break;
    }

    case QGis::Point:
    {
      QgsMultiPoint multiPoint;

      QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
      for ( ; it != mPoints.constEnd(); ++it )
      {
        multiPoint += getPolyline( *it );
      }
      geom = QgsGeometry::fromMultiPoint( multiPoint );
      break;
    }

    case QGis::Line:
    default:
    {
      if ( mPoints.size() > 0 )
      {
        if ( mPoints.size() > 1 )
        {
          QgsMultiPolyline multiPolyline;
          QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
          for ( ; it != mPoints.constEnd(); ++it )
          {
            multiPolyline.append( getPolyline( *it ) );
          }
          geom = QgsGeometry::fromMultiPolyline( multiPolyline );
        }
        else
        {
          geom = QgsGeometry::fromPolyline( getPolyline( mPoints[0] ) );
        }
      }
      break;
    }
  }
  return geom;
}
Пример #9
0
int QgsMapToolDeleteRing::ringNumInPolygon( const QgsGeometry &g, int vertexNr )
{
  QgsPolygon polygon = g.asPolygon();
  for ( int ring = 0; ring < polygon.count(); ring++ )
  {
    if ( vertexNr < polygon[ring].count() )
      return ring;

    vertexNr -= polygon[ring].count();
  }
  return -1;
}
Пример #10
0
void QgsMapToolCapture::validateGeometry()
{
  QgsSettings settings;
  if ( settings.value( QStringLiteral( "qgis/digitizing/validate_geometries" ), 1 ).toInt() == 0 )
    return;

  if ( mValidator )
  {
    mValidator->deleteLater();
    mValidator = nullptr;
  }

  mGeomErrors.clear();
  while ( !mGeomErrorMarkers.isEmpty() )
  {
    delete mGeomErrorMarkers.takeFirst();
  }

  QgsGeometry geom;

  switch ( mCaptureMode )
  {
    case CaptureNone:
    case CapturePoint:
      return;
    case CaptureLine:
      if ( size() < 2 )
        return;
      geom = QgsGeometry( mCaptureCurve.curveToLine() );
      break;
    case CapturePolygon:
      if ( size() < 3 )
        return;
      QgsLineString *exteriorRing = mCaptureCurve.curveToLine();
      exteriorRing->close();
      QgsPolygon *polygon = new QgsPolygon();
      polygon->setExteriorRing( exteriorRing );
      geom = QgsGeometry( polygon );
      break;
  }

  if ( geom.isNull() )
    return;

  QgsGeometry::ValidationMethod method = QgsGeometry::ValidatorQgisInternal;
  if ( settings.value( QStringLiteral( "qgis/digitizing/validate_geometries" ), 1 ).toInt() == 2 )
    method = QgsGeometry::ValidatorGeos;
  mValidator = new QgsGeometryValidator( geom, nullptr, method );
  connect( mValidator, &QgsGeometryValidator::errorFound, this, &QgsMapToolCapture::addError );
  mValidator->start();
  QgsDebugMsgLevel( QStringLiteral( "Validation started" ), 4 );
}
Пример #11
0
QgsGeometry QgsInternalGeometryEngine::extrude( double x, double y ) const
{
  QVector<QgsLineString *> linesToProcess;

  const QgsMultiCurve *multiCurve = qgsgeometry_cast< const QgsMultiCurve * >( mGeometry );
  if ( multiCurve )
  {
    for ( int i = 0; i < multiCurve->partCount(); ++i )
    {
      linesToProcess << static_cast<QgsLineString *>( multiCurve->geometryN( i )->clone() );
    }
  }

  const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( mGeometry );
  if ( curve )
  {
    linesToProcess << static_cast<QgsLineString *>( curve->segmentize() );
  }

  std::unique_ptr<QgsMultiPolygon> multipolygon( linesToProcess.size() > 1 ? new QgsMultiPolygon() : nullptr );
  QgsPolygon *polygon = nullptr;

  if ( !linesToProcess.empty() )
  {
    std::unique_ptr< QgsLineString > secondline;
    for ( QgsLineString *line : qgis::as_const( linesToProcess ) )
    {
      QTransform transform = QTransform::fromTranslate( x, y );

      secondline.reset( line->reversed() );
      secondline->transform( transform );

      line->append( secondline.get() );
      line->addVertex( line->pointN( 0 ) );

      polygon = new QgsPolygon();
      polygon->setExteriorRing( line );

      if ( multipolygon )
        multipolygon->addGeometry( polygon );
    }

    if ( multipolygon )
      return QgsGeometry( multipolygon.release() );
    else
      return QgsGeometry( polygon );
  }

  return QgsGeometry();
}
Пример #12
0
QgsAbstractGeometryV2* QgsGeometryImport::fromRect( const QgsRectangle& rect )
{
  QgsPolyline ring;
  ring.append( QgsPoint( rect.xMinimum(), rect.yMinimum() ) );
  ring.append( QgsPoint( rect.xMaximum(), rect.yMinimum() ) );
  ring.append( QgsPoint( rect.xMaximum(), rect.yMaximum() ) );
  ring.append( QgsPoint( rect.xMinimum(), rect.yMaximum() ) );
  ring.append( QgsPoint( rect.xMinimum(), rect.yMinimum() ) );

  QgsPolygon polygon;
  polygon.append( ring );

  return fromPolygon( polygon );
}
Пример #13
0
void TestQgsTessellator::testBadCoordinates()
{
  // triangulation would crash for me with this polygon if there is no simplification
  // to remove the coordinates that are very close to each other
  QgsPolygon polygon;
  polygon.fromWkt( "POLYGON((1 1, 2 1, 2.0000001 1.0000001, 2.0000002 1.0000001, 2.0000001 1.0000002, 2.0000002 1.0000002, 3 2, 1 2, 1 1))" );

  QList<TriangleCoords> tc;
  tc << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 2, 1, 0 ), QVector3D( 3, 2, 0 ) );
  tc << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 1, 1, 0 ), QVector3D( 2, 1, 0 ) );

  QgsTessellator t( 0, 0, false );
  t.addPolygon( polygon, 0 );
  QVERIFY( checkTriangleOutput( t.data(), false, tc ) );
}
Пример #14
0
void TestQgsTessellator::asMultiPolygon()
{
  QgsPolygon polygon;
  polygon.fromWkt( "POLYGON((1 1, 2 1, 3 2, 1 2, 1 1))" );

  QgsPolygon polygonZ;
  polygonZ.fromWkt( "POLYGONZ((1 1 1, 2 1 2, 3 2 3, 1 2 4, 1 1 1))" );

  QgsTessellator t( 0, 0, false );
  t.addPolygon( polygon, 0 );
  QCOMPARE( t.asMultiPolygon()->asWkt(), QStringLiteral( "MultiPolygonZ (((1 2 0, 2 1 0, 3 2 0, 1 2 0)),((1 2 0, 1 1 0, 2 1 0, 1 2 0)))" ) );

  QgsTessellator t2( 0, 0, false );
  t2.addPolygon( polygonZ, 0 );
  QCOMPARE( t2.asMultiPolygon()->asWkt(), QStringLiteral( "MultiPolygonZ (((1 2 4, 2 1 2, 3 2 3, 1 2 4)),((1 2 4, 1 1 1, 2 1 2, 1 2 4)))" ) );
}
Пример #15
0
void QgsHighlight::paintPolygon( QPainter *p, QgsPolygon polygon )
{
  // OddEven fill rule by default
  QPainterPath path;

  p->setPen( mPen );
  p->setBrush( mBrush );

  for ( int i = 0; i < polygon.size(); i++ )
  {
    if ( polygon[i].empty() ) continue;

    QPolygonF ring;
    ring.reserve( polygon[i].size() + 1 );

    for ( int j = 0; j < polygon[i].size(); j++ )
    {
      //adding point only if it is more than a pixel appart from the previous one
      const QPointF cur = toCanvasCoordinates( polygon[i][j] ) - pos();
      if ( 0 == j || std::abs( ring.back().x() - cur.x() ) > 1 || std::abs( ring.back().y() - cur.y() ) > 1 )
      {
        ring.push_back( cur );
      }
    }

    ring.push_back( ring[ 0 ] );

    path.addPolygon( ring );
  }

  p->drawPath( path );
}
Пример #16
0
void QgsHighlight::paintPolygon( QPainter *p, QgsPolygon polygon )
{
  QPolygonF poly;

  // just ring outlines, no fill
  p->setPen( mPen );
  p->setBrush( Qt::NoBrush );

  for ( int i = 0; i < polygon.size(); i++ )
  {
    QPolygonF ring( polygon[i].size() + 1 );

    for ( int j = 0; j < polygon[i].size(); j++ )
    {
      ring[ j ] = toCanvasCoordinates( polygon[i][j] ) - pos();
    }

    ring[ polygon[i].size()] = ring[ 0 ];

    p->drawPolygon( ring );

    if ( i == 0 )
      poly = ring;
    else
      poly = poly.subtracted( ring );
  }

  // just fill, no outline
  p->setPen( Qt::NoPen );
  p->setBrush( mBrush );
  p->drawPolygon( poly );
}
Пример #17
0
static bool _check_intersecting_rings( const QgsPolygon &polygon )
{
  QList<QgsGeometry> geomRings;
  geomRings << QgsGeometry( polygon.exteriorRing()->clone() );
  for ( int i = 0; i < polygon.numInteriorRings(); ++i )
    geomRings << QgsGeometry( polygon.interiorRing( i )->clone() );

  // we need to make sure that the polygon has no rings with self-intersection: that may
  // crash the tessellator. The original geometry maybe have been valid and the self-intersection
  // was introduced when transforming to a new base (in a rare case when all points are not in the same plane)

  for ( int i = 0; i < geomRings.count(); ++i )
  {
    if ( !geomRings[i].isSimple() )
      return false;
  }

  // At this point we assume that input polygons are valid according to the OGC definition.
  // This means e.g. no duplicate points, polygons are simple (no butterfly shaped polygon with self-intersection),
  // internal rings are inside exterior rings, rings do not cross each other, no dangles.

  // There is however an issue with polygons where rings touch:
  //  +---+
  //  |   |
  //  | +-+-+
  //  | | | |
  //  | +-+ |
  //  |     |
  //  +-----+
  // This is a valid polygon with one exterior and one interior ring that touch at one point,
  // but poly2tri library does not allow interior rings touch each other or exterior ring.
  // TODO: Handle the situation better - rather than just detecting the problem, try to fix
  // it by converting touching rings into one ring.

  if ( polygon.numInteriorRings() > 0 )
  {
    for ( int i = 0; i < geomRings.count(); ++i )
      for ( int j = i + 1; j < geomRings.count(); ++j )
      {
        if ( geomRings[i].intersects( geomRings[j] ) )
          return false;
      }
  }
  return true;
}
Пример #18
0
double QgsGrassGisLib::G_area_of_polygon( const double *x, const double *y, int n )
{
    QgsPolyline polyline;
    for ( int i = 0; i < n; i++ )
    {
        polyline.append( QgsPoint( x[i], y[i] ) );
    }
    QgsPolygon polygon;
    polygon.append( polyline );
    QgsGeometry* geo = QgsGeometry::fromPolygon( polygon );
    double area = mDistanceArea.measure( geo );
    delete geo;
    if ( !mCrs.geographicFlag() )
    {
        area *= qPow( G_database_units_to_meters_factor(), 2 );
    }
    return area;
}
Пример #19
0
double _minimum_distance_between_coordinates( const QgsPolygon &polygon )
{
  double min_d = 1e20;
  auto it = polygon.vertices_begin();

  if ( it == polygon.vertices_end() )
    return min_d;

  QgsPoint p0 = *it;
  ++it;
  for ( ; it != polygon.vertices_end(); ++it )
  {
    QgsPoint p1 = *it;
    double d = p0.distance( p1 );
    if ( d < min_d )
      min_d = d;
    p0 = p1;
  }
  return min_d;
}
Пример #20
0
std::unique_ptr<QgsPolygonV2> QgsGeometryFactory::fromPolygon( const QgsPolygon &polygon )
{
  std::unique_ptr< QgsPolygonV2 > poly( new QgsPolygonV2() );

  QList<QgsCurve *> holes;
  for ( int i = 0; i < polygon.size(); ++i )
  {
    std::unique_ptr< QgsLineString > l = linestringFromPolyline( polygon.at( i ) );
    l->close();

    if ( i == 0 )
    {
      poly->setExteriorRing( l.release() );
    }
    else
    {
      holes.push_back( l.release() );
    }
  }
  poly->setInteriorRings( holes );
  return poly;
}
Пример #21
0
void TestQgsTessellator::testWalls()
{
  QgsPolygon polygonZ;
  polygonZ.fromWkt( "POLYGONZ((1 1 1, 2 1 2, 3 2 3, 1 2 4, 1 1 1))" );

  QList<TriangleCoords> tc;

  tc << TriangleCoords( QVector3D( 1, 2, 14 ), QVector3D( 2, 1, 12 ), QVector3D( 3, 2, 13 ) );
  tc << TriangleCoords( QVector3D( 1, 2, 14 ), QVector3D( 1, 1, 11 ), QVector3D( 2, 1, 12 ) );

  tc << TriangleCoords( QVector3D( 1, 1, 11 ), QVector3D( 1, 2, 14 ), QVector3D( 1, 1, 1 ) );
  tc << TriangleCoords( QVector3D( 1, 1, 1 ), QVector3D( 1, 2, 14 ), QVector3D( 1, 2, 4 ) );
  tc << TriangleCoords( QVector3D( 1, 2, 14 ), QVector3D( 3, 2, 13 ), QVector3D( 1, 2, 4 ) );
  tc << TriangleCoords( QVector3D( 1, 2, 4 ), QVector3D( 3, 2, 13 ), QVector3D( 3, 2, 3 ) );
  tc << TriangleCoords( QVector3D( 3, 2, 13 ), QVector3D( 2, 1, 12 ), QVector3D( 3, 2, 3 ) );
  tc << TriangleCoords( QVector3D( 3, 2, 3 ), QVector3D( 2, 1, 12 ), QVector3D( 2, 1, 2 ) );
  tc << TriangleCoords( QVector3D( 2, 1, 12 ), QVector3D( 1, 1, 11 ), QVector3D( 2, 1, 2 ) );
  tc << TriangleCoords( QVector3D( 2, 1, 2 ), QVector3D( 1, 1, 11 ), QVector3D( 1, 1, 1 ) );

  QgsTessellator tZ( 0, 0, false );
  tZ.addPolygon( polygonZ, 10 );
  QVERIFY( checkTriangleOutput( tZ.data(), false, tc ) );
}
Пример #22
0
void TestQgsTessellator::testBasic()
{
  QgsPolygon polygon;
  polygon.fromWkt( "POLYGON((1 1, 2 1, 3 2, 1 2, 1 1))" );

  QgsPolygon polygonZ;
  polygonZ.fromWkt( "POLYGONZ((1 1 0, 2 1 0, 3 2 0, 1 2 0, 1 1 0))" );

  QList<TriangleCoords> tc;
  tc << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 2, 1, 0 ), QVector3D( 3, 2, 0 ) );
  tc << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 1, 1, 0 ), QVector3D( 2, 1, 0 ) );

  QVector3D up( 0, 0, 1 );  // surface normal pointing straight up
  QList<TriangleCoords> tcNormals;
  tcNormals << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 2, 1, 0 ), QVector3D( 3, 2, 0 ), up, up, up );
  tcNormals << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 1, 1, 0 ), QVector3D( 2, 1, 0 ), up, up, up );

  // without normals

  QgsTessellator t( 0, 0, false );
  t.addPolygon( polygon, 0 );
  QVERIFY( checkTriangleOutput( t.data(), false, tc ) );

  QgsTessellator tZ( 0, 0, false );
  tZ.addPolygon( polygonZ, 0 );
  QVERIFY( checkTriangleOutput( tZ.data(), false, tc ) );

  // with normals

  QgsTessellator tN( 0, 0, true );
  tN.addPolygon( polygon, 0 );
  QVERIFY( checkTriangleOutput( tN.data(), true, tcNormals ) );

  QgsTessellator tNZ( 0, 0, true );
  tNZ.addPolygon( polygonZ, 0 );
  QVERIFY( checkTriangleOutput( tNZ.data(), true, tcNormals ) );
}
void CDTMapToolSelectTrainingSamples::canvasReleaseEvent(QgsMapMouseEvent *e)
{
    if ( e->button() == Qt::LeftButton )
    {
        if ( mDragging )
        {
            mCanvas->panActionEnd( e->pos() );
            mDragging = false;
        }
        else // add pan to mouse cursor
        {
            // transform the mouse pos to map coordinates
            QgsPoint center = mCanvas->getCoordinateTransform()->toMapPoint( e->x(), e->y() );
            mCanvas->setExtent( QgsRectangle( center, center ) );
            mCanvas->refresh();
        }
    }
    else if (e->button()==Qt::RightButton)
    {
        QgsVectorLayer* vlayer = NULL;
        if ( !mapCanvas->currentLayer()
             || ( vlayer = qobject_cast<QgsVectorLayer *>( mapCanvas->currentLayer() ) ) == NULL )
            return;

        QRect selectRect( 0, 0, 0, 0 );
        int boxSize = 1;
        selectRect.setLeft  ( e->pos().x() - boxSize );
        selectRect.setRight ( e->pos().x() + boxSize );
        selectRect.setTop   ( e->pos().y() - boxSize );
        selectRect.setBottom( e->pos().y() + boxSize );

        const QgsMapToPixel* transform = mapCanvas->getCoordinateTransform();
        QgsPoint ll = transform->toMapCoordinates( selectRect.left(), selectRect.bottom() );
        QgsPoint ur = transform->toMapCoordinates( selectRect.right(), selectRect.top() );

        QgsPolyline points;
        points.push_back(ll);
        points.push_back(QgsPoint( ur.x(), ll.y() ));
        points.push_back(ur);
        points.push_back(QgsPoint( ll.x(), ur.y() ));

        QgsPolygon polygon;
        polygon.push_back(points);
        QgsGeometry selectGeom = *(QgsGeometry::fromPolygon(polygon) );

        if ( mapCanvas->mapSettings().hasCrsTransformEnabled() )
        {
            QgsCoordinateTransform ct( mapCanvas->mapSettings().destinationCrs(), vlayer->crs() );
            selectGeom.transform( ct );
        }

        QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectGeom.boundingBox() ).setFlags( QgsFeatureRequest::ExactIntersect ) );
        QgsFeature f;
        qint64 closestFeatureId = 0;
        bool foundSingleFeature = false;
        double closestFeatureDist = std::numeric_limits<double>::max();
        while ( fit.nextFeature( f ) )
        {
            QgsGeometry* g = f.geometry();
            if ( !selectGeom.intersects( g ) )
                continue;
            foundSingleFeature = true;
            double distance = g->distance( selectGeom );
            if ( distance <= closestFeatureDist )
            {
                closestFeatureDist = distance;
                closestFeatureId = f.attribute("GridCode").toInt();
            }
        }

        if ( foundSingleFeature )
            addSingleSample( closestFeatureId );
    }
}
Пример #24
0
void QgsTessellator::addPolygon( const QgsPolygon &polygon, float extrusionHeight )
{
  if ( _minimum_distance_between_coordinates( polygon ) < 0.001 )
  {
    // when the distances between coordinates of input points are very small,
    // the triangulation likes to crash on numerical errors - when the distances are ~ 1e-5
    // Assuming that the coordinates should be in a projected CRS, we should be able
    // to simplify geometries that may cause problems and avoid possible crashes
    QgsGeometry polygonSimplified = QgsGeometry( polygon.clone() ).simplify( 0.001 );
    const QgsPolygon *polygonSimplifiedData = qgsgeometry_cast<const QgsPolygon *>( polygonSimplified.constGet() );
    if ( _minimum_distance_between_coordinates( *polygonSimplifiedData ) < 0.001 )
    {
      // Failed to fix that. It could be a really tiny geometry... or maybe they gave us
      // geometry in unprojected lat/lon coordinates
      QgsMessageLog::logMessage( "geometry's coordinates are too close to each other and simplification failed - skipping", "3D" );
    }
    else
    {
      addPolygon( *polygonSimplifiedData, extrusionHeight );
    }
    return;
  }

  if ( !_check_intersecting_rings( polygon ) )
  {
    // skip the polygon - it would cause a crash inside poly2tri library
    QgsMessageLog::logMessage( "polygon rings intersect each other - skipping", "3D" );
    return;
  }

  const QgsCurve *exterior = polygon.exteriorRing();

  QList< std::vector<p2t::Point *> > polylinesToDelete;
  QHash<p2t::Point *, float> z;

  std::vector<p2t::Point *> polyline;

  const QVector3D pNormal = _calculateNormal( exterior, mOriginX, mOriginY );
  const int pCount = exterior->numPoints();

  // Polygon is a triangle
  if ( pCount == 4 )
  {
    QgsPoint pt;
    QgsVertexId::VertexType vt;
    for ( int i = 0; i < 3; i++ )
    {
      exterior->pointAt( i, pt, vt );
      mData << pt.x() - mOriginX << pt.z() << - pt.y() + mOriginY;
      if ( mAddNormals )
        mData << pNormal.x() << pNormal.z() << - pNormal.y();
    }
  }
  else
  {
    if ( !qgsDoubleNear( pNormal.length(), 1, 0.001 ) )
      return;  // this should not happen - pNormal should be normalized to unit length

    QVector3D pXVector, pYVector;
    _normalVectorToXYVectors( pNormal, pXVector, pYVector );

    // so now we have three orthogonal unit vectors defining new base
    // let's build transform matrix. We actually need just a 3x3 matrix,
    // but Qt does not have good support for it, so using 4x4 matrix instead.
    QMatrix4x4 toNewBase(
      pXVector.x(), pXVector.y(), pXVector.z(), 0,
      pYVector.x(), pYVector.y(), pYVector.z(), 0,
      pNormal.x(), pNormal.y(), pNormal.z(), 0,
      0, 0, 0, 0 );

    // our 3x3 matrix is orthogonal, so for inverse we only need to transpose it
    QMatrix4x4 toOldBase = toNewBase.transposed();

    const QgsPoint ptFirst( exterior->startPoint() );
    _ringToPoly2tri( exterior, ptFirst, toNewBase, polyline, z );
    polylinesToDelete << polyline;

    // TODO: robustness (no nearly duplicate points, invalid geometries ...)

    double x0 = ptFirst.x(), y0 = ptFirst.y(), z0 = ( std::isnan( ptFirst.z() ) ? 0 : ptFirst.z() );
    if ( polyline.size() == 3 && polygon.numInteriorRings() == 0 )
    {
      for ( std::vector<p2t::Point *>::iterator it = polyline.begin(); it != polyline.end(); it++ )
      {
        p2t::Point *p = *it;
        QVector4D ptInNewBase( p->x, p->y, z[p], 0 );
        QVector4D nPoint = toOldBase * ptInNewBase;
        const double fx = nPoint.x() - mOriginX + x0;
        const double fy = nPoint.y() - mOriginY + y0;
        const double fz = nPoint.z() + extrusionHeight + z0;
        mData << fx << fz << -fy;
        if ( mAddNormals )
          mData << pNormal.x() << pNormal.z() << - pNormal.y();
      }
    }
    else if ( polyline.size() >= 3 )
    {
      p2t::CDT *cdt = new p2t::CDT( polyline );

      // polygon holes
      for ( int i = 0; i < polygon.numInteriorRings(); ++i )
      {
        std::vector<p2t::Point *> holePolyline;
        const QgsCurve *hole = polygon.interiorRing( i );

        _ringToPoly2tri( hole, ptFirst, toNewBase, holePolyline, z );

        cdt->AddHole( holePolyline );
        polylinesToDelete << holePolyline;
      }

      try
      {
        cdt->Triangulate();

        std::vector<p2t::Triangle *> triangles = cdt->GetTriangles();

        for ( size_t i = 0; i < triangles.size(); ++i )
        {
          p2t::Triangle *t = triangles[i];
          for ( int j = 0; j < 3; ++j )
          {
            p2t::Point *p = t->GetPoint( j );
            QVector4D ptInNewBase( p->x, p->y, z[p], 0 );
            QVector4D nPoint = toOldBase * ptInNewBase;
            const double fx = nPoint.x() - mOriginX + x0;
            const double fy = nPoint.y() - mOriginY + y0;
            const double fz = nPoint.z() + extrusionHeight + z0;
            mData << fx << fz << -fy;
            if ( mAddNormals )
              mData << pNormal.x() << pNormal.z() << - pNormal.y();
          }
        }
      }
      catch ( ... )
      {
        QgsMessageLog::logMessage( "Triangulation failed. Skipping polygon...", "3D" );
      }

      delete cdt;
    }

    for ( int i = 0; i < polylinesToDelete.count(); ++i )
      qDeleteAll( polylinesToDelete[i] );
  }

  // add walls if extrusion is enabled
  if ( extrusionHeight != 0 )
  {
    _makeWalls( *exterior, false, extrusionHeight, mData, mAddNormals, mOriginX, mOriginY );

    for ( int i = 0; i < polygon.numInteriorRings(); ++i )
      _makeWalls( *polygon.interiorRing( i ), true, extrusionHeight, mData, mAddNormals, mOriginX, mOriginY );
  }
}
Пример #25
0
void QgsDxfExport::addFeature( const QgsSymbolV2RenderContext& ctx, const QString& layer, const QgsSymbolLayerV2* symbolLayer, const QgsSymbolV2* symbol )
{
  const QgsFeature* fet = ctx.feature();
  if ( !fet )
  {
    return;
  }

  QgsGeometry* geom = fet->geometry();
  if ( geom )
  {
    int c = 0;
    if ( mSymbologyExport != NoSymbology )
    {
      c = colorFromSymbolLayer( symbolLayer, ctx );
    }
    double width = -1;
    if ( mSymbologyExport != NoSymbology && symbolLayer )
    {
      width = symbolLayer->dxfWidth( *this, ctx );
    }
    QString lineStyleName = "CONTINUOUS";
    if ( mSymbologyExport != NoSymbology )
    {
      lineStyleName = lineStyleFromSymbolLayer( symbolLayer );
    }
    QGis::WkbType geometryType = geom->wkbType();

    //single point
    if ( geometryType == QGis::WKBPoint || geometryType == QGis::WKBPoint25D )
    {
      writePoint( geom->asPoint(), layer, c, fet, symbolLayer, symbol );
    }

    //multipoint
    if ( geometryType == QGis::WKBMultiPoint || geometryType == QGis::WKBMultiPoint25D )
    {
      QgsMultiPoint multiPoint = geom->asMultiPoint();
      QgsMultiPoint::const_iterator it = multiPoint.constBegin();
      for ( ; it != multiPoint.constEnd(); ++it )
      {
        writePoint( *it, layer, c, fet, symbolLayer, symbol );
      }
    }

    //single line
    if ( geometryType == QGis::WKBLineString || geometryType == QGis::WKBLineString25D )
    {
      writePolyline( geom->asPolyline(), layer, lineStyleName, c, width, false );
    }

    //multiline
    if ( geometryType == QGis::WKBMultiLineString || geometryType == QGis::WKBMultiLineString25D )
    {
      QgsMultiPolyline multiLine = geom->asMultiPolyline();
      QgsMultiPolyline::const_iterator lIt = multiLine.constBegin();
      for ( ; lIt != multiLine.constEnd(); ++lIt )
      {
        writePolyline( *lIt, layer, lineStyleName, c, width, false );
      }
    }

    //polygon
    if ( geometryType == QGis::WKBPolygon || geometryType == QGis::WKBPolygon25D )
    {
      QgsPolygon polygon = geom->asPolygon();
      QgsPolygon::const_iterator polyIt = polygon.constBegin();
      for ( ; polyIt != polygon.constEnd(); ++polyIt ) //iterate over rings
      {
        writePolyline( *polyIt, layer, lineStyleName, c, width, true );
      }
    }

    //multipolygon or polygon
    if ( geometryType == QGis::WKBMultiPolygon || geometryType == QGis::WKBMultiPolygon25D )
    {
      QgsMultiPolygon mp = geom->asMultiPolygon();
      QgsMultiPolygon::const_iterator mpIt = mp.constBegin();
      for ( ; mpIt != mp.constEnd(); ++mpIt )
      {
        QgsPolygon::const_iterator polyIt = mpIt->constBegin();
        for ( ; polyIt != mpIt->constEnd(); ++polyIt )
        {
          writePolyline( *polyIt, layer, lineStyleName, c, width, true );
        }
      }
    }
  }
}
Пример #26
0
QgsGeometry* QgsTransectSample::clipBufferLine( QgsGeometry* stratumGeom, QgsGeometry* clippedBaseline, double tolerance )
{
  if ( !stratumGeom || !clippedBaseline || clippedBaseline->wkbType() == QGis::WKBUnknown )
  {
    return 0;
  }

  double currentBufferDist = tolerance;
  int maxLoops = 10;

  for ( int i = 0; i < maxLoops; ++i )
  {
    //loop with tolerance: create buffer, convert buffer to line, clip line by stratum, test if result is (single) line
    QgsGeometry* clipBaselineBuffer = clippedBaseline->buffer( currentBufferDist, 8 );
    if ( !clipBaselineBuffer )
    {
      delete clipBaselineBuffer;
      continue;
    }

    //it is also possible that clipBaselineBuffer is a multipolygon
    QgsGeometry* bufferLine = 0; //buffer line or multiline
    QgsGeometry* bufferLineClipped = 0;
    QgsMultiPolyline mpl;
    if ( clipBaselineBuffer->isMultipart() )
    {
      QgsMultiPolygon bufferMultiPolygon = clipBaselineBuffer->asMultiPolygon();
      if ( bufferMultiPolygon.size() < 1 )
      {
        delete clipBaselineBuffer;
        continue;
      }

      for ( int j = 0; j < bufferMultiPolygon.size(); ++j )
      {
        int size = bufferMultiPolygon.at( j ).size();
        for ( int k = 0; k < size; ++k )
        {
          mpl.append( bufferMultiPolygon.at( j ).at( k ) );
        }
      }
      bufferLine = QgsGeometry::fromMultiPolyline( mpl );
    }
    else
    {
      QgsPolygon bufferPolygon = clipBaselineBuffer->asPolygon();
      if ( bufferPolygon.size() < 1 )
      {
        delete clipBaselineBuffer;
        continue;
      }

      int size = bufferPolygon.size();
      for ( int j = 0; j < size; ++j )
      {
        mpl.append( bufferPolygon[j] );
      }
      bufferLine = QgsGeometry::fromMultiPolyline( mpl );
    }
    bufferLineClipped = bufferLine->intersection( stratumGeom );

    if ( bufferLineClipped && bufferLineClipped->type() == QGis::Line )
    {
      //if stratumGeom is a multipolygon, bufferLineClipped must intersect each part
      bool bufferLineClippedIntersectsStratum = true;
      if ( stratumGeom->wkbType() == QGis::WKBMultiPolygon || stratumGeom->wkbType() == QGis::WKBMultiPolygon25D )
      {
        QVector<QgsPolygon> multiPoly = stratumGeom->asMultiPolygon();
        QVector<QgsPolygon>::const_iterator multiIt = multiPoly.constBegin();
        for ( ; multiIt != multiPoly.constEnd(); ++multiIt )
        {
          QgsGeometry* poly = QgsGeometry::fromPolygon( *multiIt );
          if ( !poly->intersects( bufferLineClipped ) )
          {
            bufferLineClippedIntersectsStratum = false;
            delete poly;
            break;
          }
          delete poly;
        }
      }

      if ( bufferLineClippedIntersectsStratum )
      {
        return bufferLineClipped;
      }
    }

    delete bufferLineClipped; delete clipBaselineBuffer; delete bufferLine;
    currentBufferDist /= 2;
  }

  return 0; //no solution found even with reduced tolerances
}
int QgsVectorLayerEditUtils::addTopologicalPoints( QgsGeometry* geom )
{
  if ( !L->hasGeometryType() )
    return 1;

  if ( !geom )
  {
    return 1;
  }

  int returnVal = 0;

  QGis::WkbType wkbType = geom->wkbType();

  switch ( wkbType )
  {
      //line
    case QGis::WKBLineString25D:
    case QGis::WKBLineString:
    {
      QgsPolyline theLine = geom->asPolyline();
      QgsPolyline::const_iterator line_it = theLine.constBegin();
      for ( ; line_it != theLine.constEnd(); ++line_it )
      {
        if ( addTopologicalPoints( *line_it ) != 0 )
        {
          returnVal = 2;
        }
      }
      break;
    }

    //multiline
    case QGis::WKBMultiLineString25D:
    case QGis::WKBMultiLineString:
    {
      QgsMultiPolyline theMultiLine = geom->asMultiPolyline();
      QgsPolyline currentPolyline;

      for ( int i = 0; i < theMultiLine.size(); ++i )
      {
        QgsPolyline::const_iterator line_it = currentPolyline.constBegin();
        for ( ; line_it != currentPolyline.constEnd(); ++line_it )
        {
          if ( addTopologicalPoints( *line_it ) != 0 )
          {
            returnVal = 2;
          }
        }
      }
      break;
    }

    //polygon
    case QGis::WKBPolygon25D:
    case QGis::WKBPolygon:
    {
      QgsPolygon thePolygon = geom->asPolygon();
      QgsPolyline currentRing;

      for ( int i = 0; i < thePolygon.size(); ++i )
      {
        currentRing = thePolygon.at( i );
        QgsPolyline::const_iterator line_it = currentRing.constBegin();
        for ( ; line_it != currentRing.constEnd(); ++line_it )
        {
          if ( addTopologicalPoints( *line_it ) != 0 )
          {
            returnVal = 2;
          }
        }
      }
      break;
    }

    //multipolygon
    case QGis::WKBMultiPolygon25D:
    case QGis::WKBMultiPolygon:
    {
      QgsMultiPolygon theMultiPolygon = geom->asMultiPolygon();
      QgsPolygon currentPolygon;
      QgsPolyline currentRing;

      for ( int i = 0; i < theMultiPolygon.size(); ++i )
      {
        currentPolygon = theMultiPolygon.at( i );
        for ( int j = 0; j < currentPolygon.size(); ++j )
        {
          currentRing = currentPolygon.at( j );
          QgsPolyline::const_iterator line_it = currentRing.constBegin();
          for ( ; line_it != currentRing.constEnd(); ++line_it )
          {
            if ( addTopologicalPoints( *line_it ) != 0 )
            {
              returnVal = 2;
            }
          }
        }
      }
      break;
    }
    default:
      break;
  }
  return returnVal;
}
Пример #28
0
void TestQgsDistanceArea::measureAreaAndUnits()
{
  QgsDistanceArea da;
  da.setSourceCrs( 3452 );
  da.setEllipsoidalMode( false );
  da.setEllipsoid( "NONE" );
  QgsCoordinateReferenceSystem daCRS;
  daCRS.createFromSrsId( da.sourceCrsId() );
  QgsPolyline ring;
  ring << QgsPoint( 0, 0 )
  << QgsPoint( 1, 0 )
  << QgsPoint( 1, 1 )
  << QgsPoint( 2, 1 )
  << QgsPoint( 2, 2 )
  << QgsPoint( 0, 2 )
  << QgsPoint( 0, 0 );
  QgsPolygon poly;
  poly << ring;

  QgsGeometry polygon( QgsGeometry::fromPolygon( poly ) );

  // We check both the measured area AND the units, in case the logic regarding
  // ellipsoids and units changes in future
  double area = da.measureArea( &polygon );
  QgsUnitTypes::AreaUnit units = da.areaUnits();

  QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) );

  QVERIFY(( qgsDoubleNear( area, 3.0, 0.00000001 ) && units == QgsUnitTypes::AreaSquareDegrees )
          || ( qgsDoubleNear( area, 37176087091.5, 0.1 ) && units == QgsUnitTypes::AreaSquareMeters ) );

  da.setEllipsoid( "WGS84" );
  area = da.measureArea( &polygon );
  units = da.areaUnits();

  QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) );
  QVERIFY(( qgsDoubleNear( area, 3.0, 0.00000001 ) && units == QgsUnitTypes::AreaSquareDegrees )
          || ( qgsDoubleNear( area, 37176087091.5, 0.1 ) && units == QgsUnitTypes::AreaSquareMeters ) );

  da.setEllipsoidalMode( true );
  area = da.measureArea( &polygon );
  units = da.areaUnits();

  QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) );
  // should always be in Meters Squared
  QGSCOMPARENEAR( area, 37416879192.9, 0.1 );
  QCOMPARE( units, QgsUnitTypes::AreaSquareMeters );

  // test converting the resultant area
  area = da.convertAreaMeasurement( area, QgsUnitTypes::AreaSquareMiles );
  QGSCOMPARENEAR( area, 14446.7378, 0.001 );

  // now try with a source CRS which is in feet
  ring.clear();
  ring << QgsPoint( 1850000, 4423000 )
  << QgsPoint( 1851000, 4423000 )
  << QgsPoint( 1851000, 4424000 )
  << QgsPoint( 1852000, 4424000 )
  << QgsPoint( 1852000, 4425000 )
  << QgsPoint( 1851000, 4425000 )
  << QgsPoint( 1850000, 4423000 );
  poly.clear();
  poly << ring;
  polygon = QgsGeometry::fromPolygon( poly );

  da.setSourceCrs( 27469 );
  da.setEllipsoidalMode( false );
  // measurement should be in square feet
  area = da.measureArea( &polygon );
  units = da.areaUnits();
  QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) );
  QGSCOMPARENEAR( area, 2000000, 0.001 );
  QCOMPARE( units, QgsUnitTypes::AreaSquareFeet );

  // test converting the resultant area
  area = da.convertAreaMeasurement( area, QgsUnitTypes::AreaSquareYards );
  QGSCOMPARENEAR( area, 222222.2222, 0.001 );

  da.setEllipsoidalMode( true );
  // now should be in Square Meters again
  area = da.measureArea( &polygon );
  units = da.areaUnits();
  QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) );
  QGSCOMPARENEAR( area, 184149.37, 1.0 );
  QCOMPARE( units, QgsUnitTypes::AreaSquareMeters );

  // test converting the resultant area
  area = da.convertAreaMeasurement( area, QgsUnitTypes::AreaSquareYards );
  QgsDebugMsg( QString( "measured %1 in sq yrds" ).arg( area ) );
  QGSCOMPARENEAR( area, 220240.8172549, 0.00001 );
}
Пример #29
0
QgsGeometry* QgsTransectSample::clipBufferLine( const QgsGeometry& stratumGeom, QgsGeometry* clippedBaseline, double tolerance )
{
  if ( !stratumGeom || !clippedBaseline || clippedBaseline->wkbType() == QgsWkbTypes::Unknown )
  {
    return nullptr;
  }

  QgsGeometry usedBaseline = *clippedBaseline;
  if ( mBaselineSimplificationTolerance >= 0 )
  {
    //int verticesBefore = usedBaseline->asMultiPolyline().count();
    usedBaseline = clippedBaseline->simplify( mBaselineSimplificationTolerance );
    if ( usedBaseline.isEmpty() )
    {
      return nullptr;
    }
    //int verticesAfter = usedBaseline->asMultiPolyline().count();

    //debug: write to file
    /*QgsVectorFileWriter debugWriter( "/tmp/debug.shp", "utf-8", QgsFields(), QgsWkbTypes::LineString, &( mStrataLayer->crs() ) );
    QgsFeature debugFeature; debugFeature.setGeometry( usedBaseline );
    debugWriter.addFeature( debugFeature );*/
  }

  double currentBufferDist = tolerance;
  int maxLoops = 10;

  for ( int i = 0; i < maxLoops; ++i )
  {
    //loop with tolerance: create buffer, convert buffer to line, clip line by stratum, test if result is (single) line
    QgsGeometry clipBaselineBuffer = usedBaseline.buffer( currentBufferDist, 8 );
    if ( clipBaselineBuffer.isEmpty() )
    {
      continue;
    }

    //it is also possible that clipBaselineBuffer is a multipolygon
    QgsGeometry bufferLine; //buffer line or multiline
    QgsGeometry bufferLineClipped;
    QgsMultiPolyline mpl;
    if ( clipBaselineBuffer.isMultipart() )
    {
      QgsMultiPolygon bufferMultiPolygon = clipBaselineBuffer.asMultiPolygon();
      if ( bufferMultiPolygon.size() < 1 )
      {
        continue;
      }

      for ( int j = 0; j < bufferMultiPolygon.size(); ++j )
      {
        int size = bufferMultiPolygon.at( j ).size();
        for ( int k = 0; k < size; ++k )
        {
          mpl.append( bufferMultiPolygon.at( j ).at( k ) );
        }
      }
      bufferLine = QgsGeometry::fromMultiPolyline( mpl );
    }
    else
    {
      QgsPolygon bufferPolygon = clipBaselineBuffer.asPolygon();
      if ( bufferPolygon.size() < 1 )
      {
        continue;
      }

      int size = bufferPolygon.size();
      mpl.reserve( size );
      for ( int j = 0; j < size; ++j )
      {
        mpl.append( bufferPolygon[j] );
      }
      bufferLine = QgsGeometry::fromMultiPolyline( mpl );
    }
    bufferLineClipped = bufferLine.intersection( stratumGeom );

    if ( bufferLineClipped.isEmpty() && bufferLineClipped.type() == QgsWkbTypes::LineGeometry )
    {
      //if stratumGeom is a multipolygon, bufferLineClipped must intersect each part
      bool bufferLineClippedIntersectsStratum = true;
      if ( stratumGeom.wkbType() == QgsWkbTypes::MultiPolygon || stratumGeom.wkbType() == QgsWkbTypes::MultiPolygon25D )
      {
        QVector<QgsPolygon> multiPoly = stratumGeom.asMultiPolygon();
        QVector<QgsPolygon>::const_iterator multiIt = multiPoly.constBegin();
        for ( ; multiIt != multiPoly.constEnd(); ++multiIt )
        {
          QgsGeometry poly = QgsGeometry::fromPolygon( *multiIt );
          if ( !poly.intersects( bufferLineClipped ) )
          {
            bufferLineClippedIntersectsStratum = false;
            break;
          }
        }
      }

      if ( bufferLineClippedIntersectsStratum )
      {
        return new QgsGeometry( bufferLineClipped );
      }
    }

    currentBufferDist /= 2;
  }

  return nullptr; //no solution found even with reduced tolerances
}
Пример #30
0
void QgsMapToolAddPart::canvasReleaseEvent( QMouseEvent * e )
{
  //check if we operate on a vector layer
  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
  if ( !vlayer )
  {
    notifyNotVectorLayer();
    return;
  }

  if ( !vlayer->isEditable() )
  {
    notifyNotEditableLayer();
    return;
  }

  //inform user at the begin of the digitising action that the island tool only works if exactly one feature is selected
  int nSelectedFeatures = vlayer->selectedFeatureCount();
  QString selectionErrorMsg;
  if ( nSelectedFeatures < 1 )
  {
    selectionErrorMsg = tr( "No feature selected. Please select a feature with the selection tool or in the attribute table" );
  }
  else if ( nSelectedFeatures > 1 )
  {
    selectionErrorMsg = tr( "Several features are selected. Please select only one feature to which an part should be added." );
  }

  if ( !selectionErrorMsg.isEmpty() )
  {
    QMessageBox::critical( 0, tr( "Error. Could not add part." ), selectionErrorMsg );
    stopCapturing();
    return;
  }

  int errorCode;
  switch ( mode() )
  {
    case CapturePoint:
    {
      QgsPoint layerPoint;
      QgsPoint mapPoint;

      if ( nextPoint( e->pos(), layerPoint, mapPoint ) != 0 )
      {
        QgsDebugMsg( "nextPoint failed" );
        return;
      }

      vlayer->beginEditCommand( tr( "Part added" ) );
      errorCode = vlayer->addPart( QList<QgsPoint>() << layerPoint );
    }
    break;

    case CaptureLine:
    case CapturePolygon:
    {
      //add point to list and to rubber band
      if ( e->button() == Qt::LeftButton )
      {
        int error = addVertex( e->pos() );
        if ( error == 1 )
        {
          QgsDebugMsg( "current layer is not a vector layer" );
          return;
        }
        else if ( error == 2 )
        {
          //problem with coordinate transformation
          QMessageBox::information( 0,
                                    tr( "Coordinate transform error" ),
                                    tr( "Cannot transform the point to the layers coordinate system" ) );
          return;
        }

        startCapturing();
        return;
      }
      else if ( e->button() != Qt::RightButton )
      {
        deleteTempRubberBand();

        return;
      }

      if ( mode() == CapturePolygon )
      {
        //close polygon
        closePolygon();
        //avoid intersections
        QgsGeometry* geom = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() );
        if ( geom )
        {
          geom->avoidIntersections();
          QgsPolygon poly = geom->asPolygon();
          if ( poly.size() < 1 )
          {
            stopCapturing();
            delete geom;
            vlayer->destroyEditCommand();
            return;
          }
          setPoints( geom->asPolygon()[0].toList() );
          delete geom;
        }
      }

      vlayer->beginEditCommand( tr( "Part added" ) );
      errorCode = vlayer->addPart( points() );

      stopCapturing();
    }
    break;
    default:
      Q_ASSERT( !"invalid capture mode" );
      errorCode = 6;
      break;
  }

  QString errorMessage;
  switch ( errorCode )
  {
    case 0:
    {
      //add points to other features to keep topology up-to-date
      int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 );
      if ( topologicalEditing )
      {
        addTopologicalPoints( points() );
      }

      vlayer->endEditCommand();

      mCanvas->refresh();
      return;
    }

    case 1:
      errorMessage = tr( "Selected feature is not multi part." );
      break;

    case 2:
      errorMessage = tr( "New part's geometry is not valid." );
      break;

    case 3:
      errorMessage = tr( "New polygon ring not disjoint with existing polygons." );
      break;

    case 4:
      errorMessage = tr( "No feature selected. Please select a feature with the selection tool or in the attribute table" );
      break;

    case 5:
      errorMessage = tr( "Several features are selected. Please select only one feature to which an island should be added." );
      break;

    case 6:
      errorMessage = tr( "Selected geometry could not be found" );
      break;
  }

  QMessageBox::critical( 0, tr( "Error, could not add part" ), errorMessage );
  vlayer->destroyEditCommand();
}