[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    koffice/libs/flake/tools
From:       Jan Hambrecht <jaham () gmx ! net>
Date:       2008-01-31 22:25:35
Message-ID: 1201818335.362719.28858.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 769235 by jaham:

implemnented a new snaping guide which snaps to the
direction of the line/path at its end points



 M  +5 -3      KoCreatePathTool.cpp  
 M  +14 -13    SnapGuide.cpp  
 M  +4 -9      SnapGuide.h  
 M  +10 -4     SnapGuideConfigWidget.cpp  
 M  +11 -4     SnapGuideConfigWidget.ui  
 M  +143 -6    SnapStrategy.cpp  
 M  +23 -3     SnapStrategy.h  


--- trunk/koffice/libs/flake/tools/KoCreatePathTool.cpp #769234:769235
@@ -21,6 +21,7 @@
 
 #include "KoCreatePathTool.h"
 #include "SnapGuide.h"
+#include "SnapStrategy.h"
 #include "SnapGuideConfigWidget.h"
 
 #include "KoPathShape.h"
@@ -48,7 +49,8 @@
 , m_mouseOverFirstPoint(false)
 , m_snapGuide( new SnapGuide(canvas) )
 {
-    m_snapGuide->enableSnapStrategies( SnapGuide::Orthogonal|SnapGuide::Node );
+    m_snapGuide->enableSnapStrategies( SnapStrategy::Orthogonal|SnapStrategy::Node|SnapStrategy::Extension );
+    //m_snapGuide->enableSnapStrategies( SnapStrategy::Node|SnapStrategy::Extension );
 }
 
 KoCreatePathTool::~KoCreatePathTool()
@@ -147,7 +149,7 @@
         m_canvas->updateCanvas( m_shape->boundingRect() );
         m_canvas->updateCanvas( m_snapGuide->boundingRect() );
 
-        m_snapGuide->setExtraShape( m_shape );
+        m_snapGuide->setEditedShape( m_shape );
     }
 }
 
@@ -256,7 +258,7 @@
 {
     m_shape->normalize();
 
-    m_snapGuide->setExtraShape(0);
+    m_snapGuide->setEditedShape(0);
 
     // this is done so that nothing happens when the mouseReleaseEvent for the this event is received 
     KoPathShape *pathShape = m_shape;
--- trunk/koffice/libs/flake/tools/SnapGuide.cpp #769234:769235
@@ -32,25 +32,26 @@
 
 
 SnapGuide::SnapGuide( KoCanvasBase * canvas )
-    : m_canvas(canvas), m_extraShape(0), m_currentStrategy(0)
+    : m_canvas(canvas), m_editedShape(0), m_currentStrategy(0)
     , m_active(true), m_snapDistance(10)
 {
     m_strategies.append( new NodeSnapStrategy() );
     m_strategies.append( new OrthogonalSnapStrategy() );
+    m_strategies.append( new ExtensionSnapStrategy() );
 }
 
 SnapGuide::~SnapGuide()
 {
 }
 
-void SnapGuide::setExtraShape( KoShape * shape )
+void SnapGuide::setEditedShape( KoShape * shape )
 {
-    m_extraShape = shape;
+    m_editedShape = shape;
 }
 
-KoShape * SnapGuide::extraShape() const
+KoShape * SnapGuide::editedShape() const
 {
-    return m_extraShape;
+    return m_editedShape;
 }
 
 void SnapGuide::enableSnapStrategies( int strategies )
@@ -130,7 +131,7 @@
 
 void SnapGuide::paint( QPainter &painter, const KoViewConverter &converter )
 {
-    if( ! m_currentStrategy )
+    if( ! m_currentStrategy || ! m_active )
         return;
 
     QPen pen( Qt::red );
@@ -174,11 +175,11 @@
 {
     QList<KoShape*> shapes = m_snapGuide->canvas()->shapeManager()->shapesAt( rect );
 
-    if( m_snapGuide->extraShape() )
+    if( m_snapGuide->editedShape() )
     {
-        QRectF bound = m_snapGuide->extraShape()->boundingRect();
+        QRectF bound = m_snapGuide->editedShape()->boundingRect();
         if( rect.intersects( bound ) || rect.contains( bound ) )
-            shapes.append( m_snapGuide->extraShape() );
+            shapes.append( m_snapGuide->editedShape() );
     }
     return shapes;
 }
@@ -207,16 +208,16 @@
         }
     }
 
