489 changes: 489 additions & 0 deletions src/app/qgsmaptooloffsetcurve.cpp

Large diffs are not rendered by default.

82 changes: 82 additions & 0 deletions src/app/qgsmaptooloffsetcurve.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/***************************************************************************
qgsmaptooloffsetcurve.h
------------------------------------------------------------
begin : February 2012
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSMAPTOOLOFFSETCURVE_H
#define QGSMAPTOOLOFFSETCURVE_H

#include "qgsmaptooledit.h"
#include "qgsgeometry.h"
#include "qgssnapper.h"

class QgsVertexMarker;
class QDoubleSpinBox;
class QGraphicsProxyWidget;

class QgsMapToolOffsetCurve: public QgsMapToolEdit
{
Q_OBJECT
public:
QgsMapToolOffsetCurve( QgsMapCanvas* canvas );
~QgsMapToolOffsetCurve();

void canvasPressEvent( QMouseEvent * e );
void canvasReleaseEvent( QMouseEvent * e );
void canvasMoveEvent( QMouseEvent * e );

private slots:
/**Places curve offset to value entered in the spin box*/
void placeOffsetCurveToValue();

private:

/**Rubberband that shows the position of the offset curve*/
QgsRubberBand* mRubberBand;
/**Geometry to manipulate*/
QgsGeometry* mOriginalGeometry;
/**Geometry after manipulation*/
QgsGeometry mModifiedGeometry;
/**ID of manipulated feature*/
QgsFeatureId mModifiedFeature;
/**Layer ID of source layer*/
QString mSourceLayerId;
/**Internal flag to distinguish move from click*/
bool mGeometryModified;
/**Embedded item widget for distance spinbox*/
QGraphicsProxyWidget* mDistanceItem;
/**Shows current distance value and allows numerical editing*/
QDoubleSpinBox* mDistanceSpinBox;
/**Marker to show the cursor was snapped to another location*/
QgsVertexMarker* mSnapVertexMarker;
/**Forces geometry copy (no modification of geometry in current layer)*/
bool mForceCopy;
bool mMultiPartGeometry;


void deleteRubberBandAndGeometry();
QgsGeometry* createOriginGeometry( QgsVectorLayer* vl, const QgsSnappingResult& sr, QgsFeature& snappedFeature );
void createDistanceItem();
void deleteDistanceItem();
void setOffsetForRubberBand( double offset, bool leftSide );
/**Creates a linestring from the polygon ring containing the snapped vertex. Caller takes ownership of the created object*/
QgsGeometry* linestringFromPolygon( QgsGeometry* featureGeom, int vertex );
/**Sets snapping with default vertex search tolerance to all layers (to vertex and segment)*/
void configureSnapper( QgsSnapper& s );
/**Returns a single line from a multiline (or does nothing if geometry is already a single line). Deletes the input geometry*/
QgsGeometry* convertToSingleLine( QgsGeometry* geom, int vertex, bool& isMulti );
/**Converts offset line back to a multiline if necessary*/
QgsGeometry* convertToMultiLine( QgsGeometry* geom );
};

#endif // QGSMAPTOOLOFFSETCURVE_H
12 changes: 12 additions & 0 deletions src/app/qgsoptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,14 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WFlags fl ) :
chkDisableAttributeValuesDlg->setChecked( settings.value( "/qgis/digitizing/disable_enter_attribute_values_dialog", false ).toBool() );
mValidateGeometries->setCurrentIndex( settings.value( "/qgis/digitizing/validate_geometries", 1 ).toInt() );

mOffsetJoinStyleComboBox->addItem( tr( "Round" ), 0 );
mOffsetJoinStyleComboBox->addItem( tr( "Mitre" ), 1 );
mOffsetJoinStyleComboBox->addItem( tr( "Bevel" ), 2 );
mOffsetJoinStyleComboBox->setCurrentIndex( settings.value( "/qgis/digitizing/offset_join_style", 0 ).toInt() );
mOffsetQuadSegSpinBox->setValue( settings.value( "/qgis/digitizing/offset_quad_seg", 8 ).toInt() );
mCurveOffsetMiterLimitComboBox->setValue( settings.value( "/qgis/digitizine/offset_miter_limit", 5.0 ).toDouble() );


#ifdef Q_WS_MAC //MH: disable incremental update on Mac for now to avoid problems with resizing
groupBox_5->setEnabled( false );
#endif //Q_WS_MAC
Expand Down Expand Up @@ -781,6 +789,10 @@ void QgsOptions::saveOptions()
settings.setValue( "/qgis/digitizing/disable_enter_attribute_values_dialog", chkDisableAttributeValuesDlg->isChecked() );
settings.setValue( "/qgis/digitizing/validate_geometries", mValidateGeometries->currentIndex() );

