#pragma once #ifndef TELLIPTIC_BRUSH_P_H #define TELLIPTIC_BRUSH_P_H #include "tcurves.h" #include "tstroke.h" #include "tgl.h" //tglPixelSize #include "tstrokeoutline.h" namespace tellipticbrush { //! Tolerance parameter used somewhere throughout this code. const double tolPar = 1e-6; //******************************************************************************** // Geometric Helper Functions //******************************************************************************** double dist(const TPointD &P1, const TPointD &P2); double dist(const TThickPoint &P1, const TThickPoint &P2); double angle(const TPointD &v1, const TPointD &v2); TPointD intersectionCoords(const TPointD &P0, const TPointD &d0, const TPointD &P1, const TPointD &d1, double detTol = 1e-2); void buildEnvelopeDirection(const TThickPoint &p, const TThickPoint &d, bool left, TPointD &res); void buildEnvelopeDirections(const TThickPoint &p, const TThickPoint &d, TPointD &resL, TPointD &resR); void buildEnvelopeVector(const TThickPoint &p, const TThickPoint &d, bool left, TPointD &res); void buildEnvelopeVectors(const TThickPoint &p, const TThickPoint &d, TPointD &resL, TPointD &resR); void buildAngularSubdivision(double radius, double angle, double err, int &nAngles); TRectD computeBBox(const TStroke &stroke); //******************************************************************************** // Options structure //******************************************************************************** /* Structure needed to hold both external and internal outlinization parameters. */ struct OutlinizationData { TOutlineUtil::OutlineParameter m_options; double m_pixSize; OutlinizationData() : m_options(), m_pixSize(0.0) {} OutlinizationData(const TOutlineUtil::OutlineParameter &options) : m_options(options), m_pixSize(sqrt(tglGetPixelSize2())) {} }; //******************************************************************************** // Centerline Point struct //******************************************************************************** /*! CenterlinePoint contains the data a about a discretized centerline stroke point - which includes its position, and eventual forward and backward derivative-like directions. Thickness data is included in the structure. This information is necessary and sufficient to build associated outline points, and eventual additional points related to caps. */ struct CenterlinePoint { int m_chunkIdx; //!< The quadratic chunk index containing this point double m_t; //!< The quadratic parameter where this point can be found TThickPoint m_p; //!< The point's thick coordinates bool m_posBuilt; //!< Whether m_p has been calculated TThickPoint m_prevD; //!< The backward direction bool m_hasPrevD; //!< If the point has (envelopable) backward direction TThickPoint m_nextD; //!< The forward direction bool m_hasNextD; //!< If the point has (envelopable) forward direction bool m_dirsBuilt; //!< Whether directions have been calculated bool m_covered; //!< Whether this point's outline can't be seen int m_countIdx; //!< Additional index needed by some procedural style... CenterlinePoint() : m_chunkIdx(-1), m_posBuilt(false), m_dirsBuilt(false) {} CenterlinePoint(int chunk, double t) : m_chunkIdx(chunk) , m_t(t) , m_posBuilt(false) , m_dirsBuilt(false) , m_countIdx(0) {} ~CenterlinePoint() {} void buildPos(const TStroke &stroke); void buildDirs(const TStroke &stroke); bool operator<(const CenterlinePoint &cp) const { return m_chunkIdx < cp.m_chunkIdx ? true : m_chunkIdx > cp.m_chunkIdx ? false : m_t < cp.m_t; } }; //******************************************************************************** // Linearizator Classes //******************************************************************************** /*! The StrokeLinearizator class models a stroke linearization interface that extracts points of interest from a succession of stroke quadratics. */ class StrokeLinearizator { protected: const TStroke *m_stroke; public: StrokeLinearizator(const TStroke *stroke) : m_stroke(stroke) {} virtual ~StrokeLinearizator() {} /*! Adds interesting stroke points to be discretized in the chunk-th TThickQuadratic stroke. \note The initial point (P0) of the quadratic is always added by the outlinization algorithm before these linearization functions are invoked (whereas P2 belongs to the next quadratic). */ virtual void linearize(std::vector &cPoints, int chunk) = 0; }; //******************************************************************************** // Outline Builder classes //******************************************************************************** /*! The OutlineBuilder class is the object used to translate centerline points into outline points. The purpose of this class is to take a CenterlinePoint instance and build a couple of outline points - at either side of the centerline - eventually adding (cap) points to form a smooth outline. */ class OutlineBuilder { double m_pixSize; TStroke::OutlineOptions m_oOptions; int m_lastChunk; private: typedef void (OutlineBuilder::*OutlineBuilderFunc)( std::vector &outPoints, const CenterlinePoint &cPoint); OutlineBuilderFunc m_addBeginCap; OutlineBuilderFunc m_addEndCap; OutlineBuilderFunc m_addSideCaps; typedef void (OutlineBuilder::*BBoxBuilderFunc)( TRectD &bbox, const CenterlinePoint &cPoint); BBoxBuilderFunc m_addBeginCap_ext; BBoxBuilderFunc m_addEndCap_ext; BBoxBuilderFunc m_addSideCaps_ext; private: /* Type-specific outline container functions. Used with outline building sub-routines that may be used to supply different outline container types. For example, a TRectD may be considered a container class to be used when building the outline bbox. */ template void addEnvelopePoint(T &container, const TPointD &oPoint, int countIdx = 0); template void addExtensionPoint(T &container, const TPointD &oPoint, int countIdx = 0); template void addOutlineBuilderFunc(OutlineBuilder::OutlineBuilderFunc func, T &container, const CenterlinePoint &cPoint); public: OutlineBuilder(const OutlinizationData &data, const TStroke &stroke); ~OutlineBuilder() {} /*! Transforms the specified centerline point into outline points, and adds them to the supplied outline points vector. */ void buildOutlinePoints(std::vector &outPoints, const CenterlinePoint &cPoint); void buildOutlineExtensions(TRectD &bbox, const CenterlinePoint &cPoint); private: void addCircle(std::vector &oPoints, const CenterlinePoint &cPoint); void addCircularArcPoints(int idx, std::vector &outPoints, const TPointD ¢er, const TPointD &ray, double angle, int nAngles, int countIdx); void addRoundBeginCap(std::vector &oPoints, const CenterlinePoint &cPoint); void addRoundEndCap(std::vector &oPoints, const CenterlinePoint &cPoint); void addButtBeginCap(std::vector &oPoints, const CenterlinePoint &cPoint); void addButtEndCap(std::vector &oPoints, const CenterlinePoint &cPoint); template void addProjectingBeginCap(T &oPoints, const CenterlinePoint &cPoint); template void addProjectingEndCap(T &oPoints, const CenterlinePoint &cPoint); void addRoundSideCaps(std::vector &oPoints, const CenterlinePoint &cPoint); void addBevelSideCaps(std::vector &oPoints, const CenterlinePoint &cPoint); template void addMiterSideCaps(T &oPoints, const CenterlinePoint &cPoint); }; //******************************************************************************** // Explicit specializations of OutlineBuilder's methods //******************************************************************************** // Container of Outline Points (for common outline extraction) template <> inline void OutlineBuilder::addEnvelopePoint( std::vector &oPoints, const TPointD &oPoint, int countIdx) { oPoints.push_back(TOutlinePoint(oPoint, countIdx)); } template <> inline void OutlineBuilder::addExtensionPoint( std::vector &oPoints, const TPointD &oPoint, int countIdx) { oPoints.push_back(TOutlinePoint(oPoint, countIdx)); } template <> inline void OutlineBuilder::addOutlineBuilderFunc( OutlineBuilder::OutlineBuilderFunc func, std::vector &oPoints, const CenterlinePoint &cPoint) { (this->*func)(oPoints, cPoint); } //============================================================================================ // Rect (for bounding box extraction) template <> inline void OutlineBuilder::addEnvelopePoint(TRectD &bbox, const TPointD &oPoint, int countIdx) {} template <> inline void OutlineBuilder::addExtensionPoint(TRectD &bbox, const TPointD &oPoint, int countIdx) { bbox.x0 = std::min(bbox.x0, oPoint.x); bbox.y0 = std::min(bbox.y0, oPoint.y); bbox.x1 = std::max(bbox.x1, oPoint.x); bbox.y1 = std::max(bbox.y1, oPoint.y); } template <> inline void OutlineBuilder::addOutlineBuilderFunc( OutlineBuilder::OutlineBuilderFunc func, TRectD &container, const CenterlinePoint &cPoint) {} //******************************************************************************** // Standard Outline Builder (from Centerline Points) //******************************************************************************** void buildOutline(const TStroke &stroke, std::vector &cPoints, TStrokeOutline &outline, const OutlinizationData &data); } // namespace tellipticbrush #endif // TELLIPTIC_BRUSH_P_H