-    if( shape == m_snapGuide->extraShape() )
+    if( shape == m_snapGuide->editedShape() )
         pathPoints.removeLast();
 
     return pathPoints;
 }
 
-QList<KoShape*> SnapProxy::shapes()
+QList<KoShape*> SnapProxy::shapes( bool omitEditedShape )
 {
     QList<KoShape*> shapes = m_snapGuide->canvas()->shapeManager()->shapes();
-    if( m_snapGuide->extraShape() )
-        shapes.append( m_snapGuide->extraShape() );
+    if( ! omitEditedShape && m_snapGuide->editedShape() )
+        shapes.append( m_snapGuide->editedShape() );
     return shapes;
 }
--- trunk/koffice/libs/flake/tools/SnapGuide.h #769234:769235
@@ -36,11 +36,6 @@
 class SnapGuide
 {
 public:
-    /// the different possible snap types
-    enum SnapType {
-        Orthogonal = 1,
-        Node = 2
-    };
 
     /// Creates the snap guide to work on the given canvas
     SnapGuide( KoCanvasBase * canvas );
@@ -57,10 +52,10 @@
     QRectF boundingRect();
 
     /// Adds an additional shape to snap to (useful when creating a path)
-    void setExtraShape( KoShape * shape );
+    void setEditedShape( KoShape * shape );
 
     /// returns the extra shapes to use
-    KoShape * extraShape() const;
+    KoShape * editedShape() const;
 
     /// enables the strategies used for snapping 
     void enableSnapStrategies( int strategies );
@@ -85,7 +80,7 @@
 
 private:
     KoCanvasBase * m_canvas;
-    KoShape * m_extraShape;
+    KoShape * m_editedShape;
 
     QList<SnapStrategy*> m_strategies;
     SnapStrategy * m_currentStrategy;
@@ -110,7 +105,7 @@
     QList<QPointF> pointsFromShape( KoShape * shape );
 
     /// returns list of all shapes
-    QList<KoShape*> shapes();
+    QList<KoShape*> shapes( bool omitEditedShape = false );
 
 private:
     SnapGuide * m_snapGuide;
--- trunk/koffice/libs/flake/tools/SnapGuideConfigWidget.cpp #769234:769235
@@ -19,22 +19,26 @@
 
 #include "SnapGuideConfigWidget.h"
 #include "SnapGuide.h"
+#include "SnapStrategy.h"
 
 SnapGuideConfigWidget::SnapGuideConfigWidget( SnapGuide * snapGuide, QWidget * parent )
     :QWidget(parent), m_snapGuide(snapGuide)
 {
     widget.setupUi(this);
 
-    if( snapGuide->enabledSnapStrategies() & SnapGuide::Orthogonal )
+    if( snapGuide->enabledSnapStrategies() & SnapStrategy::Orthogonal )
         widget.orthogonalSnapGuide->setCheckState( Qt::Checked );
-    if( snapGuide->enabledSnapStrategies() & SnapGuide::Node )
+    if( snapGuide->enabledSnapStrategies() & SnapStrategy::Node )
         widget.nodeSnapGuide->setCheckState( Qt::Checked );
+    if( snapGuide->enabledSnapStrategies() & SnapStrategy::Extension )
+        widget.extensionSnapGuide->setCheckState( Qt::Checked );
 
     widget.snapDistance->setValue( m_snapGuide->snapDistance() );
 
     connect( widget.useSnapGuides, SIGNAL(stateChanged(int)), this, SLOT(snappingEnabled(int)));
     connect( widget.orthogonalSnapGuide, SIGNAL(stateChanged(int)), this, SLOT(strategyChanged()));
     connect( widget.nodeSnapGuide, SIGNAL(stateChanged(int)), this, SLOT(strategyChanged()));
+    connect( widget.extensionSnapGuide, SIGNAL(stateChanged(int)), this, SLOT(strategyChanged()));
     connect( widget.snapDistance, SIGNAL(valueChanged(int)), this, SLOT(distanceChanged(int)));
 
     widget.useSnapGuides->setCheckState( snapGuide->isSnapping() ? Qt::Checked : Qt::Unchecked );
@@ -54,9 +58,11 @@
 {
     int strategies = 0;
     if( widget.orthogonalSnapGuide->checkState() == Qt::Checked )
-        strategies |= SnapGuide::Orthogonal;
+        strategies |= SnapStrategy::Orthogonal;
     if( widget.nodeSnapGuide->checkState() == Qt::Checked )
-        strategies |= SnapGuide::Node;
+        strategies |= SnapStrategy::Node;
+    if( widget.extensionSnapGuide->checkState() == Qt::Checked )
+        strategies |= SnapStrategy::Extension;
 
     m_snapGuide->enableSnapStrategies( strategies );
 }
--- trunk/koffice/libs/flake/tools/SnapGuideConfigWidget.ui #769234:769235
@@ -6,7 +6,7 @@
     <x>0</x>
     <y>0</y>
     <width>255</width>
-    <height>187</height>
+    <height>229</height>
    </rect>
   </property>
   <property name="windowTitle" >
@@ -38,16 +38,23 @@
        </widget>
       </item>
       <item row="2" column="0" colspan="2" >
+       <widget class="QCheckBox" name="extensionSnapGuide" >
+        <property name="text" >
+         <string>Enable Extension Guide</string>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="0" colspan="2" >
        <widget class="QLabel" name="label" >
         <property name="text" >
          <string>Snap Distance (px)</string>
         </property>
        </widget>
       </item>
-      <item row="3" column="0" >
+      <item row="4" column="0" >
        <widget class="QSpinBox" name="snapDistance" />
       </item>
-      <item row="3" column="1" >
+      <item row="4" column="1" >
        <spacer>
         <property name="orientation" >
          <enum>Qt::Horizontal</enum>
@@ -60,7 +67,7 @@
         </property>
        </spacer>
       </item>
-      <item row="4" column="0" >
+      <item row="5" column="0" >
        <spacer>
         <property name="orientation" >
          <enum>Qt::Vertical</enum>
--- trunk/koffice/libs/flake/tools/SnapStrategy.cpp #769234:769235
@@ -18,11 +18,13 @@
  */
 
 #include "SnapStrategy.h"
+#include <KoPathShape.h>
+#include <KoPathPoint.h>
 
 #include <math.h>
 
 
-SnapStrategy::SnapStrategy( SnapGuide::SnapType type )
+SnapStrategy::SnapStrategy( SnapStrategy::SnapType type )
     : m_snapType(type)
 {
 }
@@ -47,7 +49,7 @@
     m_snappedPosition= position;
 }
 
-SnapGuide::SnapType SnapStrategy::type() const
+SnapStrategy::SnapType SnapStrategy::type() const
 {
     return m_snapType;
 }
@@ -60,7 +62,7 @@
 }
 
 OrthogonalSnapStrategy::OrthogonalSnapStrategy()
