Skip to content
Open
16 changes: 16 additions & 0 deletions app/inpututils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,22 @@ bool InputUtils::isEmptyGeometry( const QgsGeometry &geometry )
return geometry.isEmpty();
}

bool InputUtils::isLastPartEmpty( const QgsGeometry &geometry )
{
if ( geometry.isEmpty() )
return true;

const QgsAbstractGeometry *geom = geometry.constGet();
if ( const QgsGeometryCollection *collection = qgsgeometry_cast<const QgsGeometryCollection *>( geom ) )
{
const int parts = collection->partCount();
const QgsAbstractGeometry *lastPart = collection->geometryN( parts - 1 );
return lastPart->isEmpty();
}

return false;
}

QgsPoint InputUtils::coordinateToPoint( const QGeoCoordinate &coor )
{
return QgsPoint( coor.longitude(), coor.latitude(), coor.altitude() );
Expand Down
5 changes: 5 additions & 0 deletions app/inpututils.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ class InputUtils: public QObject
*/
Q_INVOKABLE static bool isEmptyGeometry( const QgsGeometry &geometry );

/**
* Returns true when the last part of the geometry is empty, also implicitly for null or empty geometry
*/
Q_INVOKABLE static bool isLastPartEmpty( const QgsGeometry &geometry );

/**
* Converts QGeoCoordinate to QgsPoint
*/
Expand Down
56 changes: 53 additions & 3 deletions app/maptools/recordingmaptool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -926,10 +926,23 @@ void RecordingMapTool::lookForVertex( const QPointF &clickedPoint, double search
}
}

// Update the previously grabbed point's position
if ( mState == MapToolState::Grab )
switch ( mState )
{
updateVertex( mActiveVertex, mRecordPoint );
case MapToolState::Grab:
// Update the previously grabbed point's position
updateVertex( mActiveVertex, mRecordPoint );
break;
case MapToolState::Record:
// If we were adding a line or poly part but did not add any points yet,
// we need to drop the added empty part
if ( InputUtils::isLastPartEmpty( mRecordedGeometry ) )
{
mRecordedGeometry.deletePart( mActivePart );
emit recordedGeometryChanged( mRecordedGeometry );
}
break;
case MapToolState::View:
break;
}

if ( idx >= 0 )
Expand Down Expand Up @@ -1150,6 +1163,43 @@ void RecordingMapTool::cancelGrab()
setActiveVertex( Vertex() );
}

void RecordingMapTool::startDigitizingNewPart()
{
// cancel grab and switch to record
// we'll add a new empty part at the end (unless there's one already) and set it active
setActiveVertex( Vertex() );
setState( RecordingMapTool::MapToolState::Record );

QgsAbstractGeometry *geom = mRecordedGeometry.get();
if ( QgsGeometryCollection *collection = qgsgeometry_cast<QgsGeometryCollection *>( geom ) )
{
switch ( mRecordedGeometry.type() )
{
case Qgis::GeometryType::Line:
if ( !InputUtils::isLastPartEmpty( mRecordedGeometry ) )
{
collection->addGeometry( new QgsLineString() );
emit recordedGeometryChanged( mRecordedGeometry );
}
setActivePartAndRing( collection->partCount() - 1, 0 );
break;
case Qgis::GeometryType::Polygon:
if ( !InputUtils::isLastPartEmpty( mRecordedGeometry ) )
{
collection->addGeometry( new QgsPolygon( new QgsLineString(), QList<QgsLineString *>() ) );
emit recordedGeometryChanged( mRecordedGeometry );
}
setActivePartAndRing( collection->partCount() - 1, 0 );
break;
case Qgis::GeometryType::Point:
// MultiPoints do not need an empty placeholder part, new point part is directly appended when digitizing
case Qgis::GeometryType::Unknown:
case Qgis::GeometryType::Null:
break;
}
}
}

double RecordingMapTool::pixelsToMapUnits( double numPixels )
{
QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings()->mapSettings() );
Expand Down
7 changes: 7 additions & 0 deletions app/maptools/recordingmaptool.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ class RecordingMapTool : public AbstractMapTool

Q_INVOKABLE void cancelGrab();

/**
* When this is called on a multipart geometry, a new empty part will be added to the geometry and
* activePart will be set to that new last part.
* For MultiPoints and singlepart geometries no new empty part will be added.
*/
Q_INVOKABLE void startDigitizingNewPart();

// Getters / setters
bool centeredToGPS() const;
void setCenteredToGPS( bool newCenteredToGPS );
Expand Down
46 changes: 43 additions & 3 deletions app/qml/map/MMMapController.qml
Original file line number Diff line number Diff line change
Expand Up @@ -814,17 +814,22 @@ Item {
return "invisible"

if (internal.splitGeometryButtonVisible) {
if (!internal.redrawGeometryButtonVisible && !internal.streamingModeButtonVisible)
if (!internal.redrawGeometryButtonVisible && !internal.streamingModeButtonVisible && !internal.addPartButtonVisible)
return "split"
}

if (internal.addPartButtonVisible) {
if (!internal.splitGeometryButtonVisible && !internal.streamingModeButtonVisible && !internal.redrawGeometryButtonVisible)
return "addPart"
}

if (internal.redrawGeometryButtonVisible) {
if (!internal.splitGeometryButtonVisible && !internal.streamingModeButtonVisible)
if (!internal.splitGeometryButtonVisible && !internal.streamingModeButtonVisible && !internal.addPartButtonVisible)
return "redraw"
}

if (internal.streamingModeButtonVisible) {
if (!internal.redrawGeometryButtonVisible && !internal.splitGeometryButtonVisible)
if (!internal.redrawGeometryButtonVisible && !internal.splitGeometryButtonVisible && !internal.addPartButtonVisible)
Comment thread
Withalion marked this conversation as resolved.
return "stream"
}
return "menu"
Expand All @@ -834,6 +839,9 @@ Item {
if (actionState === "split")
return __style.splitGeometryIcon

if (actionState === "addPart")
return __style.plusIcon

if (actionState === "redraw")
return __style.redrawGeometryIcon

Expand All @@ -847,6 +855,9 @@ Item {
if (actionState === "split")
return root.toggleSplitting()

if (actionState === "addPart")
return root.toggleAddPart()

if (actionState === "redraw")
return root.toggleRedraw()

Expand Down Expand Up @@ -977,6 +988,18 @@ Item {
}
}

MMListDelegate {
text: qsTr( "Add part" )
leftContent: MMIcon { source: __style.plusIcon }

visible: internal.addPartButtonVisible

onClicked: {
root.toggleAddPart()
moreToolsMenu.close()
}
}

MMListDelegate {
text: qsTr( "Redraw geometry" )
leftContent: MMIcon { source: __style.redrawGeometryIcon }
Expand Down Expand Up @@ -1262,6 +1285,7 @@ Item {

// visibility of buttons in "more" menu
property bool splitGeometryButtonVisible: !internal.isPointLayer && !root.isStreaming && root.state === "edit"
property bool addPartButtonVisible: internal.isMultiPartLayer && !root.isStreaming && root.state === "edit"
property bool redrawGeometryButtonVisible: root.state === "edit"
property bool streamingModeButtonVisible: !internal.isPointLayer || internal.isMultiPartLayer

Expand Down Expand Up @@ -1323,6 +1347,22 @@ Item {
}
}

function toggleAddPart() {
addPart( internal.featurePairToEdit )
}

Comment thread
Withalion marked this conversation as resolved.
function addPart( featurepair) {
__activeProject.setActiveLayer( featurepair.layer )
root.showInfoTextMessage( qsTr( "Add new part to the geometry" ) )

internal.featurePairToEdit = featurepair
Comment thread
Withalion marked this conversation as resolved.

// You should be already in state == "edit"
if ( recordingToolsLoader.active ) {
recordingToolsLoader.item.recordingMapTool.startDigitizingNewPart()
}
}

function toggleSplitting() {
split(internal.featurePairToEdit)
}
Expand Down
2 changes: 1 addition & 1 deletion app/qml/map/MMRecordingTools.qml
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ Item {
enabled: {
if ( mapTool.recordingType !== MM.RecordingMapTool.Manual ) return false;
if ( mapTool.state === MM.RecordingMapTool.View ) return false;
if ( __inputUtils.isEmptyGeometry( mapTool.recordedGeometry ) ) return false;
if ( __inputUtils.isLastPartEmpty( mapTool.recordedGeometry ) ) return false;

return true;
}
Expand Down
Loading
Loading