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 );
  }
}
Beispiel #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;
}
Beispiel #3
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 );
}
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 );
}
Beispiel #5
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;
}
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();
}
Beispiel #7
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
}
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;
}
Beispiel #9
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
}
Beispiel #10
0
ErrorList topolTest::checkSegmentLength( double tolerance, QgsVectorLayer* layer1, QgsVectorLayer* layer2, bool isExtent )
{
  Q_UNUSED( layer1 );
  Q_UNUSED( layer2 );
  Q_UNUSED( isExtent );

  int i = 0;
  ErrorList errorList;
  QgsFeature f;


  QList<FeatureLayer>::Iterator it;
  QList<FeatureLayer>::ConstIterator FeatureListEnd = mFeatureList1.end();

  QgsPolygon pol;

  QgsMultiPolygon mpol;
  QgsPolyline segm;
  QgsPolyline ls;
  QgsMultiPolyline mls;
  QList<FeatureLayer> fls;
  TopolErrorShort* err;
  double distance;

  for ( it = mFeatureList1.begin(); it != FeatureListEnd; ++it )
  {
    if ( !( ++i % 100 ) )
    {
      emit progress( i );
    }

    if ( testCancelled() )
    {
      break;
    }

    QgsGeometry* g1 = it->feature.geometry();


    // switching by type here, because layer can contain both single and multi version geometries
    switch ( g1->wkbType() )
    {
      case QGis::WKBLineString:
      case QGis::WKBLineString25D:
        ls = g1->asPolyline();


        for ( int i = 1; i < ls.size(); ++i )
        {
          distance = sqrt( ls[i-1].sqrDist( ls[i] ) );
          if ( distance < tolerance )
          {
            fls.clear();
            fls << *it << *it;
            segm.clear();
            segm << ls[i-1] << ls[i];
            QgsGeometry* conflict = QgsGeometry::fromPolyline( segm );
            err = new TopolErrorShort( g1->boundingBox(), conflict, fls );
            //err = new TopolErrorShort(g1->boundingBox(), QgsGeometry::fromPolyline(segm), fls);
            errorList << err;
            //break on getting the first error
            break;
          }
        }
        break;

      case QGis::WKBPolygon:
      case QGis::WKBPolygon25D:
        pol = g1->asPolygon();

        for ( int i = 0; i < pol.size(); ++i )
        {
          for ( int j = 1; j < pol[i].size(); ++j )
          {
            distance =  sqrt( pol[i][j-1].sqrDist( pol[i][j] ) );
            if ( distance < tolerance )
            {
              fls.clear();
              fls << *it << *it;
              segm.clear();
              segm << pol[i][j-1] << pol[i][j];
              QgsGeometry* conflict = QgsGeometry::fromPolyline( segm );
              err = new TopolErrorShort( g1->boundingBox(), conflict, fls );
              errorList << err;
              //break on getting the first error
              break;
            }
          }
        }

        break;

      case QGis::WKBMultiLineString:
      case QGis::WKBMultiLineString25D:
        mls = g1->asMultiPolyline();

        for ( int k = 0; k < mls.size(); ++k )
        {
          QgsPolyline& ls = mls[k];
          for ( int i = 1; i < ls.size(); ++i )
          {
            distance = sqrt( ls[i-1].sqrDist( ls[i] ) );
            if ( distance < tolerance )
            {
              fls.clear();
              fls << *it << *it;
              segm.clear();
              segm << ls[i-1] << ls[i];
              QgsGeometry* conflict = QgsGeometry::fromPolyline( segm );
              err = new TopolErrorShort( g1->boundingBox(), conflict, fls );
              errorList << err;
              //break on getting the first error
              break;
            }
          }
        }
        break;

      case QGis::WKBMultiPolygon:
      case QGis::WKBMultiPolygon25D:
        mpol = g1->asMultiPolygon();

        for ( int k = 0; k < mpol.size(); ++k )
        {
          QgsPolygon& pol = mpol[k];
          for ( int i = 0; i < pol.size(); ++i )
          {
            for ( int j = 1; j < pol[i].size(); ++j )
            {
              distance = pol[i][j-1].sqrDist( pol[i][j] );
              if ( distance < tolerance )
              {
                fls.clear();
                fls << *it << *it;
                segm.clear();
                segm << pol[i][j-1] << pol[i][j];
                QgsGeometry* conflict = QgsGeometry::fromPolyline( segm );
                err = new TopolErrorShort( g1->boundingBox(), conflict, fls );
                errorList << err;
                //break on getting the first error
                break;
              }
            }
          }
        }
        break;

      default:
        continue;
    }
  }

  return errorList;
}