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 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(); } }
bool KoPathPointTypeCommand::appendPointData(KoPathPointData data) { KoPathPoint *point = data.pathShape->pointByIndex(data.pointIndex); if (! point) return false; PointData pointData(data); pointData.m_oldControlPoint1 = data.pathShape->shapeToDocument(point->controlPoint1()); pointData.m_oldControlPoint2 = data.pathShape->shapeToDocument(point->controlPoint2()); pointData.m_oldProperties = point->properties(); pointData.m_hadControlPoint1 = point->activeControlPoint1(); pointData.m_hadControlPoint2 = point->activeControlPoint2(); m_additionalPointData.append(pointData); return true; }
void KarbonSimplifyPath::removeDuplicates(KoPathShape *path) { // NOTE: works because path has only has one subshape, if this ever moves in // KoPathPoint it should be changed for (int i = 1; i < path->pointCount(); ++i) { KoPathPoint *p = path->pointByIndex(KoPathPointIndex(0, i)); KoPathPoint *prev = path->pointByIndex(KoPathPointIndex(0, i - 1)); QPointF diff = p->point() - prev->point(); // if diff = 0 remove point if (qFuzzyCompare(diff.x() + 1, 1) && qFuzzyCompare(diff.y() + 1, 1)) { if (prev->activeControlPoint1()) p->setControlPoint1(prev->controlPoint1()); else p->removeControlPoint1(); delete path->removePoint(KoPathPointIndex(0, i - 1)); --i; } } }
void KoCreatePathTool::mouseReleaseEvent(KoPointerEvent *event) { Q_D(KoCreatePathTool); if (! d->shape || (event->buttons() & Qt::RightButton)) return; d->listeningToModifiers = true; // After the first press-and-release d->repaintActivePoint(); d->pointIsDragged = false; KoPathPoint *lastActivePoint = d->activePoint; if (!d->finishAfterThisPoint) { d->activePoint = d->shape->lineTo(event->point); canvas()->snapGuide()->setIgnoredPathPoints((QList<KoPathPoint*>()<<d->activePoint)); } // apply symmetric point property if applicable if (lastActivePoint->activeControlPoint1() && lastActivePoint->activeControlPoint2()) { QPointF diff1 = lastActivePoint->point() - lastActivePoint->controlPoint1(); QPointF diff2 = lastActivePoint->controlPoint2() - lastActivePoint->point(); if (qFuzzyCompare(diff1.x(), diff2.x()) && qFuzzyCompare(diff1.y(), diff2.y())) lastActivePoint->setProperty(KoPathPoint::IsSymmetric); } if (d->finishAfterThisPoint) { d->firstPoint->setControlPoint1(d->activePoint->controlPoint1()); delete d->shape->removePoint(d->shape->pathPointIndex(d->activePoint)); d->activePoint = d->firstPoint; d->shape->closeMerge(); // we are closing the path, so reset the existing start path point d->existingStartPoint = 0; // finish path endPath(); } if (d->angleSnapStrategy && lastActivePoint->activeControlPoint2()) { d->angleSnapStrategy->deactivate(); } }
void KarbonWhirlPinchCommand::redo() { d->pathShape->update(); uint subpathCount = d->pathData.count(); for( uint subpathIndex = 0; subpathIndex < subpathCount; ++subpathIndex ) { uint pointCount = d->pathData[subpathIndex].count(); for( uint pointIndex = 0; pointIndex < pointCount; ++pointIndex ) { KoPathPoint * p = d->pathShape->pointByIndex( KoPathPointIndex( subpathIndex, pointIndex ) ); p->setPoint( d->whirlPinch( p->point() ) ); if( p->activeControlPoint1() ) p->setControlPoint1( d->whirlPinch( p->controlPoint1() ) ); if( p->activeControlPoint2() ) p->setControlPoint2( d->whirlPinch( p->controlPoint2() ) ); } } d->pathShape->normalize(); d->pathShape->update(); QUndoCommand::redo(); }
KoPathPointTypeCommand::KoPathPointTypeCommand( const QList<KoPathPointData> & pointDataList, PointType pointType, KUndo2Command *parent) : KoPathBaseCommand(parent) , m_pointType(pointType) { QList<KoPathPointData>::const_iterator it(pointDataList.begin()); for (; it != pointDataList.end(); ++it) { KoPathPoint *point = it->pathShape->pointByIndex(it->pointIndex); if (point) { PointData pointData(*it); pointData.m_oldControlPoint1 = it->pathShape->shapeToDocument(point->controlPoint1()); pointData.m_oldControlPoint2 = it->pathShape->shapeToDocument(point->controlPoint2()); pointData.m_oldProperties = point->properties(); pointData.m_hadControlPoint1 = point->activeControlPoint1(); pointData.m_hadControlPoint2 = point->activeControlPoint2(); m_oldPointData.append(pointData); m_shapes.insert(it->pathShape); } } setText(QObject::tr("Set point type")); }
void KoPathPointTypeCommand::redo() { KUndo2Command::redo(); repaint(false); m_additionalPointData.clear(); QList<PointData>::iterator it(m_oldPointData.begin()); for (; it != m_oldPointData.end(); ++it) { KoPathPoint *point = it->m_pointData.pathShape->pointByIndex(it->m_pointData.pointIndex); KoPathPoint::PointProperties properties = point->properties(); switch (m_pointType) { case Line: { point->removeControlPoint1(); point->removeControlPoint2(); break; } case Curve: { KoPathPointIndex pointIndex = it->m_pointData.pointIndex; KoPathPointIndex prevIndex; KoPathPointIndex nextIndex; KoPathShape * path = it->m_pointData.pathShape; // get previous path node if (pointIndex.second > 0) prevIndex = KoPathPointIndex(pointIndex.first, pointIndex.second - 1); else if (pointIndex.second == 0 && path->isClosedSubpath(pointIndex.first)) prevIndex = KoPathPointIndex(pointIndex.first, path->subpathPointCount(pointIndex.first) - 1); // get next node if (pointIndex.second < path->subpathPointCount(pointIndex.first) - 1) nextIndex = KoPathPointIndex(pointIndex.first, pointIndex.second + 1); else if (pointIndex.second < path->subpathPointCount(pointIndex.first) - 1 && path->isClosedSubpath(pointIndex.first)) nextIndex = KoPathPointIndex(pointIndex.first, 0); KoPathPoint * prevPoint = path->pointByIndex(prevIndex); KoPathPoint * nextPoint = path->pointByIndex(nextIndex); if (prevPoint && ! point->activeControlPoint1() && appendPointData(KoPathPointData(path, prevIndex))) { KoPathSegment cubic = KoPathSegment(prevPoint, point).toCubic(); if (prevPoint->activeControlPoint2()) { prevPoint->setControlPoint2(cubic.first()->controlPoint2()); point->setControlPoint1(cubic.second()->controlPoint1()); } else point->setControlPoint1(cubic.second()->controlPoint1()); } if (nextPoint && ! point->activeControlPoint2() && appendPointData(KoPathPointData(path, nextIndex))) { KoPathSegment cubic = KoPathSegment(point, nextPoint).toCubic(); if (nextPoint->activeControlPoint1()) { point->setControlPoint2(cubic.first()->controlPoint2()); nextPoint->setControlPoint1(cubic.second()->controlPoint1()); } else point->setControlPoint2(cubic.first()->controlPoint2()); } break; } case Symmetric: { properties &= ~KoPathPoint::IsSmooth; properties |= KoPathPoint::IsSymmetric; // calculate vector from node point to first control point and normalize it QPointF directionC1 = point->controlPoint1() - point->point(); qreal dirLengthC1 = sqrt(directionC1.x() * directionC1.x() + directionC1.y() * directionC1.y()); directionC1 /= dirLengthC1; // calculate vector from node point to second control point and normalize it QPointF directionC2 = point->controlPoint2() - point->point(); qreal dirLengthC2 = sqrt(directionC2.x() * directionC2.x() + directionC2.y() * directionC2.y()); directionC2 /= dirLengthC2; // calculate the average distance of the control points to the node point qreal averageLength = 0.5 * (dirLengthC1 + dirLengthC2); // compute position of the control points so that they lie on a line going through the node point // the new distance of the control points is the average distance to the node point point->setControlPoint1(point->point() + 0.5 * averageLength * (directionC1 - directionC2)); point->setControlPoint2(point->point() + 0.5 * averageLength * (directionC2 - directionC1)); } break; case Smooth: { properties &= ~KoPathPoint::IsSymmetric; properties |= KoPathPoint::IsSmooth; // calculate vector from node point to first control point and normalize it QPointF directionC1 = point->controlPoint1() - point->point(); qreal dirLengthC1 = sqrt(directionC1.x() * directionC1.x() + directionC1.y() * directionC1.y()); directionC1 /= dirLengthC1; // calculate vector from node point to second control point and normalize it QPointF directionC2 = point->controlPoint2() - point->point(); qreal dirLengthC2 = sqrt(directionC2.x() * directionC2.x() + directionC2.y() * directionC2.y()); directionC2 /= dirLengthC2; // compute position of the control points so that they lie on a line going through the node point // the new distance of the control points is the average distance to the node point point->setControlPoint1(point->point() + 0.5 * dirLengthC1 * (directionC1 - directionC2)); point->setControlPoint2(point->point() + 0.5 * dirLengthC2 * (directionC2 - directionC1)); } break; case Corner: default: properties &= ~KoPathPoint::IsSymmetric; properties &= ~KoPathPoint::IsSmooth; break; } point->setProperties(properties); } repaint(true); }