457 lines
16 KiB
C++
457 lines
16 KiB
C++
|
/*
|
||
|
* 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
|