/* * Portable Agile C++ Classes (PACC) * Copyright (C) 2001-2003 by Marc Parizeau * http://manitou.gel.ulaval.ca/~parizeau/PACC * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact: * Laboratoire de Vision et Systemes Numeriques * Departement de genie electrique et de genie informatique * Universite Laval, Quebec, Canada, G1K 7P4 * http://vision.gel.ulaval.ca * */ /*! * \file PACC/SVG/Primitives.hpp * \brief Class definitions for the SVG graphic primitives. * \author Marc Parizeau and Michel Fortin, Laboratoire de vision et systèmes numériques, Université Laval * $Revision: 1.5.2.1 $ * $Date: 2007/09/10 18:24:08 $ */ #ifndef PACC_SVG_Graphic_hpp_ #define PACC_SVG_Graphic_hpp_ #include "XML/Node.hpp" #include "XML/Streamer.hpp" #include "SVG/Styles.hpp" #include "SVG/Transforms.hpp" namespace PACC { namespace SVG { using namespace std; /*!\brief Base class for graphic elements. * \ingroup SVG * * This class provide no more functionality than it's base class. It is * intended to be able to distinguish graphics element from others. That way * we can restrict at compile time what kind of elements can be inserted in * a Group for example. * * This class must be subclassed to be useful. You may note that the only * constructor is protected to enforce that. */ class Primitive : protected XML::Node { public: /*!\brief Add some style attributes to element. * \param inStyle A style attribute list to add to this element. * * If the same style attribute with the same name is already present, it * will be replaced by the new value. */ void addStyle(const Style& inStyle) {*this += inStyle;} //! Remove any coordinate transformation applyed to this element. void clearTransform(void) {removeAttribute("transform");} //! Set id of primitive. void setID(const string& inID) {setAttribute("id", inID);} /*!\brief Set the coordinate transformation to apply. * \param inTransform A transformation to apply to this element. * * The current transformation, if any, will be replaced by the new one. * * \see transformcomp */ void setTransform(const Transform& inTransform) {setAttribute("transform", inTransform);} //! Write serialized primitive into stream \c outStream. void write(ostream& outStream) const { XML::Streamer lStream(outStream); serialize(lStream); } protected: /*!\brief Constructor for a graphic element. * \param inName A tag name for the element. * \param inAttrList A list of attributes to give to this element. */ Primitive(const string &inName, const XML::AttributeList &inAttrList = XML::AttributeList()) : XML::Node(inName, inAttrList) {} friend class Group; //!< Allowing the use of Element's << operator. }; /*!\brief Graphic primitive for rectangles. * \ingroup SVG * * A rectangle is a four-sided figure with two vertical sides and two * horizontal ones. */ class Rectangle : public Primitive { public: //! Make rectangle with origin \c inOrigin, size \c inSize, and style \c inStyle. Rectangle(const Point &inOrigin, const Size &inSize, const Style &inStyle = Style()) : Primitive("rect", inStyle) { setAttribute("x", String::convert(inOrigin.x)); setAttribute("y", String::convert(inOrigin.y)); setAttribute("width", String::convert(inSize.width)); setAttribute("height", String::convert(inSize.height)); } //! Return rectangle origin. Point getOrigin(void) const { return Point(String::convertToFloat(getAttribute("x")), String::convertToFloat(getAttribute("y"))); } //! Set rectangle origin to point \c inPoint. void setOrigin(const Point &inOrigin) { setAttribute("x", String::convert(inOrigin.x)); setAttribute("y", String::convert(inOrigin.y)); } //! Set rectangle origin to coordinates \c inX and \c inY. void setOrigin(float inX, float inY) { setAttribute("x", String::convert(inX)); setAttribute("y", String::convert(inY)); } //! Return rectangle size. Size getSize(void) const { return Size(String::convertToFloat(getAttribute("width")), String::convertToFloat(getAttribute("height"))); } //! Set rectangle size to \c inSize. void setSize(const Size &inSize) { setAttribute("width", String::convert(inSize.width)); setAttribute("height", String::convert(inSize.height)); } //! Set rectangle size to width \c inWidth and height \c inHeight. void setSize(float inWidth, float inHeight) { setAttribute("width", String::convert(inWidth)); setAttribute("height", String::convert(inHeight)); } }; /*!\brief Graphic primitive for circles. * \ingroup SVG * * A circle is defined by a central point (called the center) and a radius. * The shape is formed of the closed curve where the distance between the * center and each point of the curve is equal to the radius. */ class Circle : public Primitive { public: //! make circle centered at point \c inPoint, with radius \c inRadius, and style \c inStyle. Circle(const Point &inCenter, float inRadius, const Style &inStyle = Style()) : Primitive("circle", inStyle) { setAttribute("cx", String::convert(inCenter.x)); setAttribute("cy", String::convert(inCenter.y)); setAttribute("r", String::convert(inRadius)); } //! Return circle center. Point getCenter(void) const{ return Point(String::convertToFloat(getAttribute("cx")), String::convertToFloat(getAttribute("cy"))); } //! Set circle center to point \c inCenter. void setCenter(const Point &inCenter) { setAttribute("cx", String::convert(inCenter.x)); setAttribute("cy", String::convert(inCenter.y)); } //! Set circle center to coordinates \c inCX and \c inCY. void setCenter(float inCX, float inCY) { setAttribute("cx", String::convert(inCX)); setAttribute("cy", String::convert(inCY)); } //! Retur circle radius. float getRadius(void) const { return String::convertToFloat(getAttribute("r")); } //! Set circle radius to \c inRadius. void setRadius(float inRadius) { setAttribute("r", String::convert(inRadius)); } }; /*!\brief Graphic primitive for ellipses. * \ingroup SVG * * The ellipse is defined by a central point (the center) and two radius * values: one for the x axis, the other for the y axis. */ class Ellipse : public Primitive { public: //! Make ellipse centered at point \c inCenter, with radii \c inXRadius and \c inYRadius, and style \c inStyle. Ellipse(const Point &inCenter, float inXRadius, float inYRadius, const Style &inStyle = Style()) : SVG::Primitive("ellipse", inStyle) { setAttribute("cx", String::convert(inCenter.x)); setAttribute("cy", String::convert(inCenter.y)); setAttribute("rx", String::convert(inXRadius)); setAttribute("ry", String::convert(inYRadius)); } //! return ellipse center. Point getCenter() const { return Point(String::convertToFloat(getAttribute("cx")), String::convertToFloat(getAttribute("cy"))); } //! Set ellipse center to point \c inPoint. void setCenter(const Point &inCenter) { setAttribute("cx", String::convert(inCenter.x)); setAttribute("cy", String::convert(inCenter.y)); } //! Set ellipse center to coordinates \c inCX and \c inCY. void setCenter(float inCX, float inCY) { setAttribute("cx", String::convert(inCX)); setAttribute("cy", String::convert(inCY)); } //! Return ellipse first radius. float getXRadius() const { return String::convertToFloat(getAttribute("rx")); } //! Set ellipse first radius to \c inXRadius. void setXRadius(float inXRadius) { setAttribute("rx", String::convert(inXRadius)); } //! Return ellipse second radius. float getYRadius(void) const { return String::convertToFloat(getAttribute("ry")); } //! Set ellipse second radius to \c inYRadius. void setYRadius(float inYRadius) { setAttribute("ry", String::convert(inYRadius)); } }; /*!\brief Graphic primitive for straight lines. * \ingroup SVG * * A line link a start point to an end point. Since a line has no fillable * region and by default shapes do not have a stroke, you must explicitly * define a stroke if you want the line to be visible. * * \see Stroke */ class Line : public Primitive { public: //! Make line segment from start point \c inStart to end point \c inEnd, using style \c inStyle. Line(const Point &inStart, const Point &inEnd, const Style &inStyle = Style()) : SVG::Primitive("line", inStyle) { setAttribute("x1", String::convert(inStart.x)); setAttribute("y1", String::convert(inStart.y)); setAttribute("x2", String::convert(inEnd.x)); setAttribute("y2", String::convert(inEnd.y)); } //! Return start point of line segment. Point getStart(void) const { return Point(String::convertToFloat(getAttribute("x1")), String::convertToFloat(getAttribute("y1"))); } //! Set start point of line segment to \c inStart. void setStart(const Point &inStart) { setAttribute("x1", String::convert(inStart.x)); setAttribute("y1", String::convert(inStart.y)); } //! Set start point of line segment to coordinates \c inX and \c inY. void setStart(float inX, float inY) { setAttribute("x1", String::convert(inX)); setAttribute("y1", String::convert(inY)); } //! Return end point of line segment. Point getEnd(void) const { return Point(String::convertToFloat(getAttribute("x2")), String::convertToFloat(getAttribute("y2"))); } //! Set end point of line segment to \c inEnd. void setEnd(const Point &inEnd) { setAttribute("x2", String::convert(inEnd.x)); setAttribute("y2", String::convert(inEnd.y)); } //! set end point of line segment to coordinates \c inX and \c inY. void setEnd(float inX, float inY) { setAttribute("x2", String::convert(inX)); setAttribute("y2", String::convert(inY)); } }; /*!\brief Graphic primitive for polygons * \ingroup SVG * * A polygon is made of a serie of points linked together with strait lines. * A polygon is a closed path, so the last point is always linked with the * first one. * * \see Polyline */ class Polygon : public Primitive { public: //! Make an empty polygon with style \c inStyle. Polygon(const Style &inStyle = Style()) : Primitive("polygon", inStyle) {} /*!\brief Make a polygon from point list \c inPointList and style \c inStyle. * * This constructor gives a polygon with predefined points. You can * always add more points witht the += operator. */ Polygon(const PointList &inLinePath, const Style &inStyle = Style()) : Primitive("polygon", inStyle) { setAttribute("points", inLinePath.getStringValue()); } //! Make new polygon from this polygon concatenated with point list \c inLinePath. Polygon operator+(const PointList &inLinePath) const { return Polygon(*this) += inLinePath; } //! Append point list \c inLinePath to this polygon. Polygon &operator+=(const PointList &inLinePath) { (*this)["points"] += inLinePath.getStringValue(); return *this; } //! Make new polygon from this polygon concatenated with point \c inPoint. Polygon operator+(const Point &inPoint) const { return Polygon(*this) += inPoint; } //! Append point \c inPoint to this polygon. Polygon &operator+=(const Point &inPoint) { (*this)["points"] += string(" ") + inPoint.getStringValue(); return *this; } }; /*!\brief Graphic primitive for polyline * \ingroup SVG * * A polyline is made of a serie of points linked together with strait * lines. Polyline is not closed: so the last point is not linked with the * first one. * * \see Polygon */ class Polyline : public Primitive { public: //! Make an empty polyline with style \c inStyle. Polyline(const Style &inStyle = Style()) : Primitive("polyline", inStyle) {} //! Make a polyline from point list \c inLinePath using style \c inStyle. Polyline(const PointList &inLinePath, const Style &inStyle = Style()) : Primitive("polyline", inStyle) { setAttribute("points", inLinePath.getStringValue()); } //! Make new polyline from this polyline concatenated with point list \c inLinePath. Polyline operator+(const PointList &inLinePath) const { return Polyline(*this) += inLinePath; } //! Append point list \c inLinePath to this polyline. Polyline &operator+=(const PointList &inLinePath) { (*this)["points"] += inLinePath.getStringValue(); return *this; } //! Make new polyline from this polyline concatenated with point \c inPoint. Polyline operator+(const Point &inPoint) const { return Polyline(*this) += inPoint; } //! Append point \c inPoint to this polyline. Polyline &operator+=(const Point &inPoint) { (*this)["points"] += string(" ") + inPoint.getStringValue(); return *this; } }; /*!\brief Graphic primitive for text. * \ingroup SVG * * A text object is used to display text in a graphic. Each character of the * enclosed text is represented by a glyph on with standard stroke and fill * attributes apply. For example you can put a stroke on the text to make * an outline, and you can change the color of the character using * Fill::Color. * * There is also some special attributes that can be applyed to text to * control the appearence of the glyphs, like the font family, size, and * style. See Font for details. * * The text is placed on screen around an anchor point. How text is aligned * on the anchor depends of the TextAnchor and TextBaseline attributes. */ class Text : public Primitive { public: // Make text from string \c inString, typeset at point \c inAnchor, using style \c inStyle. Text(const string &inString, const Point &inAnchor, const Style inStyle = Style()) : Primitive("text", inStyle) { setAttribute("x", String::convert(inAnchor.x)); setAttribute("y", String::convert(-inAnchor.y)); setTransform(Scale(1, -1)); insertAsLastChild(new Node(inString, XML::eString)); } //! Return text anchor point. Point getAnchor(void) const { return Point(String::convertToFloat(getAttribute("x")), String::convertToFloat(getAttribute("y"))); } //! Set text anchor point to \c inAnchor. void setAnchor(const Point &inAnchor) { setAttribute("x", String::convert(inAnchor.x)); setAttribute("y", String::convert(inAnchor.y)); } //! Set text anchor point to coordinates \c inX and \c inY. void setAnchor(float inX, float inY) { setAttribute("x", String::convert(inX)); setAttribute("y", String::convert(inY)); } //! Return string of text. string getText(void) const { return getFirstChild()->getValue(); } //! Set text to string \c inString. void setText(const string &inString) { getFirstChild()->setValue(inString); } }; } // end of SVG namespace //! Insert primitive \c inPrimitive into output stream \c outStream. inline ostream& operator<<(ostream &outStream, const SVG::Primitive& inPrimitive) { inPrimitive.write(outStream); return outStream; } } // end of PACC namespace #endif