void KoPathPointInsertCommand::undo() { QUndoCommand::undo(); for (int i = 0; i < m_pointDataList.size(); ++i) { const KoPathPointData &pdBefore = m_pointDataList.at(i); KoPathShape * pathShape = pdBefore.pathShape; KoPathPointIndex piAfter = pdBefore.pointIndex; ++piAfter.second; KoPathPoint * before = pathShape->pointByIndex(pdBefore.pointIndex); m_points[i] = pathShape->removePoint(piAfter); if (m_points[i]->properties() & KoPathPoint::CloseSubpath) { piAfter.second = 0; } KoPathPoint * after = pathShape->pointByIndex(piAfter); if (before->activeControlPoint2()) { QPointF controlPoint2 = before->controlPoint2(); qSwap(controlPoint2, m_controlPoints[i].first); before->setControlPoint2(controlPoint2); } if (after->activeControlPoint1()) { QPointF controlPoint1 = after->controlPoint1(); qSwap(controlPoint1, m_controlPoints[i].second); after->setControlPoint1(controlPoint1); } pathShape->update(); } m_deletePoints = true; }
void KoPathSegmentTypeCommand::redo() { KUndo2Command::redo(); QList<KoPathPointData>::const_iterator it(m_pointDataList.constBegin()); for (; it != m_pointDataList.constEnd(); ++it) { KoPathShape * pathShape = it->pathShape; pathShape->update(); KoPathSegment segment = pathShape->segmentByIndex(it->pointIndex); if (m_segmentType == Curve) { // we change type to curve -> set control point positions QPointF pointDiff = segment.second()->point() - segment.first()->point(); segment.first()->setControlPoint2(segment.first()->point() + pointDiff / 3.0); segment.second()->setControlPoint1(segment.first()->point() + pointDiff * 2.0 / 3.0); } else { // we are changing type to line -> remove control points segment.first()->removeControlPoint2(); segment.second()->removeControlPoint1(); } pathShape->normalize(); pathShape->update(); } }
void SvgStyleWriter::saveSvgClipping(KoShape *shape, SvgSavingContext &context) { KoClipPath *clipPath = shape->clipPath(); if (!clipPath) return; const QSizeF shapeSize = shape->outlineRect().size(); KoPathShape *path = KoPathShape::createShapeFromPainterPath(clipPath->pathForSize(shapeSize)); if (!path) return; path->close(); const QString uid = context.createUID("clippath"); context.styleWriter().startElement("clipPath"); context.styleWriter().addAttribute("id", uid); context.styleWriter().addAttribute("clipPathUnits", "userSpaceOnUse"); context.styleWriter().startElement("path"); context.styleWriter().addAttribute("d", path->toString(path->absoluteTransformation(0)*context.userSpaceTransform())); context.styleWriter().endElement(); // path context.styleWriter().endElement(); // clipPath context.shapeWriter().addAttribute("clip-path", "url(#" + uid + ")"); if (clipPath->clipRule() != Qt::WindingFill) context.shapeWriter().addAttribute("clip-rule", "evenodd"); }
void SvgStyleWriter::saveSvgFill(KoShape *shape, SvgSavingContext &context) { if (! shape->background()) { context.shapeWriter().addAttribute("fill", "none"); } QBrush fill(Qt::NoBrush); QSharedPointer<KoColorBackground> cbg = qSharedPointerDynamicCast<KoColorBackground>(shape->background()); if (cbg) { context.shapeWriter().addAttribute("fill", cbg->color().name()); if (cbg->color().alphaF() < 1.0) context.shapeWriter().addAttribute("fill-opacity", cbg->color().alphaF()); } QSharedPointer<KoGradientBackground> gbg = qSharedPointerDynamicCast<KoGradientBackground>(shape->background()); if (gbg) { QString gradientId = saveSvgGradient(gbg->gradient(), gbg->transform(), context); context.shapeWriter().addAttribute("fill", "url(#" + gradientId + ")"); } QSharedPointer<KoPatternBackground> pbg = qSharedPointerDynamicCast<KoPatternBackground>(shape->background()); if (pbg) { const QString patternId = saveSvgPattern(pbg, shape, context); context.shapeWriter().addAttribute("fill", "url(#" + patternId + ")"); } KoPathShape * path = dynamic_cast<KoPathShape*>(shape); if (path && shape->background()) { // non-zero is default, so only write fillrule if evenodd is set if (path->fillRule() == Qt::OddEvenFill) context.shapeWriter().addAttribute("fill-rule", "evenodd"); } }
QList<KoSubpath *> KarbonSimplifyPath::split( const KoPathShape &path ) { QList<KoSubpath *> res; KoSubpath *subpath = new KoSubpath; res.append( subpath ); for ( int i = 0; i < path.pointCount(); ++i ) { KoPathPoint *p = path.pointByIndex( KoPathPointIndex(0, i) ); // if the path separates two subpaths // (if it isn't smooth nor the first or last point) if ( i != 0 && i != path.pointCount()-1 ) { KoPathPoint *prev = path.pointByIndex( KoPathPointIndex(0, i-1) ); KoPathPoint *next = path.pointByIndex( KoPathPointIndex(0, i+1) ); if ( ! p->isSmooth(prev, next) ) { // create a new subpath subpath->append( new KoPathPoint(*p) ); subpath = new KoSubpath; res.append( subpath ); } } subpath->append( new KoPathPoint(*p) ); } return res; }
void KoPathPointInsertCommand::redo() { QUndoCommand::redo(); for (int i = m_pointDataList.size() - 1; i >= 0; --i) { KoPathPointData pointData = m_pointDataList.at(i); KoPathShape * pathShape = pointData.pathShape; KoPathSegment segment = pathShape->segmentByIndex(pointData.pointIndex); ++pointData.pointIndex.second; if (segment.first()->activeControlPoint2()) { QPointF controlPoint2 = segment.first()->controlPoint2(); qSwap(controlPoint2, m_controlPoints[i].first); segment.first()->setControlPoint2(controlPoint2); } if (segment.second()->activeControlPoint1()) { QPointF controlPoint1 = segment.second()->controlPoint1(); qSwap(controlPoint1, m_controlPoints[i].second); segment.second()->setControlPoint1(controlPoint1); } pathShape->insertPoint(m_points.at(i), pointData.pointIndex); pathShape->update(); } m_deletePoints = false; }
void TestSegmentTypeCommand::changeToLine() { KoPathShape path; path.moveTo( QPointF(0,0) ); path.curveTo( QPointF(25,25), QPointF(75,25), QPointF(100,0) ); KoPathPointData segment(&path, KoPathPointIndex(0,0)); QList<KoPathPointData> segments; segments.append(segment); // get first segment KoPathSegment s = path.segmentByIndex(KoPathPointIndex(0,0)); KoPathSegmentTypeCommand cmd(segments, KoPathSegmentTypeCommand::Line); QVERIFY(s.first()->activeControlPoint2()); QVERIFY(s.second()->activeControlPoint1()); cmd.redo(); QVERIFY(!s.first()->activeControlPoint2()); QVERIFY(!s.second()->activeControlPoint1()); cmd.undo(); QVERIFY(s.first()->activeControlPoint2()); QVERIFY(s.second()->activeControlPoint1()); }
PointData( KoPathPoint * p ) { KoPathShape * shape = p->parent(); // save points in document coordinates oldNode = shape->shapeToDocument( p->point() ); oldControlPoint1 = shape->shapeToDocument( p->controlPoint1() ); oldControlPoint2 = shape->shapeToDocument( p->controlPoint2() ); }
void restorePoint( KoPathPoint * p ) { KoPathShape * shape = p->parent(); p->setPoint( shape->documentToShape( oldNode ) ); if( p->activeControlPoint1() ) p->setControlPoint1( shape->documentToShape( oldControlPoint1 ) ); if( p->activeControlPoint2() ) p->setControlPoint2( shape->documentToShape( oldControlPoint2 ) ); }
void KoShapeStroke::Private::paintBorder(KoShape *shape, QPainter &painter, const QPen &pen) const { if (!pen.isCosmetic()) { KoPathShape *pathShape = dynamic_cast<KoPathShape *>(shape); if (pathShape) { QPainterPath path = pathShape->pathStroke(pen); painter.fillPath(path, pen.brush()); return; } painter.strokePath(shape->outline(), pen); } }
KoClipPath *PictureShape::generateClipPath() { QPainterPath path = _Private::generateOutline(imageData()->image()); path = path * QTransform().scale(size().width(), size().height()); KoPathShape *pathShape = KoPathShape::createShapeFromPainterPath(path); //createShapeFromPainterPath converts the path topleft into a shape topleft //and the pathShape needs to be on top of us. So to preserve both we do: pathShape->setTransformation(pathShape->transformation() * transformation()); return new KoClipPath(this, new KoClipData(pathShape)); }
void TestPACopyPastePage::addShape( KoPAPageBase * page ) { KoPathShape * path = new KoPathShape(); path->lineTo( QPointF( 10, 0 ) ); path->lineTo( QPointF( 10, 10 ) ); path->setPosition( m_pos ); m_pos += QPointF( 1.0, 1.0 ); QList<KoShape*> shapes = page->shapes(); if ( !shapes.isEmpty() ) { KoShapeLayer* layer = dynamic_cast<KoShapeLayer*>( shapes.last() ); layer->addShape( path ); } }
void KoCreatePathTool::paintPath(KoPathShape& pathShape, QPainter &painter, const KoViewConverter &converter) { Q_D(KoCreatePathTool); painter.setTransform(pathShape.absoluteTransformation(&converter) * painter.transform()); painter.save(); KoShapePaintingContext paintContext; //FIXME pathShape.paint(painter, converter, paintContext); painter.restore(); if (pathShape.stroke()) { painter.save(); pathShape.stroke()->paint(d->shape, painter, converter); painter.restore(); } }
void KoPathShapeLoaderPrivate::svgMoveTo(qreal x1, qreal y1, bool abs) { if (abs) lastPoint = QPointF(x1, y1); else lastPoint += QPointF(x1, y1); path->moveTo(lastPoint); }
void KoPathBreakAtPointCommand::undo() { KUndo2Command::undo(); KoPathShape * lastPathShape = 0; for (int i = 0; i < m_pointDataList.size(); ++i) { const KoPathPointData & pd = m_pointDataList.at(i); KoPathShape * pathShape = pd.pathShape; KoPathPointIndex pointIndex = pd.pointIndex; ++pointIndex.second; if (m_closedIndex.at(i).first != -1) { m_closedIndex[i] = pathShape->closeSubpath(m_closedIndex.at(i)); } else { pointIndex.second = pointIndex.second + m_closedIndex.at(i).second; pathShape->join(pd.pointIndex.first); } m_points[i] = pathShape->removePoint(pointIndex); if (lastPathShape != pathShape) { if (lastPathShape) { lastPathShape->update(); } lastPathShape = pathShape; } } if (lastPathShape) { lastPathShape->update(); } m_deletePoints = true; }
KoPathControlPointMoveCommand::KoPathControlPointMoveCommand( const KoPathPointData &pointData, const QPointF &offset, KoPathPoint::PointType pointType, KUndo2Command *parent) : KUndo2Command(parent) , m_pointData(pointData) , m_pointType(pointType) { Q_ASSERT(offset.x() < 1e14 && offset.y() < 1e14); KoPathShape * pathShape = m_pointData.pathShape; KoPathPoint * point = pathShape->pointByIndex(m_pointData.pointIndex); if (point) { m_offset = point->parent()->documentToShape(offset) - point->parent()->documentToShape(QPointF(0, 0)); } setText(i18nc("(qtundo-format)", "Move control point")); }
void KoPathShapeLoaderPrivate::svgLineToVertical(qreal y, bool abs) { if (abs) lastPoint.setY(y); else lastPoint.ry() += y; path->lineTo(lastPoint); }
void KoPathShapeLoaderPrivate::svgLineToHorizontal(qreal x, bool abs) { if (abs) lastPoint.setX(x); else lastPoint.rx() += x; path->lineTo(lastPoint); }
void KoPathPointTypeCommand::undoChanges(const QList<PointData> &data) { QList<PointData>::const_iterator it(data.begin()); for (; it != data.end(); ++it) { KoPathShape *pathShape = it->m_pointData.pathShape; KoPathPoint *point = pathShape->pointByIndex(it->m_pointData.pointIndex); point->setProperties(it->m_oldProperties); if (it->m_hadControlPoint1) point->setControlPoint1(pathShape->documentToShape(it->m_oldControlPoint1)); else point->removeControlPoint1(); if (it->m_hadControlPoint2) point->setControlPoint2(pathShape->documentToShape(it->m_oldControlPoint2)); else point->removeControlPoint2(); } }
void KoPathControlPointMoveCommand::redo() { KUndo2Command::redo(); KoPathShape * pathShape = m_pointData.pathShape; KoPathPoint * point = pathShape->pointByIndex(m_pointData.pointIndex); if (point) { pathShape->update(); if (m_pointType == KoPathPoint::ControlPoint1) { point->setControlPoint1(point->controlPoint1() + m_offset); if (point->properties() & KoPathPoint::IsSymmetric) { // set the other control point so that it lies on the line between the moved // control point and the point, with the same distance to the point as the moved point point->setControlPoint2(2.0 * point->point() - point->controlPoint1()); } else if (point->properties() & KoPathPoint::IsSmooth) { // move the other control point so that it lies on the line through point and control point // keeping its distance to the point QPointF direction = point->point() - point->controlPoint1(); direction /= sqrt(direction.x() * direction.x() + direction.y() * direction.y()); QPointF distance = point->point() - point->controlPoint2(); qreal length = sqrt(distance.x() * distance.x() + distance.y() * distance.y()); point->setControlPoint2(point->point() + length * direction); } } else if (m_pointType == KoPathPoint::ControlPoint2) { point->setControlPoint2(point->controlPoint2() + m_offset); if (point->properties() & KoPathPoint::IsSymmetric) { // set the other control point so that it lies on the line between the moved // control point and the point, with the same distance to the point as the moved point point->setControlPoint1(2.0 * point->point() - point->controlPoint2()); } else if (point->properties() & KoPathPoint::IsSmooth) { // move the other control point so that it lies on the line through point and control point // keeping its distance to the point QPointF direction = point->point() - point->controlPoint2(); direction /= sqrt(direction.x() * direction.x() + direction.y() * direction.y()); QPointF distance = point->point() - point->controlPoint1(); qreal length = sqrt(distance.x() * distance.x() + distance.y() * distance.y()); point->setControlPoint1(point->point() + length * direction); } } pathShape->normalize(); pathShape->update(); } }
void KoPathBreakAtPointCommand::redo() { KUndo2Command::redo(); KoPathPointData last(0, KoPathPointIndex(-1, -1)); // offset, needed when path was opened int offset = 0; for (int i = m_pointDataList.size() - 1; i >= 0; --i) { const KoPathPointData & pd = m_pointDataList.at(i); KoPathShape * pathShape = pd.pathShape; KoPathPointIndex pointIndex = pd.pointIndex; if (last.pathShape != pathShape || last.pointIndex.first != pointIndex.first) { offset = 0; } pointIndex.second = pointIndex.second + offset + 1; pathShape->insertPoint(m_points[i], pointIndex); if (m_closedIndex.at(i).first != -1) { m_closedIndex[i] = pathShape->openSubpath(m_closedIndex.at(i)); offset = m_closedIndex.at(i).second; } else { KoPathPointIndex breakIndex = pd.pointIndex; breakIndex.second += offset; pathShape->breakAfter(breakIndex); m_closedIndex[i].second = offset; } if (last.pathShape != pathShape) { if (last.pathShape) { last.pathShape->update(); } last = pd; } } if (last.pathShape) { last.pathShape->update(); } m_deletePoints = false; }
/* * The algorithm to break a multiple open or closed subpaths is: * Subpath is closed * - open behind the last point in the subpath * - go on like as described in Not closed * Not closed * - break from the back of the subpath */ KoPathBreakAtPointCommand::KoPathBreakAtPointCommand(const QList<KoPathPointData> & pointDataList, KUndo2Command *parent) : KUndo2Command(parent) , m_deletePoints(true) { QList<KoPathPointData> sortedPointDataList(pointDataList); qSort(sortedPointDataList); setText(i18nc("(qtundo-format)", "Break subpath at points")); QList<KoPathPointData>::const_iterator it(sortedPointDataList.constBegin()); for (; it != sortedPointDataList.constEnd(); ++it) { KoPathShape * pathShape = it->pathShape; KoPathPoint * point = pathShape->pointByIndex(it->pointIndex); if(! point) continue; // check if subpath is closed and the point is start or end point of the subpath if(! pathShape->isClosedSubpath(it->pointIndex.first)) { if(it->pointIndex.second == 0 || it->pointIndex.second == pathShape->subpathPointCount(it->pointIndex.first)) { continue; } } m_pointDataList.append(*it); m_points.push_back(new KoPathPoint(*point)); m_closedIndex.push_back(KoPathPointIndex(-1, 0)); } KoPathPointData last(0, KoPathPointIndex(-1, -1)); for (int i = m_pointDataList.size() - 1; i >= 0; --i) { const KoPathPointData ¤t = m_pointDataList.at(i); if (last.pathShape != current.pathShape || last.pointIndex.first != current.pointIndex.first) { last = current; if (current.pathShape->isClosedSubpath(current.pointIndex.first)) { // the break will happen before the inserted point so we have to increment by 1 m_closedIndex[i] = current.pointIndex; ++m_closedIndex[i].second; } } } }
void KoShapeShadow::Private::paintShadow(KoShape *shape, QPainter &painter, const KoViewConverter &converter) { QPainterPath path(shape->shadowOutline()); if (!path.isEmpty()) { painter.save(); KoShape::applyConversion(painter, converter); painter.setBrush(QBrush(color)); // Make sure the shadow has the same fill rule as the shape. KoPathShape * pathShape = dynamic_cast<KoPathShape*>(shape); if (pathShape) path.setFillRule(pathShape->fillRule()); painter.drawPath(path); painter.restore(); } if (shape->stroke()) { shape->stroke()->paint(shape, painter, converter); } }
void KoSubpathJoinCommand::redo() { KUndo2Command::redo(); KoPathShape * pathShape = m_pointData1.pathShape; bool closeSubpath = m_pointData1.pointIndex.first == m_pointData2.pointIndex.first; KoPathPoint * point1 = pathShape->pointByIndex(m_pointData1.pointIndex); KoPathPoint * point2 = pathShape->pointByIndex(m_pointData2.pointIndex); // if the endpoint is has a control point create a contol point for the new segment to be // at the symetric position to the exiting one if (m_reverse & ReverseFirst || closeSubpath) { if (point1->activeControlPoint2()) point1->setControlPoint1(2.0 * point1->point() - point1->controlPoint2()); } else if (point1->activeControlPoint1()) point1->setControlPoint2(2.0 * point1->point() - point1->controlPoint1()); if (m_reverse & ReverseSecond || closeSubpath) { if (point2->activeControlPoint1()) point2->setControlPoint2(2.0 * point2->point() - point2->controlPoint1()); } else if (point2->activeControlPoint2()) point2->setControlPoint1(2.0 * point2->point() - point2->controlPoint2()); if (closeSubpath) { pathShape->closeSubpath(m_pointData1.pointIndex); } else { if (m_reverse & ReverseFirst) { pathShape->reverseSubpath(m_pointData1.pointIndex.first); } if (m_reverse & ReverseSecond) { pathShape->reverseSubpath(m_pointData2.pointIndex.first); } pathShape->moveSubpath(m_pointData2.pointIndex.first, m_pointData1.pointIndex.first + 1); m_splitIndex = m_pointData1.pointIndex; m_splitIndex.second = pathShape->subpathPointCount(m_pointData1.pointIndex.first) - 1; pathShape->join(m_pointData1.pointIndex.first); } pathShape->normalize(); pathShape->update(); }
KoPathPointInsertCommand::KoPathPointInsertCommand(const QList<KoPathPointData> & pointDataList, qreal insertPosition, QUndoCommand *parent) : QUndoCommand(parent) , m_deletePoints(true) { if (insertPosition < 0) insertPosition = 0; if (insertPosition > 1) insertPosition = 1; //TODO the list needs to be sorted QList<KoPathPointData>::const_iterator it(pointDataList.begin()); for (; it != pointDataList.end(); ++it) { KoPathShape * pathShape = it->pathShape; KoPathSegment segment = pathShape->segmentByIndex(it->pointIndex); // should not happen but to be sure if (! segment.isValid()) continue; m_pointDataList.append(*it); QPair<KoPathSegment, KoPathSegment> splitSegments = segment.splitAt( insertPosition ); KoPathPoint * split1 = splitSegments.first.second(); KoPathPoint * split2 = splitSegments.second.first(); KoPathPoint * splitPoint = new KoPathPoint( pathShape, split1->point() ); if( split1->activeControlPoint1() ) splitPoint->setControlPoint1(split1->controlPoint1()); if( split2->activeControlPoint2() ) splitPoint->setControlPoint2(split2->controlPoint2()); m_points.append(splitPoint); QPointF cp1 = splitSegments.first.first()->controlPoint2(); QPointF cp2 = splitSegments.second.second()->controlPoint1(); m_controlPoints.append(QPair<QPointF, QPointF>(cp1, cp2)); } }
void KoPathSegmentTypeCommand::initialize(const QList<KoPathPointData> & pointDataList) { QList<KoPathPointData>::const_iterator it(pointDataList.begin()); for (; it != pointDataList.end(); ++it) { KoPathSegment segment = it->pathShape->segmentByIndex(it->pointIndex); if (segment.isValid()) { if (m_segmentType == Curve) { // don not change segment if already a curve if (segment.first()->activeControlPoint2() || segment.second()->activeControlPoint1()) continue; } else { // do not change segment if already a line if (! segment.first()->activeControlPoint2() && ! segment.second()->activeControlPoint1()) continue; } m_pointDataList.append(*it); SegmentTypeData segmentData; KoPathShape * pathShape = segment.first()->parent(); // we are changing a curve to a line -> save control point positions if (m_segmentType == Line) { segmentData.m_controlPoint2 = pathShape->shapeToDocument(segment.first()->controlPoint2()); segmentData.m_controlPoint1 = pathShape->shapeToDocument(segment.second()->controlPoint1()); } // save point properties segmentData.m_properties2 = segment.first()->properties(); segmentData.m_properties1 = segment.second()->properties(); m_segmentData.append(segmentData); } } if (m_segmentType == Curve) { setText(i18nc("(qtundo-format)", "Change segments to curves")); } else { setText(i18nc("(qtundo-format)", "Change segments to lines")); } }
KoPathShape * bezierFit(const QList<QPointF> &points, float error) { FitVector tHat1, tHat2; tHat1 = ComputeLeftTangent(points, 0); tHat2 = ComputeRightTangent(points, points.count() - 1); int width = 0; QPointF *curve; curve = FitCubic(points, 0, points.count() - 1, tHat1, tHat2, error, width); KoPathShape * path = new KoPathShape(); if (width > 3) { path->moveTo(curve[0]); path->curveTo(curve[1], curve[2], curve[3]); for (int i = 4; i < width; i += 4) { path->curveTo(curve[i+1], curve[i+2], curve[i+3]); } } delete[] curve; return path; }
void KoPathShapeLoaderPrivate::svgCurveToCubic(qreal x1, qreal y1, qreal x2, qreal y2, qreal x, qreal y, bool abs) { QPointF p1, p2; if (abs) { p1 = QPointF(x1, y1); p2 = QPointF(x2, y2); lastPoint = QPointF(x, y); } else { p1 = lastPoint + QPointF(x1, y1); p2 = lastPoint + QPointF(x2, y2); lastPoint += QPointF(x, y); } path->curveTo(p1, p2, lastPoint); }
KoShape *KoPathShapeFactory::createDefaultShape(KoDocumentResourceManager *) const { KoPathShape* path = new KoPathShape(); path->moveTo(QPointF(0, 50)); path->curveTo(QPointF(0, 120), QPointF(50, 120), QPointF(50, 50)); path->curveTo(QPointF(50, -20), QPointF(100, -20), QPointF(100, 50)); path->normalize(); path->setStroke(new KoShapeStroke(1.0)); return path; }
void TestSnapStrategy::testExtensionSnap() { //bool ExtensionSnapStrategy::snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) ExtensionSnapStrategy toTest; const QPointF paramMousePos; MockShapeController fakeShapeControllerBase; MockCanvas fakeKoCanvasBase(&fakeShapeControllerBase); KoSnapGuide aKoSnapGuide(&fakeKoCanvasBase); KoSnapProxy paramProxy(&aKoSnapGuide); qreal paramSnapDistance = 0; bool didSnap = toTest.snap(paramMousePos, ¶mProxy, paramSnapDistance); QVERIFY(!didSnap); //Second test case - testing the snap by providing ShapeManager with a shape that has snap points and a path //fakeShapeOne needs at least one subpath that is open in order to change the values of minDistances //which in turn opens the path where it is possible to get a true bool value back from the snap function // KoPathPointIndex openSubpath(const KoPathPointIndex &pointIndex); in KoPathShape needs to be called ExtensionSnapStrategy toTestTwo; const QPointF paramMousePosTwo; MockShapeController fakeShapeControllerBaseTwo; MockCanvas fakeKoCanvasBaseTwo(&fakeShapeControllerBaseTwo); KoShapeManager *fakeShapeManager = fakeKoCanvasBaseTwo.shapeManager(); KoPathShape fakeShapeOne; QList<QPointF> firstSnapPointList; firstSnapPointList.push_back(QPointF(1,2)); firstSnapPointList.push_back(QPointF(2,2)); firstSnapPointList.push_back(QPointF(3,2)); firstSnapPointList.push_back(QPointF(4,2)); qreal paramSnapDistanceTwo = 4; fakeShapeOne.snapData().setSnapPoints(firstSnapPointList); fakeShapeOne.isVisible(true); QPointF firstPoint(0,2); QPointF secondPoint(1,2); QPointF thirdPoint(2,3); QPointF fourthPoint(3,4); fakeShapeOne.moveTo(firstPoint); fakeShapeOne.lineTo(secondPoint); fakeShapeOne.lineTo(thirdPoint); fakeShapeOne.lineTo(fourthPoint); fakeShapeManager->addShape(&fakeShapeOne); KoSnapGuide aKoSnapGuideTwo(&fakeKoCanvasBaseTwo); KoSnapProxy paramProxyTwo(&aKoSnapGuideTwo); bool didSnapTwo = toTest.snap(paramMousePosTwo, ¶mProxyTwo, paramSnapDistanceTwo); QVERIFY(didSnapTwo); }