settings.setValue( "/qgis/digitizing/offset_join_style", mOffsetJoinStyleComboBox->itemData( mOffsetJoinStyleComboBox->currentIndex() ).toInt() );
settings.setValue( "/qgis/digitizing/offset_quad_seg", mOffsetQuadSegSpinBox->value() );
settings.setValue( "/qgis/digitizine/offset_miter_limit", mCurveOffsetMiterLimitComboBox->value() );

//
// Locale settings
//
Expand Down
31 changes: 28 additions & 3 deletions src/core/qgsgeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2405,7 +2405,8 @@ double QgsGeometry::closestVertexWithContext( const QgsPoint& point, int& atVert
double QgsGeometry::closestSegmentWithContext(
const QgsPoint& point,
QgsPoint& minDistPoint,
int& beforeVertex )
int& beforeVertex,
double* leftOf )
{
QgsDebugMsg( "Entering." );
QgsPoint distPoint;
Expand Down Expand Up @@ -2471,6 +2472,10 @@ double QgsGeometry::closestSegmentWithContext(
closestSegmentIndex = index;
sqrDist = testdist;
minDistPoint = distPoint;
if ( leftOf )
{
*leftOf = QgsGeometry::leftOf( point.x(), point.y(), *prevx, *prevy, *thisx, *thisy );
}
}
}
ptr += sizeof( double );
Expand Down Expand Up @@ -2515,6 +2520,10 @@ double QgsGeometry::closestSegmentWithContext(
closestSegmentIndex = pointindex;
sqrDist = testdist;
minDistPoint = distPoint;
if ( leftOf )
{
*leftOf = QgsGeometry::leftOf( point.x(), point.y(), *prevx, *prevy, *thisx, *thisy );
}
}
}
prevx = thisx;
Expand Down Expand Up @@ -2557,6 +2566,10 @@ double QgsGeometry::closestSegmentWithContext(
closestSegmentIndex = index;
sqrDist = testdist;
minDistPoint = distPoint;
if ( leftOf )
{
*leftOf = QgsGeometry::leftOf( point.x(), point.y(), *prevx, *prevy, *thisx, *thisy );
}
}
}
prevx = thisx;
Expand Down Expand Up @@ -2605,6 +2618,10 @@ double QgsGeometry::closestSegmentWithContext(
closestSegmentIndex = pointindex;
sqrDist = testdist;
minDistPoint = distPoint;
if ( leftOf )
{
*leftOf = QgsGeometry::leftOf( point.x(), point.y(), *prevx, *prevy, *thisx, *thisy );
}
}
}
prevx = thisx;
Expand Down Expand Up @@ -6141,8 +6158,7 @@ QgsGeometry* QgsGeometry::combine( QgsGeometry* geometry )
GEOSGeometry* unionGeom = GEOSUnion( mGeos, geometry->mGeos );
QGis::WkbType thisGeomType = wkbType();
QGis::WkbType otherGeomType = geometry->wkbType();
if (( thisGeomType == QGis::WKBLineString || thisGeomType == QGis::WKBLineString25D )
&& ( otherGeomType == QGis::WKBLineString || otherGeomType == QGis::WKBLineString25D ) )
if ( type() == QGis::Line )
{
GEOSGeometry* mergedGeom = GEOSLineMerge( unionGeom );
if ( mergedGeom )
Expand Down Expand Up @@ -6453,3 +6469,12 @@ bool QgsGeometry::isGeosEmpty()
return false;
}
}

double QgsGeometry::leftOf( double x, double y, double& x1, double& y1, double& x2, double& y2 )
{
double f1 = x - x1;
double f2 = y2 - y1;
double f3 = y - y1;
double f4 = x2 - x1;
return f1*f2 - f3*f4;
}
6 changes: 5 additions & 1 deletion src/core/qgsgeometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,10 @@ class CORE_EXPORT QgsGeometry
* @param minDistPoint Receives the nearest point on the segment
* @param beforeVertex Receives index of the vertex before the closest segment. The vertex
* after the closest segment is always beforeVertex + 1
* @param leftOf Out: Returns if the point lies on the left of right side of the segment ( < 0 means left, > 0 means right )
* @return The squared cartesian distance is also returned in sqrDist, negative number on error
*/
double closestSegmentWithContext( const QgsPoint& point, QgsPoint& minDistPoint, int& beforeVertex );
double closestSegmentWithContext( const QgsPoint& point, QgsPoint& minDistPoint, int& beforeVertex, double* leftOf = 0 );

/**Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
@return 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
Expand Down Expand Up @@ -566,6 +567,9 @@ class CORE_EXPORT QgsGeometry
static bool geosRelOp( char( *op )( const GEOSGeometry*, const GEOSGeometry * ),
QgsGeometry *a, QgsGeometry *b );

/**Returns < 0 if point(x/y) is left of the line x1,y1 -> x1,y2*/
double leftOf( double x, double y, double& x1, double& y1, double& x2, double& y2 );


static int refcount;
}; // class QgsGeometry
Expand Down
3 changes: 1 addition & 2 deletions src/gui/qgsmapcanvassnapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@
#ifndef QGSMAPCANVASSNAPPER_H
#define QGSMAPCANVASSNAPPER_H

#include "qgssnapper.h"
#include <QList>
#include "qgssnapper.h"

class QgsMapCanvas;
class QPoint;
class QgsSnapper;

/** \ingroup gui
* This class reads the snapping properties from the current project and
Expand Down
16 changes: 15 additions & 1 deletion src/ui/qgisapp.ui
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<x>0</x>
<y>0</y>
<width>1052</width>
<height>28</height>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="mEditMenu">
Expand All @@ -41,6 +41,7 @@
<addaction name="mActionDeleteRing"/>
<addaction name="mActionDeletePart"/>
<addaction name="mActionReshapeFeatures"/>
<addaction name="mActionOffsetCurve"/>
<addaction name="mActionSplitFeatures"/>
<addaction name="mActionMergeFeatures"/>
<addaction name="mActionMergeFeatureAttributes"/>
Expand Down Expand Up @@ -292,6 +293,7 @@
<addaction name="mActionDeleteRing"/>
<addaction name="mActionDeletePart"/>
<addaction name="mActionReshapeFeatures"/>
<addaction name="mActionOffsetCurve"/>
<addaction name="mActionSplitFeatures"/>
<addaction name="mActionMergeFeatures"/>
<addaction name="mActionMergeFeatureAttributes"/>
Expand Down Expand Up @@ -1604,6 +1606,18 @@
<string>Pan Map to Selection</string>
</property>
</action>
<action name="mActionOffsetCurve">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionOffsetCurve.png</normaloff>:/images/themes/default/mActionOffsetCurve.png</iconset>
</property>
<property name="text">
<string>Offset curve</string>
</property>
</action>
</widget>
<resources>
<include location="../../images/images.qrc"/>
Expand Down
76 changes: 53 additions & 23 deletions src/ui/qgsoptionsbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>779</width>
<height>791</height>
<width>809</width>
<height>778</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
Expand Down Expand Up @@ -726,8 +726,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>604</width>
<height>494</height>
<width>809</width>
<height>778</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_8">
Expand Down Expand Up @@ -900,8 +900,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>483</width>
<height>478</height>
<width>809</width>
<height>778</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_4">
Expand Down Expand Up @@ -1186,8 +1186,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>257</width>
<height>93</height>
<width>809</width>
<height>778</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_10">
Expand Down Expand Up @@ -1261,8 +1261,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>569</width>
<height>510</height>
<width>795</width>
<height>764</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_13">
Expand Down Expand Up @@ -1529,8 +1529,8 @@
<property name="title">
<string>Other settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_26">
<item row="0" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_12">
<item row="0" column="0">
<widget class="QCheckBox" name="chkDisableAttributeValuesDlg">
<property name="text">
<string>Suppress attributes pop-up windows after each created feature</string>
Expand All @@ -1540,7 +1540,7 @@
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<item row="1" column="0">
<widget class="QCheckBox" name="chkReuseLastValues">
<property name="text">
<string>Reuse last entered attribute values</string>
Expand All @@ -1550,20 +1550,50 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="mValidateGeometries"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Validate geometries</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="mValidateGeometries"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Join style for curve offset</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="mOffsetJoinStyleComboBox"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Quadrantsegments for curve offset</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="mOffsetQuadSegSpinBox"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Miter limit for curve offset</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="mCurveOffsetMiterLimitComboBox"/>
</item>
</layout>
</widget>
</item>
<item row="5" column="0">
<item row="4" column="0">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
Expand Down Expand Up @@ -1607,8 +1637,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>412</width>
<height>411</height>
<width>809</width>
<height>778</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_15">
Expand Down Expand Up @@ -1781,8 +1811,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>523</width>
<height>560</height>
<width>809</width>
<height>778</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_17">
Expand Down Expand Up @@ -1878,8 +1908,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>321</width>
<height>541</height>
<width>809</width>
<height>778</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_20">
Expand Down