Warning, file /office/calligra/libs/flake/KoPathShape.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright (C) 2006, 2011 Thorsten Zachmann <zachmann@kde.org>
0003    Copyright (C) 2007,2009 Thomas Zander <zander@kde.org>
0004    Copyright (C) 2006-2008 Jan Hambrecht <jaham@gmx.net>
0005    Copyright (C) 2011 Jean-Nicolas Artaud <jeannicolasartaud@gmail.com>
0006 
0007    This library is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Library General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This library is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    Library General Public License for more details.
0016 
0017    You should have received a copy of the GNU Library General Public License
0018    along with this library; see the file COPYING.LIB.  If not, write to
0019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  * Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #ifndef KOPATHSHAPE_H
0024 #define KOPATHSHAPE_H
0025 
0026 #include "flake_export.h"
0027 
0028 #include <QMetaType>
0029 #include <QTransform>
0030 
0031 #include "KoTosContainer.h"
0032 #include "KoMarkerData.h"
0033 
0034 #define KoPathShapeId "KoPathShape"
0035 
0036 class KoPathSegment;
0037 class KoPathPoint;
0038 class KoPathShapePrivate;
0039 class KoMarker;
0040 
0041 typedef QPair<int, int> KoPathPointIndex;
0042 
0043 /// a KoSubpath contains a path from a moveTo until a close or a new moveTo
0044 typedef QList<KoPathPoint *> KoSubpath;
0045 typedef QList<KoSubpath *> KoSubpathList;
0046 /// The position of a path point within a path shape
0047 /**
0048  * @brief This is the base for all graphical objects.
0049  *
0050  * All graphical objects are based on this object e.g. lines, rectangulars, pies
0051  * and so on.
0052  *
0053  * The KoPathShape uses KoPathPoint's to describe the path of the shape.
0054  *
0055  * Here a short example:
0056  * 3 points connected by a curveTo's described by the following svg:
0057  * M 100,200 C 100,100 250,100 250,200 C 250,200 400,300 400,200.
0058  *
0059  * This will be stored in 3 KoPathPoint's as
0060  * The first point contains in
0061  *       point 100,200
0062  *       controlPoint2 100,100
0063  * The second point contains in
0064  *       point 250,200
0065  *       controlPoint1 250,100
0066  *       controlPoint2 250,300
0067  * The third point contains in
0068  *       point 400,300
0069  *       controlPoint1 400,200
0070  *
0071  * Not the segments are stored but the points. Out of the points the segments are
0072  * generated. See the outline method. The reason for storing it like that is that
0073  * it is the points that are modified by the user and not the segments.
0074  */
0075 class FLAKE_EXPORT KoPathShape : public KoTosContainer
0076 {
0077 public:
0078     /**
0079      * @brief constructor
0080      */
0081     KoPathShape();
0082 
0083     /**
0084      * @brief
0085      */
0086     ~KoPathShape() override;
0087 
0088     /// reimplemented
0089     void paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) override;
0090     virtual void paintPoints(QPainter &painter, const KoViewConverter &converter, int handleRadius);
0091     /// reimplemented
0092     QPainterPath outline() const override;
0093     /// reimplemented
0094     QRectF boundingRect() const override;
0095     /// reimplemented
0096     QSizeF size() const override;
0097 
0098     QPainterPath pathStroke(const QPen &pen) const;
0099     /**
0100      * Resize the shape
0101      *
0102      * This makes sure that the pathshape will not be resized to 0 if the new size
0103      * is null as that makes it impossible to undo the change.
0104      *
0105      * All functions that overwrite this function should also use the resizeMatrix
0106      * function to get and use the same data in resizing.
0107      *
0108      * @see resizeMatrix()
0109      */
0110     void setSize(const QSizeF &size) override;
0111     /// reimplemented
0112     bool hitTest(const QPointF &position) const override;
0113 
0114     // reimplemented
0115     void saveOdf(KoShapeSavingContext &context) const override;
0116     // reimplemented
0117     bool loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) override;
0118 
0119     // basically the same as loadOdf but adapted to the contour cases
0120     // tag needs to be either contour-polygon or contour-path from another shape
0121     bool loadContourOdf(const KoXmlElement & element, KoShapeLoadingContext &context, const QSizeF &scaleFactor);
0122 
0123     /** basically the equivalent saveOdf but adapted to the contour cases
0124      * @param context saving context
0125      * @param originalSize the original size of the unscaled image.
0126      */
0127     void saveContourOdf(KoShapeSavingContext &context, const QSizeF &originalSize) const;
0128 
0129     /// Removes all subpaths and their points from the path
0130     void clear();
0131     /**
0132      * @brief Starts a new Subpath
0133      *
0134      * Moves the pen to p and starts a new subpath.
0135      *
0136      * @return the newly created point
0137      */
0138     KoPathPoint *moveTo(const QPointF &p);
0139 
0140     /**
0141      * @brief Adds a new line segment
0142      *
0143      * Adds a straight line between the last point and the given point p.
0144      *
0145      * @return the newly created point
0146      */
0147     KoPathPoint *lineTo(const QPointF &p);
0148 
0149     /**
0150      * @brief Adds a new cubic Bezier curve segment.
0151      *
0152      * Adds a cubic Bezier curve between the last point and the given point p,
0153      * using the control points specified by c1 and c2.
0154      *
0155      * @param c1 control point1
0156      * @param c2 control point2
0157      * @param p the endpoint of this curve segment
0158      *
0159      * @return The newly created point
0160      */
0161     KoPathPoint *curveTo(const QPointF &c1, const QPointF &c2, const QPointF &p);
0162 
0163     /**
0164      * @brief Adds a new quadratic Bezier curve segment.
0165      *
0166      * Adds a quadratic Bezier curve between the last point and the given point p,
0167      * using the control point specified by c.
0168      *
0169      * @param c control point
0170      * @param p the endpoint of this curve segment
0171      *
0172      * @return The newly created point
0173      */
0174     KoPathPoint *curveTo(const QPointF &c, const QPointF &p);
0175 
0176     /**
0177      * @brief Add an arc.
0178      *
0179      * Adds an arc starting at the current point. The arc will be converted to bezier curves.
0180      *
0181      * @param rx x radius of the ellipse
0182      * @param ry y radius of the ellipse
0183      * @param startAngle the angle where the arc will be started
0184      * @param sweepAngle the length of the angle
0185      * TODO add param to have angle of the ellipse
0186      *
0187      * @return The newly created point
0188      */
0189     KoPathPoint *arcTo(qreal rx, qreal ry, qreal startAngle, qreal sweepAngle);
0190 
0191 
0192     /**
0193      * @brief Closes the current subpath
0194      */
0195     void close();
0196 
0197     /**
0198      * @brief Closes the current subpath
0199      *
0200      * It tries to merge the last and first point of the subpath
0201      * to one point and then closes the subpath. If merging is not
0202      * possible as the two point are to far from each other a close
0203      * will be done.
0204      * TODO define a maximum distance between  the two points until this is working
0205      */
0206     void closeMerge();
0207 
0208     /**
0209      * @brief Normalizes the path data.
0210      *
0211      * The path points are transformed so that the top-left corner
0212      * of the bounding rect is at (0,0).
0213      * This should be called after adding points to the path or changing
0214      * positions of path points.
0215      * @return the offset by which the points are moved in shape coordinates.
0216      */
0217     virtual QPointF normalize();
0218 
0219     /**
0220      * @brief Returns the path points within the given rectangle.
0221      * @param rect the rectangle the requested points are in
0222      * @return list of points within the rectangle
0223      */
0224     QList<KoPathPoint*> pointsAt(const QRectF &rect) const;
0225 
0226     /**
0227      * @brief Returns the list of path segments within the given rectangle.
0228      * @param rect the rectangle the requested segments are in
0229      * @return list of segments within the rectangle
0230      */
0231     QList<KoPathSegment> segmentsAt(const QRectF &rect) const;
0232 
0233     /**
0234      * @brief Returns the path point index of a given path point
0235      *
0236      * @param point the point for which you want to get the index
0237      * @return path point index of the point if it exists
0238      *         otherwise KoPathPointIndex( -1, -1 )
0239      */
0240     KoPathPointIndex pathPointIndex(const KoPathPoint *point) const;
0241 
0242     /**
0243      * @brief Returns the path point specified by a path point index
0244      *
0245      * @param pointIndex index of the point to get
0246      *
0247      * @return KoPathPoint on success, 0 otherwise e.g. out of bounds
0248      */
0249     KoPathPoint *pointByIndex(const KoPathPointIndex &pointIndex) const;
0250 
0251     /**
0252      * @brief Returns the segment specified by a path point index
0253      *
0254      * A semgent is defined by the point index of the first point in the segment.
0255      * A segment contains the defined point and its following point. If the subpath is
0256      * closed and the and the pointIndex point to the last point in the subpath, the
0257      * following point is the first point in the subpath.
0258      *
0259      * @param pointIndex index of the first point of the segment
0260      *
0261      * @return Segment containing both points of the segment or KoPathSegment( 0, 0 ) on error e.g. out of bounds
0262      */
0263     KoPathSegment segmentByIndex(const KoPathPointIndex &pointIndex) const;
0264 
0265     /**
0266      * @brief Returns the number of points in the path
0267      *
0268      * @return The number of points in the path
0269      */
0270     int pointCount() const;
0271 
0272     /**
0273      * @brief Returns the number of subpaths in the path
0274      *
0275      * @return The number of subpaths in the path
0276      */
0277     int subpathCount() const;
0278 
0279     /**
0280      * @brief Returns the number of points in a subpath
0281      *
0282      * @return The number of points in the subpath or -1 if subpath out of bounds
0283      */
0284     int subpathPointCount(int subpathIndex) const;
0285 
0286     /**
0287      * @brief Checks if a subpath is closed
0288      *
0289      * @param subpathIndex index of the subpath to check
0290      *
0291      * @return true when the subpath is closed, false otherwise
0292      */
0293     bool isClosedSubpath(int subpathIndex) const;
0294 
0295     /**
0296      * @brief Inserts a new point into the given subpath at the specified position
0297      *
0298      * This method keeps the subpath closed if it is closed, and open when it was
0299      * open. So it can change the properties of the point inserted.
0300      * You might need to update the point before/after to get the desired result
0301      * e.g. when you insert the point into a curve.
0302      *
0303      * @param point to insert
0304      * @param pointIndex index at which the point should be inserted
0305      *
0306      * @return true on success,
0307      *         false when pointIndex is out of bounds
0308      */
0309     bool insertPoint(KoPathPoint *point, const KoPathPointIndex &pointIndex);
0310 
0311     /**
0312      * @brief Removes a point from the path.
0313      *
0314      * Note that the ownership of the point will pass to the caller.
0315      *
0316      * @param pointIndex index of the point which should be removed
0317      *
0318      * @return The removed point on success,
0319      *         otherwise 0
0320      */
0321     KoPathPoint *removePoint(const KoPathPointIndex &pointIndex);
0322 
0323     /**
0324      * @brief Breaks the path after the point index
0325      *
0326      * The new subpath will be behind the one that was broken. The segment between
0327      * the given point and the one behind will be removed. If you want to split at
0328      * one point insert first a copy of the point behind it.
0329      * This does not work when the subpath is closed. Use openSubpath for this.
0330      * It does not break at the last position of a subpath or if there is only one
0331      * point in the subpath.
0332      *
0333      * @param pointIndex index of the point after which the path should be broken
0334      *
0335      * @return true if the subpath was broken, otherwise false
0336      */
0337     bool breakAfter(const KoPathPointIndex &pointIndex);
0338 
0339     /**
0340      * @brief Joins the given subpath with the following one
0341      *
0342      * Joins the given subpath with the following one by inserting a segment between
0343      * the two subpaths.
0344      * This does nothing if the specified subpath is the last subpath
0345      * or one of both subpaths is closed.
0346      *
0347      * @param subpathIndex index of the subpath being joined with the following subpath
0348      *
0349      * @return true if the subpath was joined, otherwise false
0350      */
0351     bool join(int subpathIndex);
0352 
0353     /**
0354      * @brief Moves the position of a subpath within a path
0355      *
0356      * @param oldSubpathIndex old index of the subpath
0357      * @param newSubpathIndex new index of the subpath
0358      *
0359      * @return true if the subpath was moved, otherwise false e.g. if an index is out of bounds
0360      */
0361     bool moveSubpath(int oldSubpathIndex, int newSubpathIndex);
0362 
0363     /**
0364      * @brief Opens a closed subpath
0365      *
0366      * The subpath is opened by removing the segment before the given point, making
0367      * the given point the new start point of the subpath.
0368      *
0369      * @param pointIndex the index of the point at which to open the closed subpath
0370      * @return the new position of the old first point in the subpath
0371      *         otherwise KoPathPointIndex( -1, -1 )
0372      */
0373     KoPathPointIndex openSubpath(const KoPathPointIndex &pointIndex);
0374 
0375     /**
0376      * @brief Close a open subpath
0377      *
0378      * The subpath is closed be inserting a segment between the start and end point, making
0379      * the given point the new start point of the subpath.
0380      *
0381      * @return the new position of the old first point in the subpath
0382      *         otherwise KoPathPointIndex( -1, -1 )
0383      */
0384     KoPathPointIndex closeSubpath(const KoPathPointIndex &pointIndex);
0385 
0386     /**
0387      * @brief Reverse subpath
0388      *
0389      * The last point becomes the first point and the first one becomes the last one.
0390      *
0391      * @param subpathIndex the index of the subpath to reverse
0392      */
0393     bool reverseSubpath(int subpathIndex);
0394 
0395     /**
0396      * @brief Removes subpath from the path
0397      * @param subpathIndex the index of the subpath to remove
0398      * @return the removed subpath on succes, 0 otherwise.
0399      */
0400     KoSubpath *removeSubpath(int subpathIndex);
0401 
0402     /**
0403      * @brief Adds a subpath at the given index to the path
0404      * @param subpath the subpath to add
0405      * @param subpathIndex the index at which the new subpath should be inserted
0406      * @return true on success, false otherwise e.g. subpathIndex out of bounds
0407      */
0408     bool addSubpath(KoSubpath *subpath, int subpathIndex);
0409 
0410     /**
0411      * @brief Combines two path shapes by appending the data of the specified path.
0412      * @param path the path to combine with
0413      * @return true if combining was successful, else false
0414      */
0415     bool combine(KoPathShape *path);
0416 
0417     /**
0418      * @brief Creates separate path shapes, one for each existing subpath.
0419      * @param separatedPaths the list which contains the separated path shapes
0420      * @return true if separating the path was successful, false otherwise
0421      */
0422     bool separate(QList<KoPathShape*> &separatedPaths);
0423 
0424     /**
0425      * Returns the specific path shape id.
0426      *
0427      * Path shape derived shapes have a different shape id which link them
0428      * to their respective shape factories. In most cases they do not have
0429      * a special tool for editing them.
0430      * This function returns the specific shape id for finding the shape
0431      * factory from KoShapeRegistry. The default KoPathShapeId is returned
0432      * from KoShape::shapeId() so that the generic path editing tool gets
0433      * activated when the shape is selected.
0434      *
0435      * @return the specific shape id
0436      */
0437     virtual QString pathShapeId() const;
0438 
0439     /// Returns a odf/svg string representation of the path data with the given matrix applied.
0440     QString toString(const QTransform &matrix = QTransform()) const;
0441 
0442     /// Returns the fill rule for the path object
0443     Qt::FillRule fillRule() const;
0444 
0445     /// Sets the fill rule to be used for painting the background
0446     void setFillRule(Qt::FillRule fillRule);
0447 
0448     /// Creates path shape from given QPainterPath
0449     static KoPathShape *createShapeFromPainterPath(const QPainterPath &path);
0450 
0451     /// Returns the viewbox from the given xml element.
0452     static QRect loadOdfViewbox(const KoXmlElement &element);
0453 
0454     /// Marker setter
0455     void setMarker(const KoMarkerData &markerData);
0456 
0457     /// Marker setter
0458     void setMarker(KoMarker *marker, KoMarkerData::MarkerPosition position);
0459 
0460     /// returns the list of all the markers of the path
0461     KoMarker *marker(KoMarkerData::MarkerPosition position) const;
0462 
0463     KoMarkerData markerData(KoMarkerData::MarkerPosition position) const;
0464 
0465 protected:
0466     /// constructor \internal
0467     KoPathShape(KoPathShapePrivate &);
0468 
0469     /// reimplemented
0470     QString saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const override;
0471     /// reimplemented
0472     void loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context) override;
0473 
0474     /**
0475      * @brief Add an arc.
0476      *
0477      * Adds an arc starting at the current point. The arc will be converted to bezier curves.
0478      * @param rx x radius of the ellipse
0479      * @param ry y radius of the ellipse
0480      * @param startAngle the angle where the arc will be started
0481      * @param sweepAngle the length of the angle
0482      * TODO add param to have angle of the ellipse
0483      * @param offset to the first point in the arc
0484      * @param curvePoints a array which take the cuve points, pass a 'QPointF curvePoins[12]';
0485      *
0486      * @return number of points created by the curve
0487      */
0488     int arcToCurve(qreal rx, qreal ry, qreal startAngle, qreal sweepAngle, const QPointF &offset, QPointF *curvePoints) const;
0489 
0490     /**
0491      * Get the resize matrix
0492      *
0493      * This makes sure that also if the newSize isNull that there will be a
0494      * very small size of 0.000001 pixels
0495      */
0496     QTransform resizeMatrix( const QSizeF &newSize ) const;
0497 
0498     KoSubpathList m_subpaths;
0499 
0500 private:
0501     Q_DECLARE_PRIVATE(KoPathShape)
0502 };
0503 
0504 Q_DECLARE_METATYPE(KoPathShape*)
0505 
0506 #endif /* KOPATHSHAPE_H */