summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFridrich Štrba <fridrich.strba@bluewin.ch>2013-07-11 17:12:32 +0200
committerFridrich Štrba <fridrich.strba@bluewin.ch>2013-07-11 17:12:32 +0200
commit20179ba61a98c1b9896c751d847838383e968d23 (patch)
tree7396489e56c036f474140037fd529d653a60d59f /src
parentdf155ad555c5e4eb9c991d7e08b5a7816e399257 (diff)
Some more code towards handling arrw
Diffstat (limited to 'src')
-rw-r--r--src/lib/CDRContentCollector.cpp38
-rw-r--r--src/lib/CDRPath.cpp325
-rw-r--r--src/lib/CDRPath.h1
3 files changed, 364 insertions, 0 deletions
diff --git a/src/lib/CDRContentCollector.cpp b/src/lib/CDRContentCollector.cpp
index ee82c3a..5dd33e2 100644
--- a/src/lib/CDRContentCollector.cpp
+++ b/src/lib/CDRContentCollector.cpp
@@ -1026,8 +1026,46 @@ void libcdr::CDRContentCollector::_lineProperties(WPXPropertyList &propList)
propList.insert("svg:stroke-width", 0.0);
propList.insert("svg:stroke-color", "#000000");
}
+ }
+ // Deal with line markers (arrows, etc.)
+ if (!m_currentLineStyle.startMarker.empty())
+ {
+ CDRPath startMarker(m_currentLineStyle.startMarker);
+ startMarker.transform(m_currentTransforms);
+ if (!m_groupTransforms.empty())
+ startMarker.transform(m_groupTransforms.top());
+ CDRTransform tmpTrafo(1.0, 0.0, -m_page.offsetX, 0.0, 1.0, -m_page.offsetY);
+ startMarker.transform(tmpTrafo);
+ tmpTrafo = CDRTransform(1.0, 0.0, 0.0, 0.0, -1.0, m_page.height);
+ startMarker.transform(tmpTrafo);
+ WPXString path, viewBox;
+ double width;
+ startMarker.writeOut(path, viewBox, width);
+ propList.insert("draw:marker-start-viewbox", viewBox);
+ propList.insert("draw:marker-start-path", path);
+ propList.insert("draw:marker-start-width", width);
}
+ if (!m_currentLineStyle.endMarker.empty())
+ {
+ CDRPath endMarker(m_currentLineStyle.endMarker);
+ endMarker.transform(m_currentTransforms);
+ if (!m_groupTransforms.empty())
+ endMarker.transform(m_groupTransforms.top());
+ CDRTransform tmpTrafo(1.0, 0.0, -m_page.offsetX, 0.0, 1.0, -m_page.offsetY);
+ endMarker.transform(tmpTrafo);
+ tmpTrafo = CDRTransform(1.0, 0.0, 0.0, 0.0, -1.0, m_page.height);
+ endMarker.transform(tmpTrafo);
+ WPXString path, viewBox;
+ double width;
+ endMarker.writeOut(path, viewBox, width);
+ propList.insert("draw:marker-end-viewbox", viewBox);
+ propList.insert("draw:marker-end-path", path);
+ propList.insert("draw:marker-end-width", width);
+ }
+
+
+
}
void libcdr::CDRContentCollector::_generateBitmapFromPattern(WPXBinaryData &bitmap, const CDRPattern &pattern, const CDRColor &fgColor, const CDRColor &bgColor)
diff --git a/src/lib/CDRPath.cpp b/src/lib/CDRPath.cpp
index c9e86db..6446096 100644
--- a/src/lib/CDRPath.cpp
+++ b/src/lib/CDRPath.cpp
@@ -40,6 +40,206 @@
#define DEBUG_SPLINES 0
#endif
+namespace
+{
+
+static inline double getAngle(double bx, double by)
+{
+ return fmod(2*M_PI + (by > 0.0 ? 1.0 : -1.0) * acos( bx / sqrt(bx * bx + by * by) ), 2*M_PI);
+}
+
+static void getEllipticalArcBBox(double x0, double y0,
+ double rx, double ry, double phi, bool largeArc, bool sweep, double x, double y,
+ double &xmin, double &ymin, double &xmax, double &ymax)
+{
+ phi *= M_PI/180;
+ if (rx < 0.0)
+ rx *= -1.0;
+ if (ry < 0.0)
+ ry *= -1.0;
+
+ if (rx == 0.0 || ry == 0.0)
+ {
+ xmin = (x0 < x ? x0 : x);
+ xmax = (x0 > x ? x0 : x);
+ ymin = (y0 < y ? y0 : y);
+ ymax = (y0 > y ? y0 : y);
+ return;
+ }
+
+ const double x1prime = cos(phi)*(x0 - x)/2 + sin(phi)*(y0 - y)/2;
+ const double y1prime = -sin(phi)*(x0 - x)/2 + cos(phi)*(y0 - y)/2;
+
+ double radicant = (rx*rx*ry*ry - rx*rx*y1prime*y1prime - ry*ry*x1prime*x1prime)/(rx*rx*y1prime*y1prime + ry*ry*x1prime*x1prime);
+ double cxprime = 0.0;
+ double cyprime = 0.0;
+ if (radicant < 0.0)
+ {
+ double ratio = rx/ry;
+ radicant = y1prime*y1prime + x1prime*x1prime/(ratio*ratio);
+ if (radicant < 0.0)
+ {
+ xmin = (x0 < x ? x0 : x);
+ xmax = (x0 > x ? x0 : x);
+ ymin = (y0 < y ? y0 : y);
+ ymax = (y0 > y ? y0 : y);
+ return;
+ }
+ ry=sqrt(radicant);
+ rx=ratio*ry;
+ }
+ else
+ {
+ double factor = (largeArc==sweep ? -1.0 : 1.0)*sqrt(radicant);
+
+ cxprime = factor*rx*y1prime/ry;
+ cyprime = -factor*ry*x1prime/rx;
+ }
+
+ double cx = cxprime*cos(phi) - cyprime*sin(phi) + (x0 + x)/2;
+ double cy = cxprime*sin(phi) + cyprime*cos(phi) + (y0 + y)/2;
+
+ double txmin, txmax, tymin, tymax;
+
+ if (phi == 0 || phi == M_PI)
+ {
+ xmin = cx - rx;
+ txmin = getAngle(-rx, 0);
+ xmax = cx + rx;
+ txmax = getAngle(rx, 0);
+ ymin = cy - ry;
+ tymin = getAngle(0, -ry);
+ ymax = cy + ry;
+ tymax = getAngle(0, ry);
+ }
+ else if (phi == M_PI / 2.0 || phi == 3.0*M_PI/2.0)
+ {
+ xmin = cx - ry;
+ txmin = getAngle(-ry, 0);
+ xmax = cx + ry;
+ txmax = getAngle(ry, 0);
+ ymin = cy - rx;
+ tymin = getAngle(0, -rx);
+ ymax = cy + rx;
+ tymax = getAngle(0, rx);
+ }
+ else
+ {
+ txmin = -atan(ry*tan(phi)/rx);
+ txmax = M_PI - atan (ry*tan(phi)/rx);
+ xmin = cx + rx*cos(txmin)*cos(phi) - ry*sin(txmin)*sin(phi);
+ xmax = cx + rx*cos(txmax)*cos(phi) - ry*sin(txmax)*sin(phi);
+ double tmpY = cy + rx*cos(txmin)*sin(phi) + ry*sin(txmin)*cos(phi);
+ txmin = getAngle(xmin - cx, tmpY - cy);
+ tmpY = cy + rx*cos(txmax)*sin(phi) + ry*sin(txmax)*cos(phi);
+ txmax = getAngle(xmax - cx, tmpY - cy);
+
+ tymin = atan(ry/(tan(phi)*rx));
+ tymax = atan(ry/(tan(phi)*rx))+M_PI;
+ ymin = cy + rx*cos(tymin)*sin(phi) + ry*sin(tymin)*cos(phi);
+ ymax = cy + rx*cos(tymax)*sin(phi) + ry*sin(tymax)*cos(phi);
+ double tmpX = cx + rx*cos(tymin)*cos(phi) - ry*sin(tymin)*sin(phi);
+ tymin = getAngle(tmpX - cx, ymin - cy);
+ tmpX = cx + rx*cos(tymax)*cos(phi) - ry*sin(tymax)*sin(phi);
+ tymax = getAngle(tmpX - cx, ymax - cy);
+ }
+ if (xmin > xmax)
+ {
+ std::swap(xmin,xmax);
+ std::swap(txmin,txmax);
+ }
+ if (ymin > ymax)
+ {
+ std::swap(ymin,ymax);
+ std::swap(tymin,tymax);
+ }
+ double angle1 = getAngle(x0 - cx, y0 - cy);
+ double angle2 = getAngle(x - cx, y - cy);
+
+ if (!sweep)
+ std::swap(angle1, angle2);
+
+ bool otherArc = false;
+ if (angle1 > angle2)
+ {
+ std::swap(angle1, angle2);
+ otherArc = true;
+ }
+
+ if ((!otherArc && (angle1 > txmin || angle2 < txmin)) || (otherArc && !(angle1 > txmin || angle2 < txmin)))
+ xmin = x0 < x ? x0 : x;
+ if ((!otherArc && (angle1 > txmax || angle2 < txmax)) || (otherArc && !(angle1 > txmax || angle2 < txmax)))
+ xmax = x0 > x ? x0 : x;
+ if ((!otherArc && (angle1 > tymin || angle2 < tymin)) || (otherArc && !(angle1 > tymin || angle2 < tymin)))
+ ymin = y0 < y ? y0 : y;
+ if ((!otherArc && (angle1 > tymax || angle2 < tymax)) || (otherArc && !(angle1 > tymax || angle2 < tymax)))
+ ymax = y0 > y ? y0 : y;
+}
+
+static inline double quadraticExtreme(double t, double a, double b, double c)
+{
+ return (1.0-t)*(1.0-t)*a + 2.0*(1.0-t)*t*b + t*t*c;
+}
+
+static inline double quadraticDerivative(double a, double b, double c)
+{
+ double denominator = a - 2.0*b + c;
+ if (fabs(denominator) != 0.0)
+ return (a - b)/denominator;
+ return -1.0;
+}
+
+static void getQuadraticBezierBBox(double x0, double y0, double x1, double y1, double x, double y,
+ double &xmin, double &ymin, double &xmax, double &ymax)
+{
+ xmin = x0 < x ? x0 : x;
+ xmax = x0 > x ? x0 : x;
+ ymin = y0 < y ? y0 : y;
+ ymax = y0 > y ? y0 : y;
+
+ double t = quadraticDerivative(x0, x1, x);
+ if(t>=0 && t<=1)
+ {
+ double tmpx = quadraticExtreme(t, x0, x1, x);
+ xmin = tmpx < xmin ? tmpx : xmin;
+ xmax = tmpx > xmax ? tmpx : xmax;
+ }
+
+ t = quadraticDerivative(y0, y1, y);
+ if(t>=0 && t<=1)
+ {
+ double tmpy = quadraticExtreme(t, y0, y1, y);
+ ymin = tmpy < ymin ? tmpy : ymin;
+ ymax = tmpy > ymax ? tmpy : ymax;
+ }
+}
+
+static inline double cubicBase(double t, double a, double b, double c, double d)
+{
+ return (1.0-t)*(1.0-t)*(1.0-t)*a + 3.0*(1.0-t)*(1.0-t)*t*b + 3.0*(1.0-t)*t*t*c + t*t*t*d;
+}
+
+static void getCubicBezierBBox(double x0, double y0, double x1, double y1, double x2, double y2, double x, double y,
+ double &xmin, double &ymin, double &xmax, double &ymax)
+{
+ xmin = x0 < x ? x0 : x;
+ xmax = x0 > x ? x0 : x;
+ ymin = y0 < y ? y0 : y;
+ ymax = y0 > y ? y0 : y;
+
+ for (double t = 0.0; t <= 1.0; t+=0.01)
+ {
+ double tmpx = cubicBase(t, x0, x1, x2, x);
+ xmin = tmpx < xmin ? tmpx : xmin;
+ xmax = tmpx > xmax ? tmpx : xmax;
+ double tmpy = cubicBase(t, y0, y1, y2, y);
+ ymin = tmpy < ymin ? tmpy : ymin;
+ ymax = tmpy > ymax ? tmpy : ymax;
+ }
+}
+
+} // anonymous namespace
+
namespace libcdr
{
@@ -500,6 +700,131 @@ void libcdr::CDRPath::writeOut(WPXPropertyListVector &vec) const
(*iter)->writeOut(vec);
}
+void libcdr::CDRPath::writeOut(WPXString &path, WPXString &viewBox, double &width) const
+{
+ WPXPropertyListVector vec;
+ writeOut(vec);
+ if(vec.count() == 0)
+ return;
+ // This must be a mistake and we do not want to crash lower
+ if(vec[0]["libwpg:path-action"]->getStr() == "Z")
+ return;
+
+ // try to find the bounding box
+ bool isFirstPoint = true;
+
+ double px = 0.0, py = 0.0, qx = 0.0, qy = 0.0;
+ double lastX = 0.0;
+ double lastY = 0.0;
+
+ for(unsigned k = 0; k < vec.count(); ++k)
+ {
+ if (!vec[k]["svg:x"] || !vec[k]["svg:y"])
+ continue;
+ if (isFirstPoint)
+ {
+ px = vec[k]["svg:x"]->getDouble();
+ py = vec[k]["svg:y"]->getDouble();
+ qx = px;
+ qy = py;
+ lastX = px;
+ lastY = py;
+ isFirstPoint = false;
+ }
+ px = (px > vec[k]["svg:x"]->getDouble()) ? vec[k]["svg:x"]->getDouble() : px;
+ py = (py > vec[k]["svg:y"]->getDouble()) ? vec[k]["svg:y"]->getDouble() : py;
+ qx = (qx < vec[k]["svg:x"]->getDouble()) ? vec[k]["svg:x"]->getDouble() : qx;
+ qy = (qy < vec[k]["svg:y"]->getDouble()) ? vec[k]["svg:y"]->getDouble() : qy;
+
+ double xmin, xmax, ymin, ymax;
+
+ if(vec[k]["libwpg:path-action"]->getStr() == "C")
+ {
+ getCubicBezierBBox(lastX, lastY, vec[k]["svg:x1"]->getDouble(), vec[k]["svg:y1"]->getDouble(),
+ vec[k]["svg:x2"]->getDouble(), vec[k]["svg:y2"]->getDouble(),
+ vec[k]["svg:x"]->getDouble(), vec[k]["svg:y"]->getDouble(), xmin, ymin, xmax, ymax);
+
+ px = (px > xmin ? xmin : px);
+ py = (py > ymin ? ymin : py);
+ qx = (qx < xmax ? xmax : qx);
+ qy = (qy < ymax ? ymax : qy);
+ }
+ if(vec[k]["libwpg:path-action"]->getStr() == "Q")
+ {
+ getQuadraticBezierBBox(lastX, lastY, vec[k]["svg:x1"]->getDouble(), vec[k]["svg:y1"]->getDouble(),
+ vec[k]["svg:x"]->getDouble(), vec[k]["svg:y"]->getDouble(), xmin, ymin, xmax, ymax);
+
+ px = (px > xmin ? xmin : px);
+ py = (py > ymin ? ymin : py);
+ qx = (qx < xmax ? xmax : qx);
+ qy = (qy < ymax ? ymax : qy);
+ }
+ if(vec[k]["libwpg:path-action"]->getStr() == "A")
+ {
+ getEllipticalArcBBox(lastX, lastY, vec[k]["svg:rx"]->getDouble(), vec[k]["svg:ry"]->getDouble(),
+ vec[k]["libwpg:rotate"] ? vec[k]["libwpg:rotate"]->getDouble() : 0.0,
+ vec[k]["libwpg:large-arc"] ? vec[k]["libwpg:large-arc"]->getInt() : 1,
+ vec[k]["libwpg:sweep"] ? vec[k]["libwpg:sweep"]->getInt() : 1,
+ vec[k]["svg:x"]->getDouble(), vec[k]["svg:y"]->getDouble(), xmin, ymin, xmax, ymax);
+
+ px = (px > xmin ? xmin : px);
+ py = (py > ymin ? ymin : py);
+ qx = (qx < xmax ? xmax : qx);
+ qy = (qy < ymax ? ymax : qy);
+ }
+ lastX = vec[k]["svg:x"]->getDouble();
+ lastY = vec[k]["svg:y"]->getDouble();
+ }
+
+
+ width = qx - px;
+ viewBox.sprintf("%i %i %i %i", 0, 0, (unsigned)(2540*(qx - px)), (unsigned)(2540*(qy - py)));
+
+ for(unsigned i = 0; i < vec.count(); ++i)
+ {
+ WPXString sElement;
+ if (vec[i]["libwpg:path-action"]->getStr() == "M")
+ {
+ // 2540 is 2.54*1000, 2.54 in = 1 inch
+ sElement.sprintf("M%i %i", (unsigned)((vec[i]["svg:x"]->getDouble()-px)*2540),
+ (unsigned)((vec[i]["svg:y"]->getDouble()-py)*2540));
+ path.append(sElement);
+ }
+ else if (vec[i]["libwpg:path-action"]->getStr() == "L")
+ {
+ sElement.sprintf("L%i %i", (unsigned)((vec[i]["svg:x"]->getDouble()-px)*2540),
+ (unsigned)((vec[i]["svg:y"]->getDouble()-py)*2540));
+ path.append(sElement);
+ }
+ else if (vec[i]["libwpg:path-action"]->getStr() == "C")
+ {
+ sElement.sprintf("C%i %i %i %i %i %i", (unsigned)((vec[i]["svg:x1"]->getDouble()-px)*2540),
+ (unsigned)((vec[i]["svg:y1"]->getDouble()-py)*2540), (unsigned)((vec[i]["svg:x2"]->getDouble()-px)*2540),
+ (unsigned)((vec[i]["svg:y2"]->getDouble()-py)*2540), (unsigned)((vec[i]["svg:x"]->getDouble()-px)*2540),
+ (unsigned)((vec[i]["svg:y"]->getDouble()-py)*2540));
+ path.append(sElement);
+ }
+ else if (vec[i]["libwpg:path-action"]->getStr() == "Q")
+ {
+ sElement.sprintf("Q%i %i %i %i", (unsigned)((vec[i]["svg:x1"]->getDouble()-px)*2540),
+ (unsigned)((vec[i]["svg:y1"]->getDouble()-py)*2540), (unsigned)((vec[i]["svg:x"]->getDouble()-px)*2540),
+ (unsigned)((vec[i]["svg:y"]->getDouble()-py)*2540));
+ path.append(sElement);
+ }
+ else if (vec[i]["libwpg:path-action"]->getStr() == "A")
+ {
+ sElement.sprintf("A%i %i %i %i %i %i %i", (unsigned)((vec[i]["svg:rx"]->getDouble())*2540),
+ (unsigned)((vec[i]["svg:ry"]->getDouble())*2540), (vec[i]["libwpg:rotate"] ? vec[i]["libwpg:rotate"]->getInt() : 0),
+ (vec[i]["libwpg:large-arc"] ? vec[i]["libwpg:large-arc"]->getInt() : 1),
+ (vec[i]["libwpg:sweep"] ? vec[i]["libwpg:sweep"]->getInt() : 1),
+ (unsigned)((vec[i]["svg:x"]->getDouble()-px)*2540), (unsigned)((vec[i]["svg:y"]->getDouble()-py)*2540));
+ path.append(sElement);
+ }
+ else if (vec[i]["libwpg:path-action"]->getStr() == "Z")
+ path.append(" Z");
+ }
+}
+
void libcdr::CDRPath::transform(const CDRTransforms &trafos)
{
for (std::vector<CDRPathElement *>::iterator iter = m_elements.begin(); iter != m_elements.end(); ++iter)
diff --git a/src/lib/CDRPath.h b/src/lib/CDRPath.h
index ccff6d2..5faa4a5 100644
--- a/src/lib/CDRPath.h
+++ b/src/lib/CDRPath.h
@@ -70,6 +70,7 @@ public:
void appendPath(const CDRPath &path);
void writeOut(WPXPropertyListVector &vec) const;
+ void writeOut(WPXString &path, WPXString &viewBox, double &width) const;
void transform(const CDRTransforms &trafos);
void transform(const CDRTransform &trafo);
CDRPathElement *clone();