Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "p_MWTk_SvgToPathConverter.h"
- p_MWTk_SvgToPathConverter::p_MWTk_SvgToPathConverter() { }
- QPainterPath p_MWTk_SvgToPathConverter::importSvgPathData(QString data)
- {
- QPainterPath ret_path;
- data = data.replace("m", " m ", Qt::CaseSensitive);
- data = data.replace("M", " M ", Qt::CaseSensitive);
- data = data.replace("c", " c ", Qt::CaseSensitive);
- data = data.replace("C", " C ", Qt::CaseSensitive);
- data = data.replace("l", " l ", Qt::CaseSensitive);
- data = data.replace("L", " L ", Qt::CaseSensitive);
- data = data.replace("v", " v ", Qt::CaseSensitive);
- data = data.replace("V", " V ", Qt::CaseSensitive);
- data = data.replace("h", " h ", Qt::CaseSensitive);
- data = data.replace("H", " H ", Qt::CaseSensitive);
- data = data.replace("a", " a ", Qt::CaseSensitive);
- data = data.replace("A", " A ", Qt::CaseSensitive);
- data = data.replace("t", " t ", Qt::CaseSensitive);
- data = data.replace("T", " T ", Qt::CaseSensitive);
- data = data.replace("q", " q ", Qt::CaseSensitive);
- data = data.replace("Q", " Q ", Qt::CaseSensitive);
- data = data.replace("s", " s ", Qt::CaseSensitive);
- data = data.replace("S", " S ", Qt::CaseSensitive);
- data = data.replace("z", " z ", Qt::CaseInsensitive);
- while (data.indexOf(" ") > -1) { data = data.replace(" ", " "); }
- QStringList codesUpper;
- codesUpper << "M" << "L" << "C" << "Z" << "Q" << "S" << "T" << "H" << "V";
- QStringList codesLower;
- codesLower << "m" << "l" << "c" << "z" << "q" << "s" << "t" << "h" << "v";
- QStringList codes_list;
- codes_list << codesUpper << codesLower;
- QChar prev_letter = 'M';
- QChar last_letter = 'M';
- SvgAction last_operation = MoveTo;
- QPointF last_position = QPointF(0.0, 0.0);
- QPointF last_cp = QPointF(0.0, 0.0);
- bool bypass_test = false;
- QStringList list_chunks = data.split(" ", QString::SkipEmptyParts);
- QStringListIterator it(list_chunks);
- while (it.hasNext()) {
- if (!bypass_test) {
- last_letter = QChar(it.next().at(0));
- //qDebug() << "INFO : bypass is off, last_letter found :" << last_letter;
- }
- else {
- //qDebug() << "INFO : bypass is on, last_letter used :" << last_letter;
- }
- bool is_relative = last_letter.isLower();
- //qDebug() << "INFO : operation is_relative:" << is_relative;
- int needed_points = -1;
- // find the needed code and points
- switch (last_letter.toLower().toAscii()) {
- case 'm' : {
- last_operation = MoveTo;
- needed_points = 1;
- break;
- }
- case 'l' : {
- last_operation = LineTo;
- needed_points = 1;
- break;
- }
- case 'v' : {
- last_operation = LineTo;
- needed_points = 1;
- break;
- }
- case 'h' : {
- last_operation = LineTo;
- needed_points = 1;
- break;
- }
- case 'c': {
- last_operation = CubicTo;
- needed_points = 3;
- break;
- }
- case 's': {
- last_operation = CubicTo;
- needed_points = 2;
- break;
- }
- case 'q' : {
- last_operation = QuadTo;
- needed_points = 2;
- break;
- }
- case 't': {
- last_operation = QuadTo;
- needed_points = 1;
- break;
- }
- case 'a' : {
- // a 25,50 -30 0,1 50,-25
- last_operation = ArcTo;
- needed_points = 4;
- break;
- }
- case 'z' : {
- last_operation = ClosePath;
- needed_points = 0;
- break;
- }
- default : {
- qDebug() << "ERROR : unknown SVG operation code :" << last_letter;
- break;
- }
- }
- // construct a list of points
- QVector<QPointF> vector_points;
- while (vector_points.count() < needed_points) {
- qreal x = 0;
- qreal y = 0;
- QString str_number;
- // iterate the list
- if (it.hasNext()) {
- str_number = it.next();
- }
- else {
- qDebug() << "ERROR : at end of the list before having found all needed points !";
- break;
- }
- if (str_number.contains(",")) {
- // split the pair
- x = str_number.split(",").first().toDouble();
- y = str_number.split(",").last().toDouble();
- }
- else {
- if (last_letter.toLower() == 'a'
- && vector_points.count() == 1) {
- // storing angle in X property
- x = str_number.toDouble();
- }
- if (last_letter.toLower() == 'h') {
- x = str_number.toDouble();
- // y is not provided for H
- }
- else if (last_letter.toLower() == 'v') {
- // x is not provided for V
- y = str_number.toDouble();
- }
- else {
- x = str_number.toDouble();
- // iterate the list
- if (it.hasNext()) {
- str_number = it.next();
- y = str_number.toDouble();
- }
- else {
- qDebug() << "ERROR : at end of the list before having found all needed points !";
- break;
- }
- }
- }
- vector_points.append(QPointF(x,y));
- }
- if (vector_points.count() < needed_points) {
- qDebug() << "ERROR : not enough points found";
- break;
- }
- qreal offsetX = is_relative ? last_position.x() : 0;
- qreal offsetY = is_relative ? last_position.y() : 0;
- // add operation to the path
- switch (last_operation) {
- case MoveTo: {
- QPointF p2 = vector_points.last() + QPointF(offsetX,offsetY);
- ret_path.moveTo(p2); // qDebug() << "INFO : added moveTo to the path.";
- last_position = p2;
- // back to default after a move operation
- last_operation = LineTo;
- last_letter = last_letter.isLower() ? 'l' : 'L';
- break;
- }
- case LineTo: {
- QPointF p2 = vector_points.last() + QPointF(offsetX,offsetY);
- ret_path.lineTo(p2); // qDebug() << "INFO : added LineTo to the path.";
- last_position = p2;
- break;
- }
- case CubicTo: {
- QPointF p1 = last_position;
- QPointF c1;
- QPointF c2;
- QPointF p2;
- if (last_letter.toLower() == 'c')
- {
- //qDebug() << "INFO : parse cubicto";
- c1 = vector_points.at(0) + QPointF(offsetX,offsetY);
- c2 = vector_points.at(1) + QPointF(offsetX,offsetY);
- p2 = vector_points.at(2) + QPointF(offsetX,offsetY);
- }
- else if (last_letter.toLower() == 's')
- {
- //qDebug() << "INFO : convert shorthand/smooth curveto";
- if (prev_letter == 'c' || prev_letter == 'C' ||
- prev_letter == 's' || prev_letter == 'S') {
- c1 = QPointF(2 * p1.x() - last_cp.x(),
- 2 * p1.y() - last_cp.y());
- }
- else {
- c1 = p1;
- }
- c2 = vector_points.at(0) + QPointF(offsetX,offsetY);
- p2 = vector_points.at(1) + QPointF(offsetX,offsetY);
- }
- ret_path.cubicTo(c1, c2, p2); // qDebug() << "INFO : added cubicTo to the path.";
- last_cp = c2;
- last_position = p2;
- break;
- }
- case QuadTo: {
- QPointF p1 = last_position;
- QPointF c;
- QPointF p2;
- if (last_letter.toLower() == 'q')
- {
- //qDebug() << "INFO : parse quadto";
- c = vector_points.at(0) + QPointF(offsetX,offsetY);
- p2 = vector_points.at(1) + QPointF(offsetX,offsetY);
- }
- else if (last_letter.toLower() == 't')
- {
- //qDebug() << "INFO : convert Shorthand/smooth quadratic Bézier curveto";
- p2 = vector_points.at(0) + QPointF(offsetX,offsetY);
- QPointF c;
- if (prev_letter == 'q' || prev_letter == 'Q' ||
- prev_letter == 't' || prev_letter == 'T') {
- c = QPointF(2 * p1.x() - last_cp.x(),
- 2 * p1.y() - last_cp.y());
- }
- else {
- c = p1;
- }
- }
- ret_path.quadTo(c, p2); // qDebug() << "INFO : added quadTo to the path.";
- last_cp = c;
- last_position = p2;
- break;
- }
- case ArcTo : {
- QPointF p1 = last_position;
- QPointF radius = vector_points.at(0);
- QPointF angle = vector_points.at(1);
- QPointF flags = vector_points.at(2);
- QPointF p2 = vector_points.at(3);
- pathArc(ret_path,
- radius.x(), radius.y(),
- angle.x(),
- (int)flags.x(), (int)flags.y(),
- p2.x(), p2.y(),
- p1.x(), p1.y());
- last_position = p2;
- break;
- }
- case ClosePath: {
- ret_path.closeSubpath(); // qDebug() << "INFO : added closeSubPath to the path.";
- // back to default after a close operation
- last_operation = MoveTo;
- last_letter = 'm';
- break;
- }
- }
- prev_letter = last_letter;
- if (it.hasNext()) {
- QString test_str = it.peekNext();
- if (codes_list.contains(test_str)) {
- // next chunk is an op code
- bypass_test = false;
- }
- else {
- // next chunk is yet a list of points
- bypass_test = true;
- }
- }
- }
- return ret_path;
- }
- void p_MWTk_SvgToPathConverter::pathArcSegment(QPainterPath &path,
- qreal xc, qreal yc,
- qreal th0, qreal th1,
- qreal rx, qreal ry, qreal xAxisRotation)
- {
- qreal sinTh, cosTh;
- qreal a00, a01, a10, a11;
- qreal x1, y1, x2, y2, x3, y3;
- qreal t;
- qreal thHalf;
- sinTh = qSin(xAxisRotation * (MWTk::TRIGO_PI / 180.0));
- cosTh = qCos(xAxisRotation * (MWTk::TRIGO_PI / 180.0));
- a00 = cosTh * rx;
- a01 = -sinTh * ry;
- a10 = sinTh * rx;
- a11 = cosTh * ry;
- thHalf = 0.5 * (th1 - th0);
- t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf);
- x1 = xc + qCos(th0) - t * qSin(th0);
- y1 = yc + qSin(th0) + t * qCos(th0);
- x3 = xc + qCos(th1);
- y3 = yc + qSin(th1);
- x2 = x3 + t * qSin(th1);
- y2 = y3 - t * qCos(th1);
- path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
- a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
- a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
- }
- // the arc handling code underneath is from XSVG (BSD license)
- /*
- * Copyright 2002 USC/Information Sciences Institute
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of
- * Information Sciences Institute not be used in advertising or
- * publicity pertaining to distribution of the software without
- * specific, written prior permission. Information Sciences Institute
- * makes no representations about the suitability of this software for
- * any purpose. It is provided "as is" without express or implied
- * warranty.
- *
- * INFORMATION SCIENCES INSTITUTE DISCLAIMS ALL WARRANTIES WITH REGARD
- * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INFORMATION SCIENCES
- * INSTITUTE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
- * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- *
- */
- void p_MWTk_SvgToPathConverter::pathArc(QPainterPath &path,
- qreal rx,
- qreal ry,
- qreal x_axis_rotation,
- int large_arc_flag,
- int sweep_flag,
- qreal x,
- qreal y,
- qreal curx,
- qreal cury)
- {
- qreal sin_th, cos_th;
- qreal a00, a01, a10, a11;
- qreal x0, y0, x1, y1, xc, yc;
- qreal d, sfactor, sfactor_sq;
- qreal th0, th1, th_arc;
- int i, n_segs;
- qreal dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check;
- rx = qAbs(rx);
- ry = qAbs(ry);
- sin_th = qSin(x_axis_rotation * (MWTk::TRIGO_PI / 180.0));
- cos_th = qCos(x_axis_rotation * (MWTk::TRIGO_PI / 180.0));
- dx = (curx - x) / 2.0;
- dy = (cury - y) / 2.0;
- dx1 = cos_th * dx + sin_th * dy;
- dy1 = -sin_th * dx + cos_th * dy;
- Pr1 = rx * rx;
- Pr2 = ry * ry;
- Px = dx1 * dx1;
- Py = dy1 * dy1;
- /* Spec : check if radii are large enough */
- check = Px / Pr1 + Py / Pr2;
- if (check > 1) {
- rx = rx * qSqrt(check);
- ry = ry * qSqrt(check);
- }
- a00 = cos_th / rx;
- a01 = sin_th / rx;
- a10 = -sin_th / ry;
- a11 = cos_th / ry;
- x0 = a00 * curx + a01 * cury;
- y0 = a10 * curx + a11 * cury;
- x1 = a00 * x + a01 * y;
- y1 = a10 * x + a11 * y;
- /* (x0, y0) is current point in transformed coordinate space.
- (x1, y1) is new point in transformed coordinate space.
- The arc fits a unit-radius circle in this space.
- */
- d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
- sfactor_sq = 1.0 / d - 0.25;
- if (sfactor_sq < 0) {
- sfactor_sq = 0;
- }
- sfactor = qSqrt(sfactor_sq);
- if (sweep_flag == large_arc_flag) {
- sfactor = -sfactor;
- }
- xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
- yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
- /* (xc, yc) is center of the circle. */
- th0 = qAtan2(y0 - yc, x0 - xc);
- th1 = qAtan2(y1 - yc, x1 - xc);
- th_arc = th1 - th0;
- if (th_arc < 0 && sweep_flag) {
- th_arc += 2 * MWTk::TRIGO_PI;
- }
- else if (th_arc > 0 && !sweep_flag) {
- th_arc -= 2 * MWTk::TRIGO_PI;
- }
- n_segs = qCeil(qAbs(th_arc / (MWTk::TRIGO_PI * 0.5 + 0.001)));
- for (i = 0; i < n_segs; i++) {
- pathArcSegment(path, xc, yc,
- th0 + i * th_arc / n_segs,
- th0 + (i + 1) * th_arc / n_segs,
- rx, ry, x_axis_rotation);
- }
- }
Add Comment
Please, Sign In to add comment