r18833 by fschmid - ODG-Importer: massive improvements to custom shapes, all shapes work now, still need to fix colors.
scribus-commit
scribus-commit at lists.scribus.net
Sun Feb 23 19:33:01 UTC 2014
Author: fschmid
Date: Sun Feb 23 19:33:01 2014
New Revision: 18833
URL: http://scribus.net/websvn/listing.php?repname=Scribus&sc=1&rev=18833
Log:
ODG-Importer: massive improvements to custom shapes, all shapes work now, still need to fix colors.
Modified:
trunk/Scribus/scribus/plugins/import/odg/importodg.cpp
trunk/Scribus/scribus/plugins/import/odg/importodg.h
Modified: trunk/Scribus/scribus/plugins/import/odg/importodg.cpp
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=18833&path=/trunk/Scribus/scribus/plugins/import/odg/importodg.cpp
==============================================================================
--- trunk/Scribus/scribus/plugins/import/odg/importodg.cpp (original)
+++ trunk/Scribus/scribus/plugins/import/odg/importodg.cpp Sun Feb 23 19:33:01 2014
@@ -635,9 +635,10 @@
FunctionParser fpa;
double vx = 0;
double vy = 0;
- double vw = 1;
- double vh = 1;
- parseViewBox(p, &vx, &vy, &vw, &vh);
+ double vw = 21600;
+ double vh = 21600;
+ if (p.hasAttribute("svg:viewBox"))
+ parseViewBox(p, &vx, &vy, &vw, &vh);
fpa.AddConstant("top", vy);
fpa.AddConstant("bottom", vh);
fpa.AddConstant("left", vx);
@@ -666,6 +667,7 @@
}
if (p.hasChildNodes())
{
+ QMap<QString, QString> formulaMap;
for(QDomElement f = p.firstChildElement(); !f.isNull(); f = f.nextSiblingElement())
{
if (f.tagName() == "draw:equation")
@@ -674,13 +676,43 @@
QString formula = f.attribute("draw:formula", "0");
formula.replace("$", "Const_");
formula.replace("?", "Func_");
- double erg = 0;
- int ret = fpa.Parse(formula.toStdString(), "", false);
- if(ret < 0)
- erg = fpa.Eval(NULL);
- func_Results.insert("?" + formName, QString("%1").arg(erg));
- formName.prepend("Func_");
- fpa.AddConstant(formName.toStdString(), erg);
+ formula.replace("if(", "if(0<");
+ formulaMap.insert(formName, formula);
+ }
+ }
+ if (!formulaMap.isEmpty())
+ {
+ int maxTry = formulaMap.count() + 1;
+ int actTry = 0;
+ bool allResOK = false;
+ while (!allResOK)
+ {
+ allResOK = true;
+ QMap<QString, QString>::iterator itf = formulaMap.begin();
+ while (itf != formulaMap.end())
+ {
+ double erg = 0;
+ int ret = fpa.Parse(itf.value().toStdString(), "", false);
+ if(ret < 0)
+ {
+ QString formNam = itf.key();
+ erg = fpa.Eval(NULL);
+ func_Results.insert("?" + formNam + " ", QString("%1 ").arg(erg));
+ formNam.prepend("Func_");
+ fpa.AddConstant(formNam.toStdString(), erg);
+ itf = formulaMap.erase(itf);
+ }
+ else
+ {
+ ++itf;
+ allResOK = false;
+ }
+ }
+ actTry++;
+ if (actTry > maxTry)
+ break;
+ if (formulaMap.isEmpty())
+ break;
}
}
}
@@ -769,7 +801,18 @@
m_Doc->groupObjectsToItem(retObj, GElements);
retObj->OwnPage = m_Doc->OnPage(retObj);
m_Doc->GroupOnPage(retObj);
+ if (p.hasAttribute("draw:mirror-horizontal") && (p.attribute("draw:mirror-horizontal") == "true"))
+ retObj->flipImageH();
+ if (p.hasAttribute("draw:mirror-vertical") && (p.attribute("draw:mirror-vertical") == "true"))
+ retObj->flipImageV();
m_Doc->Items->removeLast();
+ }
+ else
+ {
+ if (p.hasAttribute("draw:mirror-horizontal") && (p.attribute("draw:mirror-horizontal") == "true"))
+ m_Doc->MirrorPolyH(retObj);
+ if (p.hasAttribute("draw:mirror-vertical") && (p.attribute("draw:mirror-vertical") == "true"))
+ m_Doc->MirrorPolyV(retObj);
}
}
}
@@ -2425,17 +2468,19 @@
stroke = true;
if( !d.isEmpty() )
{
+ bool xDir = true;
+ bool yDir = false;
+ double rad2deg = 180.0/M_PI;
QPainterPath pPath;
d = d.simplified();
QByteArray pathData = d.toLatin1();
const char *ptr = pathData.constData();
const char *end = pathData.constData() + pathData.length() + 1;
- double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
+ double tox, toy, x1, y1, x2, y2;
double px1, py1, px2, py2, px3, py3;
int moveCount = 0;
result.svgInit();
char command = *(ptr++), lastCommand = ' ';
- subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
while( ptr < end )
{
if( *ptr == ' ' )
@@ -2444,6 +2489,8 @@
{
case 'A':
case 'B':
+ case 'V':
+ case 'W':
{
ptr = getCoord( ptr, tox );
ptr = getCoord( ptr, toy );
@@ -2453,11 +2500,43 @@
ptr = getCoord( ptr, py2 );
ptr = getCoord( ptr, px3 );
ptr = getCoord( ptr, py3 );
- double startA = QLineF(QPointF((px1 + tox) / 2.0, (py1 + toy) / 2.0), QPointF(px2, py2)).angle();
- double endA = QLineF(QPointF((px1 + tox) / 2.0, (py1 + toy) / 2.0), QPointF(px3, py3)).angle();
- if (command == 'B')
- pPath.moveTo(px2, py2);
- pPath.arcTo(QRectF(QPointF(tox, toy), QPointF(px1, py1)), startA, endA - startA);
+ bool lineTo = ((command == 'A') || (command == 'W'));
+ bool clockwise = ((command == 'W') || (command == 'V'));
+ QRectF bbox = QRectF(QPointF(tox, toy), QPointF(px1, py1)).normalized();
+ QPointF center = bbox.center();
+ double rx = 0.5 * bbox.width();
+ double ry = 0.5 * bbox.height();
+ if (rx == 0)
+ rx = 1;
+ if (ry == 0)
+ ry = 1;
+ QPointF startRadialVector = QPointF(px2, py2) - center;
+ QPointF endRadialVector = QPointF(px3, py3) - center;
+ // convert from ellipse space to unit-circle space
+ double x0 = startRadialVector.x() / rx;
+ double y0 = startRadialVector.y() / ry;
+
+ double x1 = endRadialVector.x() / rx;
+ double y1 = endRadialVector.y() / ry;
+
+ double startAngle = angleFromPoint(QPointF(x0,y0));
+ double stopAngle = angleFromPoint(QPointF(x1,y1));
+
+ // we are moving counter-clockwise to the end angle
+ double sweepAngle = radSweepAngle(startAngle, stopAngle, clockwise);
+ // compute the starting point to draw the line to
+ // as the point x3 y3 is not on the ellipse, spec says the point define radial vector
+ QPointF startPoint(rx * cos(startAngle), ry * sin(2*M_PI - startAngle));
+
+ // if A or W is first command in enhanced path
+ // move to the starting point
+ bool isFirstCommandInPath = (pPath.elementCount() == 0);
+ bool isFirstCommandInSubpath = lastCommand == 'Z';
+ if (lineTo && !isFirstCommandInPath && !isFirstCommandInSubpath)
+ pPath.lineTo(center + startPoint);
+ else
+ pPath.moveTo(center + startPoint);
+ arcTo(pPath, pPath.currentPosition(), rx, ry, startAngle * rad2deg, sweepAngle * rad2deg);
break;
}
case 'C':
@@ -2468,12 +2547,7 @@
ptr = getCoord( ptr, y2 );
ptr = getCoord( ptr, tox );
ptr = getCoord( ptr, toy );
- result.svgCurveToCubic(x1, y1, x2, y2, tox, toy);
pPath.cubicTo(x1, y1, x2, y2, tox, toy);
- contrlx = x2;
- contrly = y2;
- curx = tox;
- cury = toy;
break;
}
case 'F':
@@ -2485,9 +2559,6 @@
{
ptr = getCoord( ptr, tox );
ptr = getCoord( ptr, toy );
- curx = tox;
- cury = toy;
- result.svgLineTo( curx, cury );
pPath.lineTo(tox, toy);
break;
}
@@ -2495,9 +2566,6 @@
{
ptr = getCoord( ptr, tox );
ptr = getCoord( ptr, toy );
- subpathx = curx = tox;
- subpathy = cury = toy;
- result.svgMoveTo(curx, cury );
pPath.moveTo(tox, toy);
moveCount++;
break;
@@ -2508,18 +2576,7 @@
ptr = getCoord( ptr, y1 );
ptr = getCoord( ptr, tox );
ptr = getCoord( ptr, toy );
- px1 = (curx + 2 * x1) * (1.0 / 3.0);
- py1 = (cury + 2 * y1) * (1.0 / 3.0);
- px2 = (tox + 2 * x1) * (1.0 / 3.0);
- py2 = (toy + 2 * y1) * (1.0 / 3.0);
- px3 = tox;
- py3 = toy;
- result.svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
pPath.quadTo(x1, y1, tox, toy);
- contrlx = (tox + 2 * x1) * (1.0 / 3.0);
- contrly = (toy + 2 * y1) * (1.0 / 3.0);
- curx = tox;
- cury = toy;
break;
}
case 'S':
@@ -2536,42 +2593,44 @@
ptr = getCoord(ptr, py2);
ptr = getCoord(ptr, tox);
ptr = getCoord(ptr, toy);
- if (command == 'U')
- pPath.arcMoveTo(px1 - px2, py1 - py2, px2 * 2, py2 * 2, tox);
- pPath.arcTo(px1 - px2, py1 - py2, px2 * 2, py2 * 2, tox, toy - tox);
+ bool lineTo = (command == 'T');
+ const QPointF &radii = QPointF(px2, py2);
+ const QPointF &angles = QPointF(tox, toy) / (180.0/M_PI);
+ QPointF start(radii.x() * cos(angles.x()), -1 * radii.y() * sin(angles.x()));
+ double sweepAngle = degSweepAngle(tox, toy, false);
+ if (lineTo)
+ pPath.lineTo(QPointF(px1, py1) + start);
+ else
+ pPath.moveTo(QPointF(px1, py1) + start);
+ arcTo(pPath, pPath.currentPosition(), radii.x(), radii.y(), tox, sweepAngle);
break;
}
- case 'V':
- case 'W':
+ case 'X':
{
ptr = getCoord( ptr, tox );
ptr = getCoord( ptr, toy );
- ptr = getCoord( ptr, px1 );
- ptr = getCoord( ptr, py1 );
- ptr = getCoord( ptr, px2 );
- ptr = getCoord( ptr, py2 );
- ptr = getCoord( ptr, px3 );
- ptr = getCoord( ptr, py3 );
- double startA = QLineF(QPointF((px1 + tox) / 2.0, (py1 + toy) / 2.0), QPointF(px2, py2)).angle();
- double endA = QLineF(QPointF((px1 + tox) / 2.0, (py1 + toy) / 2.0), QPointF(px3, py3)).angle();
- if (command == 'V')
- pPath.moveTo(px2, py2);
- pPath.arcTo(QRectF(QPointF(tox, toy), QPointF(px1, py1)), startA, endA - startA);
+ double rx = tox - pPath.currentPosition().x();
+ double ry = toy - pPath.currentPosition().y();
+ double startAngle = xDir ? (ry > 0.0 ? 90.0 : 270.0) : (rx < 0.0 ? 0.0 : 180.0);
+ double sweepAngle = xDir ? (rx*ry < 0.0 ? 90.0 : -90.0) : (rx*ry > 0.0 ? 90.0 : -90.0);
+ arcTo(pPath, pPath.currentPosition(), fabs(rx), fabs(ry), startAngle, sweepAngle);
+ xDir = !xDir;
break;
}
- case 'X':
case 'Y':
{
ptr = getCoord( ptr, tox );
ptr = getCoord( ptr, toy );
- // qDebug() << "Command X and Y not implemented yet";
+ double rx = tox - pPath.currentPosition().x();
+ double ry = toy - pPath.currentPosition().y();
+ double startAngle = yDir ? (ry > 0.0 ? 90.0 : 270.0) : (rx < 0.0 ? 0.0 : 180.0);
+ double sweepAngle = yDir ? (rx*ry < 0.0 ? 90.0 : -90.0) : (rx*ry > 0.0 ? 90.0 : -90.0);
+ arcTo(pPath, pPath.currentPosition(), fabs(rx), fabs(ry), startAngle, sweepAngle);
+ yDir = !yDir;
break;
}
case 'Z':
{
- curx = subpathx;
- cury = subpathy;
- result.svgClosePath();
pPath.closeSubpath();
break;
}
@@ -2584,24 +2643,133 @@
command = 'L';
}
else
+ {
command = *(ptr++);
-
- if( lastCommand != 'C' && lastCommand != 'S' && lastCommand != 'Q' && lastCommand != 'T')
- {
- contrlx = curx;
- contrly = cury;
+ xDir = true;
+ yDir = false;
}
}
if ((lastCommand != 'Z') || (moveCount > 1))
ret = true;
- if (result.size() > 2)
- {
- if ((result.point(0).x() == result.point(result.size()-2).x()) && (result.point(0).y() == result.point(result.size()-2).y()) && (moveCount == 1))
- ret = false;
- }
result.fromQPainterPath(pPath, !ret);
}
return ret;
+}
+
+double OdgPlug::angleFromPoint(const QPointF &point)
+{
+ double angle = atan2(point.y(), point.x());
+ if (angle < 0.0)
+ angle += 2*M_PI;
+ return 2*M_PI - angle;
+}
+
+double OdgPlug::radSweepAngle(double start, double stop, bool clockwise)
+{
+ double sweepAngle = stop - start;
+ if (fabs(sweepAngle) < 0.1) {
+ return 2*M_PI;
+ }
+ if (clockwise) {
+ // we are moving clockwise to the end angle
+ if (stop > start)
+ sweepAngle = (stop - start) - 2*M_PI;
+ } else {
+ // we are moving counter-clockwise to the stop angle
+ if (start > stop)
+ sweepAngle = 2*M_PI - (start-stop);
+ }
+
+ return sweepAngle;
+}
+
+double OdgPlug::degSweepAngle(double start, double stop, bool clockwise)
+{
+ double sweepAngle = stop - start;
+ if (fabs(sweepAngle) < 0.1) {
+ return 360.0;
+ }
+ if (clockwise) {
+ // we are moving clockwise to the end angle
+ if (stop > start)
+ sweepAngle = (stop - start) - 360.0;
+ } else {
+ // we are moving counter-clockwise to the stop angle
+ if (start > stop)
+ sweepAngle = 360.0 - (start-stop);
+ }
+ return sweepAngle;
+}
+
+void OdgPlug::arcTo(QPainterPath &path, QPointF startpoint, double rx, double ry, double startAngle, double sweepAngle)
+{
+ QPointF curvePoints[12];
+ int pointCnt = arcToCurve(rx, ry, startAngle, sweepAngle, startpoint, curvePoints);
+ for (int i = 0; i < pointCnt; i += 3)
+ {
+ path.cubicTo(curvePoints[i], curvePoints[i+1], curvePoints[i+2]);
+ }
+ return;
+}
+
+int OdgPlug::arcToCurve(double rx, double ry, double startAngle, double sweepAngle, const QPointF & offset, QPointF * curvePoints)
+{
+ int pointCnt = 0;
+
+ // check Parameters
+ if (sweepAngle == 0)
+ return pointCnt;
+ if (sweepAngle > 360)
+ sweepAngle = 360;
+ else if (sweepAngle < -360)
+ sweepAngle = - 360;
+
+ if (rx == 0 || ry == 0) {
+ //TODO
+ }
+
+ // split angles bigger than 90° so that it gives a good aproximation to the circle
+ double parts = ceil(qAbs(sweepAngle / 90.0));
+
+ double sa_rad = startAngle * M_PI / 180.0;
+ double partangle = sweepAngle / parts;
+ double endangle = startAngle + partangle;
+ double se_rad = endangle * M_PI / 180.0;
+ double sinsa = sin(sa_rad);
+ double cossa = cos(sa_rad);
+ double kappa = 4.0 / 3.0 * tan((se_rad - sa_rad) / 4);
+
+ // startpoint is at the last point is the path but when it is closed
+ // it is at the first point
+ QPointF startpoint(offset);
+
+ //center berechnen
+ QPointF center(startpoint - QPointF(cossa * rx, -sinsa * ry));
+
+ //kDebug(30006) <<"kappa" << kappa <<"parts" << parts;;
+
+ for (int part = 0; part < parts; ++part) {
+ // start tangent
+ curvePoints[pointCnt++] = QPointF(startpoint - QPointF(sinsa * rx * kappa, cossa * ry * kappa));
+
+ double sinse = sin(se_rad);
+ double cosse = cos(se_rad);
+
+ // end point
+ QPointF endpoint(center + QPointF(cosse * rx, -sinse * ry));
+ // end tangent
+ curvePoints[pointCnt++] = QPointF(endpoint - QPointF(-sinse * rx * kappa, -cosse * ry * kappa));
+ curvePoints[pointCnt++] = endpoint;
+
+ // set the endpoint as next start point
+ startpoint = endpoint;
+ sinsa = sinse;
+ cossa = cosse;
+ endangle += partangle;
+ se_rad = endangle * M_PI / 180.0;
+ }
+
+ return pointCnt;
}
PageItem* OdgPlug::addClip(PageItem* retObj, ObjStyle &obState)
Modified: trunk/Scribus/scribus/plugins/import/odg/importodg.h
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=18833&path=/trunk/Scribus/scribus/plugins/import/odg/importodg.h
==============================================================================
--- trunk/Scribus/scribus/plugins/import/odg/importodg.h (original)
+++ trunk/Scribus/scribus/plugins/import/odg/importodg.h Sun Feb 23 19:33:01 2014
@@ -285,6 +285,11 @@
double parseUnit(const QString &unit);
const char * getCoord( const char *ptr, double &number );
bool parseEnhPath(const QString& svgPath, FPointArray &result, bool &fill, bool &stroke);
+ double angleFromPoint(const QPointF &point);
+ double radSweepAngle(double start, double stop, bool clockwise);
+ double degSweepAngle(double start, double stop, bool clockwise);
+ void arcTo(QPainterPath &path, QPointF startpoint, double rx, double ry, double startAngle, double sweepAngle);
+ int arcToCurve(double rx, double ry, double startAngle, double sweepAngle, const QPointF & offset, QPointF * curvePoints);
QColor parseColorN( const QString &rgbColor );
QString parseColor( const QString &s );
QString constructFontName(QString fontBaseName, QString fontStyle);
More information about the scribus-commit
mailing list