diff options
Diffstat (limited to 'karbon/core/vsegment.h')
-rw-r--r-- | karbon/core/vsegment.h | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/karbon/core/vsegment.h b/karbon/core/vsegment.h new file mode 100644 index 00000000..402946a8 --- /dev/null +++ b/karbon/core/vsegment.h @@ -0,0 +1,432 @@ +/* This file is part of the KDE project + Copyright (C) 2001, 2002, 2003 The Karbon Developers + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#ifndef __VSEGMENT_H__ +#define __VSEGMENT_H__ + +#include <qptrlist.h> +#include <qvaluelist.h> + +#include <KoPoint.h> +#include <KoRect.h> + +#include "vglobal.h" +#include <koffice_export.h> + +class QDomElement; +class VPainter; + +/** + * A class representing lines and beziers. We waste some KoPoints, if we + * would use only lines, but this makes it easy to convert the segment types + * into each other. Make sure yourself, that you pass values to functions within + * proper ranges. + */ + +class KARBONBASE_EXPORT VSegment +{ + friend class VSubpath; + friend class VSubpathIterator; + +public: + /** + * Tells which control point is "fixed" i.e. located at the + * corresponding knot and invisible. This flag makes no sense for + * line segments. + */ + enum VCtrlPointFixing + { + none = 0, + first = 1, + second = 2 + }; + + enum VState + { + normal, + deleted + }; + + + VSegment( unsigned short deg = 3 ); + + VSegment( const VSegment& segment ); + + ~VSegment(); + + /** + * Returns the segment's degree, which is identical to the number of nodes. + * For cubic beziers it is "three" and "one" for lines. + */ + unsigned short degree() const + { + return m_degree; + } + + /** + * Sets the segment's degree and thus resizes the array of node data. + * The node data is copied from the old knot "backwards". + */ + void setDegree( unsigned short deg ); + + /** + * Tests for the segment type ("begin", "line" or "curve"). + */ + bool isBegin() const { return (degree() == 1) && !prev(); } + bool isLine() const { return (degree() == 1) && prev(); } + bool isCurve() const { return degree() > 1; } + + /** + * Returns the segment state. + */ + VState state() const + { + return m_state; + } + + /** + * Sets the segment state. + */ + void setState( VState state ) + { + m_state = state; + } + + + /** + * Returns the segment's point with index 0 <= i < degree(). + */ + const KoPoint& point( int i ) const + { + return m_nodes[ i ].m_vector; + } + + /** + * This is a convenience function. It returns the point with index + * 0 <= i <= degree() while p( 0 ) is the knot of the previous + * segment. + */ + const KoPoint& p( int i ) const + { + return i == 0 + ? prev()->knot() + : m_nodes[ --i ].m_vector; + } + + /** + * Returns the knot. This is a convenience function using point(). + */ + const KoPoint& knot() const + { + return point( degree() - 1 ); + } + + /** + * Sets the segment's point with index 0 <= i < degree() to "p". + */ + void setPoint( int i, const KoPoint& p ) + { + m_nodes[ i ].m_vector = p; + } + + /** + * This is a convenience function. It sets the point with index + * 0 <= i <= degree() to "p" while setP( 0 ) sets the knot of the + * previous segment. + */ + void setP( int i, const KoPoint& p ) + { + if( i == 0 ) + prev()->setKnot( p ); + else + m_nodes[ --i ].m_vector = p; + } + + /** + * Sets the knot. This is a convenience function. + */ + void setKnot( const KoPoint& p ) + { + m_nodes[ degree() - 1 ].m_vector = p; + } + + + /** + * Returns true if the point with index 0 <= i < degree() is selected. + */ + bool pointIsSelected( int i ) const + { + return m_nodes[ i ].m_isSelected; + } + + /** + * Returns true if the knot is selected. This is a convenience function. + */ + bool knotIsSelected() const + { + return m_nodes[ degree() - 1 ].m_isSelected; + } + + /** + * Selects the point with index 0 <= i < degree(). + */ + void selectPoint( int i, bool select = true ) + { + m_nodes[ i ].m_isSelected = select; + } + + /** + * Selects/deselects the knot of this segment. + */ + void selectKnot( bool select = true ) + { + m_nodes[ degree() - 1 ].m_isSelected = select; + } + + + /** + * Returns index of the node at point p. Returns 0 if no + * segment point matches point p. + */ + // TODO: Move this function into "userland" + uint nodeNear( const KoPoint& p, + double isNearRange = VGlobal::isNearRange ) const; + + + /** + * Returns a pointer to the previous not deleted segment, if + * stored in a VSubpath. + */ + VSegment* prev() const; + + /** + * Returns a pointer to the next not deleted segment, if + * stored in a VSubpath. + */ + VSegment* next() const; + + /** + * Returns true if the segment is flat. That means it's height + * is smaller than flatness. + */ + bool isFlat( double flatness = VGlobal::flatnessTolerance ) const; + + + /** + * Calculates the point on this segment at parameter 0 <= t <= 1. + * This is a convenience wrapper for pointDerivativesAt(). + */ + KoPoint pointAt( double t ) const; + + /** + * Calculates the point and the derivatives of first and + * second order for 0 <= t <= 1. + */ + void pointDerivativesAt( double t, KoPoint* p = 0L, + KoPoint* d1 = 0L, KoPoint* d2 = 0L ) const; + + + /** + * Calculates the normalized tangent vector (length=1) at the point + * parameterized by 0 <= t <= 1. This is a convenience wrapper + * for pointTangentNormalAt(). Use the latter function directly if you + * need to calculate the point and normal vector or tangent vector + * at once. + */ + KoPoint tangentAt( double t ) const; + + /** + * Calculates the point, the tangent vector and the normal vector for + * 0 <= t <= 1. The tangent vector and the normal vector are + * normalized (length=1). + */ + void pointTangentNormalAt( double t, KoPoint* p = 0L, + KoPoint* tn = 0L, KoPoint* n = 0L ) const; + + + /** + * Calculates the arclength from p0 to the point parametrized + * by 0 <= t <= 1. For beziers this function is a bit expensive. + */ + double length( double t = 1.0 ) const; + + /** + * Calculates the chord length (the distance from the previous + * knot to the current knot). + */ + double chordLength() const; + + /** + * Calculates the length of the control polygon. + */ + double polyLength() const; + + + /** + * Calculates the parameter of a point located at arclength len. + * This is the exact inverse operation of length( t ). + */ + double lengthParam( double len ) const; + + + /** + * Calculates the parameter of the nearest point on this segment + * to the point p. This function is pretty expensive. + */ + double nearestPointParam( const KoPoint& p ) const; + + + /** + * Calculates wether the tangent at the knot is exactly parallel to + * the tangent at p0 of the next segment. Returns false if the + * current segment is a "begin". + */ + bool isSmooth( const VSegment& next ) const; + + bool isSmooth() const + { + return next() + ? isSmooth( *next() ) + : false; + } + + + /** + * Creates a reverted version of this segment. For example: + * if this segment is a line from A to B, the result is a + * line from B to A. + */ + VSegment* revert() const; + + + /** + * Splits the segment at parameter 0 <= t <= 1. Returns a pointer + * to the first segment and modifies the current one to + * be the second segment. + */ + VSegment* splitAt( double t ); + + + /** + * Calculates height of point p above line AB. + */ + static double height( + const KoPoint& a, + const KoPoint& p, + const KoPoint& b ); + + + /** + * Calculates whether lines A0A1 and B0B1 intersect. + */ + static bool linesIntersect( + const KoPoint& a0, + const KoPoint& a1, + const KoPoint& b0, + const KoPoint& b1 ); + + /** + * Returns true, if this segment intersects the other segment. + */ + bool intersects( const VSegment& segment ) const; + + + /** + * Returns a number > 0 if the point p is left, 0 if it's on and + * a number < 0 if it's right of the infinite line through the + * previous segment's knot and the current knot. + */ + double pointIsLeft( const KoPoint& p ) const + { + return + ( knot().x() - prev()->knot().x() ) * + ( p.y() - prev()->knot().y() ) + - + ( p.x() - prev()->knot().x() ) * + ( knot().y() - prev()->knot().y() ); + } + + /** + * Calculates the bounding box. + */ + KoRect boundingBox() const; + + + void draw( VPainter* painter ) const; + + // TODO: remove this backward compatibility function after koffice 1.3.x. + void load( const QDomElement& element ); + + + /** + * Returns a pointer to a copy of this segment. + */ + VSegment* clone() const; + +private: + /** + * Calculates the solutions of y(x) = 0 where 0 <= x <= 1. The + * returned parameters are not ordered. + */ + void rootParams( QValueList<double>& params ) const; + + /** + * Calculates how often the control polygon crosses the x-axis. + */ + int controlPolygonZeros() const; + + + /** + * The segment degree. For (cubic) beziers "three", "one" for lines. + */ + unsigned short m_degree : 6; + + /** + * The segment state. + */ + VState m_state : 2; + + /** + * Node data. + */ + struct VNodeData + { + KoPoint m_vector; + bool m_isSelected; + }; + + /** + * A pointer to an array of node data. + */ + VNodeData* m_nodes; + + + /** + * Pointer to the previous segment. + */ + VSegment* m_prev; + + /** + * Pointer to the next segment. + */ + VSegment* m_next; +}; + +#endif + |