-    : SnapStrategy( SnapGuide::Orthogonal )
+    : SnapStrategy( SnapStrategy::Orthogonal )
 {
 }
 
@@ -119,7 +121,7 @@
 }
 
 NodeSnapStrategy::NodeSnapStrategy()
-    : SnapStrategy( SnapGuide::Node )
+    : SnapStrategy( SnapStrategy::Node )
 {
 }
 
@@ -136,8 +138,7 @@
 
     foreach( QPointF point, points )
     {
-        QPointF diffVec = mousePosition-point;
-        double distance = diffVec.x()*diffVec.x() + diffVec.y()*diffVec.y();
+        double distance = fastDistance( mousePosition, point );
         if( distance < maxDistance && distance < minDistance )
         {
             snappedPoint = point;
@@ -159,3 +160,139 @@
 
     return (minDistance < HUGE_VAL);
 }
+
+ExtensionSnapStrategy::ExtensionSnapStrategy()
+    : SnapStrategy( SnapStrategy::Extension )
+{
+}
+
+bool ExtensionSnapStrategy::snapToPoints( const QPointF &mousePosition, SnapProxy * proxy, double maxSnapDistance )
+{
+    double maxDistance = maxSnapDistance*maxSnapDistance;
+    double minDistance = HUGE_VAL;
+
+    QPointF snappedPoint = mousePosition;
+    QPointF startPoint;
+
+    QList<KoShape*> shapes = proxy->shapes( true );
+    foreach( KoShape * shape, shapes )
+    {
+        KoPathShape * path = dynamic_cast<KoPathShape*>( shape );
+        if( ! path )
+            continue;
+
+        QMatrix matrix = path->absoluteTransformation(0);
+
+        int subpathCount = path->subpathCount();
+        for( int subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex )
+        {
+            if( path->isClosedSubpath( subpathIndex ) )
+                continue;
+
+            int pointCount = path->pointCountSubpath( subpathIndex );
+
+            // check the extension from the start point
+            KoPathPoint * first = path->pointByIndex( KoPathPointIndex( subpathIndex, 0 )  );
+            QPointF firstSnapPosition = mousePosition;
+            if( snapToExtension( firstSnapPosition, first, matrix ) )
+            {
+                double distance = fastDistance( firstSnapPosition, mousePosition );
+                if( distance < maxDistance && distance < minDistance )
+                {
+                    minDistance = distance;
+                    snappedPoint = firstSnapPosition;
+                    startPoint = matrix.map( first->point() );
+                }
+            }
+
+            // now check the extension from the last point
+            KoPathPoint * last = path->pointByIndex( KoPathPointIndex( subpathIndex, pointCount-1 )  );
+            QPointF lastSnapPosition = mousePosition;
+            if( snapToExtension( lastSnapPosition, last, matrix ) )
+            {
+                double distance = fastDistance( lastSnapPosition, mousePosition );
+                if( distance < maxDistance && distance < minDistance )
+                {
+                    minDistance = distance;
+                    snappedPoint = lastSnapPosition;
+                    startPoint = matrix.map( last->point() );
+                }
+            }
+        }
+    }
+
+    QPainterPath decoration;
+
+    if( minDistance < HUGE_VAL )
+    {
+        decoration.moveTo( startPoint );
+        decoration.lineTo( snappedPoint );
+    }
+
+    setDecoration( decoration );
+    setSnappedPosition( snappedPoint );
+
+    return (minDistance < HUGE_VAL);
+}
+
+bool ExtensionSnapStrategy::snapToExtension( QPointF &position, KoPathPoint * point, const QMatrix &matrix )
+{
+    QPointF direction = extensionDirection( point, matrix );
+    QPointF extensionStart = matrix.map( point->point() );
+    QPointF extensionStop = matrix.map( point->point() ) + direction;
+    float posOnExtension = project( extensionStart, extensionStop, position );
+    if( posOnExtension < 0.0 )
+        return false;
+
+    position = extensionStart + posOnExtension * direction;
+    return true;
+}
+
+double ExtensionSnapStrategy::project( const QPointF &lineStart, const QPointF &lineEnd, const QPointF &point )
+{
+    QPointF diff = lineEnd - lineStart;
+    QPointF relPoint = point - lineStart;
+    double diffLength = sqrt( diff.x()*diff.x() + diff.y()*diff.y() );
+    diff /= diffLength;
+    // project mouse position relative to stop position on extension line
+    double scalar = relPoint.x()*diff.x() + relPoint.y()*diff.y();
+    return scalar /= diffLength;
+}
+
+QPointF ExtensionSnapStrategy::extensionDirection( KoPathPoint * point, const QMatrix &matrix )
+{
+    KoPathShape * path = point->parent();
+    KoPathPointIndex index = path->pathPointIndex( point );
+
+    /// check if it is a start point
+    if( point->properties() & KoPathPoint::StartSubpath )
+    {
+        if( point->properties() & KoPathPoint::HasControlPoint2 )
+        {
+            return matrix.map(point->point()) - matrix.map(point->controlPoint2());
+        }
+        else
+        {
+            KoPathPoint * next = path->pointByIndex( KoPathPointIndex( index.first, index.second+1 ) );
+            if( next->properties() & KoPathPoint::HasControlPoint1 )
+                return matrix.map(point->point()) - matrix.map(next->controlPoint1());
+            else
+                return matrix.map(point->point()) - matrix.map(next->point());
+        }
+    }
+    else
+    {
+        if( point->properties() & KoPathPoint::HasControlPoint1 )
+        {
+            return matrix.map(point->point()) - matrix.map(point->controlPoint1());
+        }
+        else
+        {
+            KoPathPoint * prev = path->pointByIndex( KoPathPointIndex( index.first, index.second-1 ) );
+            if( prev->properties() & KoPathPoint::HasControlPoint2 )
+                return matrix.map(point->point()) - matrix.map(prev->controlPoint2());
+            else
+                return matrix.map(point->point()) - matrix.map(prev->point());
+        }
+    }
+}
--- trunk/koffice/libs/flake/tools/SnapStrategy.h #769234:769235
@@ -25,10 +25,19 @@
 #include <QtCore/QPointF>
 #include <QtGui/QPainterPath>
 
+class KoPathPoint;
+
 class SnapStrategy
 {
 public:
-    SnapStrategy( SnapGuide::SnapType type );
+    /// the different possible snap types
+    enum SnapType {
+        Orthogonal = 1,
+        Node = 2,
+        Extension = 4
+    };
+
+    SnapStrategy( SnapType type );
     virtual ~SnapStrategy() {};
 
     virtual bool snapToPoints( const QPointF &mousePosition, SnapProxy * proxy, double maxSnapDistance ) = 0;
@@ -37,7 +46,7 @@
     QPainterPath decoration() const;
 
     /// returns the strategies type
-    SnapGuide::SnapType type() const;
+    SnapType type() const;
 
     static double fastDistance( const QPointF &p1, const QPointF &p2 );
 
@@ -53,7 +62,7 @@
 
 private:
     QPainterPath m_decoration;
-    SnapGuide::SnapType m_snapType;
+    SnapType m_snapType;
     QPointF m_snappedPosition;
 };
 
@@ -71,4 +80,15 @@
     virtual bool snapToPoints( const QPointF &mousePosition, SnapProxy * proxy, double maxSnapDistance );
 };
 
+class ExtensionSnapStrategy : public SnapStrategy
+{
+public:
+    ExtensionSnapStrategy();
+    virtual bool snapToPoints( const QPointF &mousePosition, SnapProxy * proxy, double maxSnapDistance );
+private:
+    double project( const QPointF &lineStart , const QPointF &lineEnd, const QPointF &point );
+    QPointF extensionDirection( KoPathPoint * point, const QMatrix &matrix );
+    bool snapToExtension( QPointF &position, KoPathPoint * point, const QMatrix &matrix );
+};
+
 #endif // SNAPSTRATEGY_H
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic