diff options
Diffstat (limited to 'ksvg/impl/SVGPathSegArcImpl.cc')
-rw-r--r-- | ksvg/impl/SVGPathSegArcImpl.cc | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/ksvg/impl/SVGPathSegArcImpl.cc b/ksvg/impl/SVGPathSegArcImpl.cc new file mode 100644 index 00000000..9fb4190f --- /dev/null +++ b/ksvg/impl/SVGPathSegArcImpl.cc @@ -0,0 +1,495 @@ +/* + Copyright (C) 2001-2003 KSVG Team + This file is part of the KDE project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <math.h> + +#include <kdebug.h> + +#include "SVGPathSegArcImpl.h" +#include "SVGAngleImpl.h" + +using namespace KSVG; + +#include "SVGPathSegArcImpl.lut.h" +#include "ksvg_scriptinterpreter.h" +#include "ksvg_bridge.h" + +static void getArcSlopes(bool relative, double curx, double cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag, double *pStartSlope, double *pEndSlope) +{ + double sin_th, cos_th; + double a00, a01, a10, a11; + double x0, y0, x1, y1, xc, yc; + double d, sfactor, sfactor_sq; + double th0, th1, th_arc; + int i, n_segs; + + sin_th = sin(angle * (M_PI / 180.0)); + cos_th = cos(angle * (M_PI / 180.0)); + + double dx; + + if(!relative) + dx = (curx - x) / 2.0; + else + dx = -x / 2.0; + + double dy; + + if(!relative) + dy = (cury - y) / 2.0; + else + dy = -y / 2.0; + + double _x1 = cos_th * dx + sin_th * dy; + double _y1 = -sin_th * dx + cos_th * dy; + double Pr1 = r1 * r1; + double Pr2 = r2 * r2; + double Px = _x1 * _x1; + double Py = _y1 * _y1; + + // Spec : check if radii are large enough + double check = Px / Pr1 + Py / Pr2; + if(check > 1) + { + r1 = r1 * sqrt(check); + r2 = r2 * sqrt(check); + } + + a00 = cos_th / r1; + a01 = sin_th / r1; + a10 = -sin_th / r2; + a11 = cos_th / r2; + + x0 = a00 * curx + a01 * cury; + y0 = a10 * curx + a11 * cury; + + if(!relative) + x1 = a00 * x + a01 * y; + else + x1 = a00 * (curx + x) + a01 * (cury + y); + + if(!relative) + y1 = a10 * x + a11 * y; + else + y1 = a10 * (curx + x) + a11 * (cury + 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 = sqrt(sfactor_sq); + + if(sweepFlag == largeArcFlag) + 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 = atan2(y0 - yc, x0 - xc); + th1 = atan2(y1 - yc, x1 - xc); + + th_arc = th1 - th0; + if(th_arc < 0 && sweepFlag) + th_arc += 2 * M_PI; + else if(th_arc > 0 && !sweepFlag) + th_arc -= 2 * M_PI; + + n_segs = (int) (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))); + + for(int step = 0; step < 2; step++) + { + i = step == 0 ? 0 : n_segs - 1; + + double sin_th, cos_th; + double a00, a01, a10, a11; + double x1, y1, x2, y2, x3, y3; + double t; + double th_half; + + double _th0 = th0 + i * th_arc / n_segs; + double _th1 = th0 + (i + 1) * th_arc / n_segs; + + sin_th = sin(angle * (M_PI / 180.0)); + cos_th = cos(angle * (M_PI / 180.0)); + + /* inverse transform compared with rsvg_path_arc */ + a00 = cos_th * r1; + a01 = -sin_th * r2; + a10 = sin_th * r1; + a11 = cos_th * r2; + + th_half = 0.5 * (_th1 - _th0); + t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half); + x1 = xc + cos(_th0) - t * sin(_th0); + y1 = yc + sin(_th0) + t * cos(_th0); + x3 = xc + cos(_th1); + y3 = yc + sin(_th1); + x2 = x3 + t * sin(_th1); + y2 = y3 - t * cos(_th1); + + double bezX1 = a00 * x1 + a01 * y1; + double bezY1 = a10 * x1 + a11 * y1; + double bezX2 = a00 * x2 + a01 * y2; + double bezY2 = a10 * x2 + a11 * y2; + double bezX = a00 * x3 + a01 * y3; + double bezY = a10 * x3 + a11 * y3; + + if(step == 0) + *pStartSlope = SVGAngleImpl::todeg(atan2(bezY1 - cury, bezX1 - curx)); + else + *pEndSlope = SVGAngleImpl::todeg(atan2(bezY - bezY2, bezX - bezX2)); + } +} + +SVGPathSegArcAbsImpl::SVGPathSegArcAbsImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegArcAbsImpl::~SVGPathSegArcAbsImpl() +{ +} + +void SVGPathSegArcAbsImpl::setX(double x) +{ + m_x = x; +} + +double SVGPathSegArcAbsImpl::x() const +{ + return m_x; +} + +void SVGPathSegArcAbsImpl::setY(double y) +{ + m_y = y; +} + +double SVGPathSegArcAbsImpl::y() const +{ + return m_y; +} + +void SVGPathSegArcAbsImpl::setR1(double r1) +{ + m_r1 = r1; +} + +double SVGPathSegArcAbsImpl::r1() const +{ + return m_r1; +} + +void SVGPathSegArcAbsImpl::setR2(double r2) +{ + m_r2 = r2; +} + +double SVGPathSegArcAbsImpl::r2() const +{ + return m_r2; +} + +void SVGPathSegArcAbsImpl::setAngle(double angle) +{ + m_angle = angle; +} + +double SVGPathSegArcAbsImpl::angle() const +{ + return m_angle; +} + +void SVGPathSegArcAbsImpl::setLargeArcFlag(bool largeArcFlag) +{ + m_largeArcFlag = largeArcFlag; +} + +bool SVGPathSegArcAbsImpl::largeArcFlag() const +{ + return m_largeArcFlag; +} + +void SVGPathSegArcAbsImpl::setSweepFlag(bool sweepFlag) +{ + m_sweepFlag = sweepFlag; +} + +bool SVGPathSegArcAbsImpl::sweepFlag() const +{ + return m_sweepFlag; +} + +void SVGPathSegArcAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x() - curx; + double dy = y() - cury; + double startSlope; + double endSlope; + getArcSlopes(false, curx, cury, angle(), x(), y(), r1(), r2(), largeArcFlag(), sweepFlag(), &startSlope, &endSlope); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegArcAbsImpl::s_hashTable 11 + x SVGPathSegArcAbsImpl::X DontDelete + y SVGPathSegArcAbsImpl::Y DontDelete + r1 SVGPathSegArcAbsImpl::R1 DontDelete + r2 SVGPathSegArcAbsImpl::R2 DontDelete + angle SVGPathSegArcAbsImpl::Angle DontDelete + largeArcFlag SVGPathSegArcAbsImpl::LargeArcFlag DontDelete + sweepFlag SVGPathSegArcAbsImpl::SweepFlag DontDelete +@end +*/ + +Value SVGPathSegArcAbsImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case R1: + return Number(r1()); + case R2: + return Number(r2()); + case Angle: + return Number(angle()); + case LargeArcFlag: + return Boolean(largeArcFlag()); + case SweepFlag: + return Boolean(sweepFlag()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegArcAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case R1: + m_r1 = value.toNumber(exec); + break; + case R2: + m_r2 = value.toNumber(exec); + break; + case Angle: + m_angle = value.toNumber(exec); + break; + case LargeArcFlag: + m_largeArcFlag = value.toBoolean(exec); + break; + case SweepFlag: + m_sweepFlag = value.toBoolean(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + + + +SVGPathSegArcRelImpl::SVGPathSegArcRelImpl() : SVGPathSegImpl() +{ + KSVG_EMPTY_FLAGS +} + +SVGPathSegArcRelImpl::~SVGPathSegArcRelImpl() +{ +} + +void SVGPathSegArcRelImpl::setX(double x) +{ + m_x = x; +} + +double SVGPathSegArcRelImpl::x() const +{ + return m_x; +} + +void SVGPathSegArcRelImpl::setY(double y) +{ + m_y = y; +} + +double SVGPathSegArcRelImpl::y() const +{ + return m_y; +} + +void SVGPathSegArcRelImpl::setR1(double r1) +{ + m_r1 = r1; +} + +double SVGPathSegArcRelImpl::r1() const +{ + return m_r1; +} + +void SVGPathSegArcRelImpl::setR2(double r2) +{ + m_r2 = r2; +} + +double SVGPathSegArcRelImpl::r2() const +{ + return m_r2; +} + +void SVGPathSegArcRelImpl::setAngle(double angle) +{ + m_angle = angle; +} + +double SVGPathSegArcRelImpl::angle() const +{ + return m_angle; +} + +void SVGPathSegArcRelImpl::setLargeArcFlag(bool largeArcFlag) +{ + m_largeArcFlag = largeArcFlag; +} + +bool SVGPathSegArcRelImpl::largeArcFlag() const +{ + return m_largeArcFlag; +} + +void SVGPathSegArcRelImpl::setSweepFlag(bool sweepFlag) +{ + m_sweepFlag = sweepFlag; +} + +bool SVGPathSegArcRelImpl::sweepFlag() const +{ + return m_sweepFlag; +} + +void SVGPathSegArcRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const +{ + double dx = x(); + double dy = y(); + double startSlope; + double endSlope; + getArcSlopes(true, curx, cury, angle(), x(), y(), r1(), r2(), largeArcFlag(), sweepFlag(), &startSlope, &endSlope); + *pDx = dx; + *pDy = dy; + *pStartSlope = startSlope; + *pEndSlope = endSlope; +} + +// Ecma stuff + +/* +@namespace KSVG +@begin SVGPathSegArcRelImpl::s_hashTable 11 + x SVGPathSegArcRelImpl::X DontDelete + y SVGPathSegArcRelImpl::Y DontDelete + r1 SVGPathSegArcRelImpl::R1 DontDelete + r2 SVGPathSegArcRelImpl::R2 DontDelete + angle SVGPathSegArcRelImpl::Angle DontDelete + largeArcFlag SVGPathSegArcRelImpl::LargeArcFlag DontDelete + sweepFlag SVGPathSegArcRelImpl::SweepFlag DontDelete +@end +*/ + +Value SVGPathSegArcRelImpl::getValueProperty(ExecState *, int token) const +{ + switch(token) + { + case X: + return Number(x()); + case Y: + return Number(y()); + case R1: + return Number(r1()); + case R2: + return Number(r2()); + case Angle: + return Number(angle()); + case LargeArcFlag: + return Boolean(largeArcFlag()); + case SweepFlag: + return Boolean(sweepFlag()); + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + return Undefined(); + } +} + +void SVGPathSegArcRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int) +{ + switch(token) + { + case X: + m_x = value.toNumber(exec); + break; + case Y: + m_y = value.toNumber(exec); + break; + case R1: + m_r1 = value.toNumber(exec); + break; + case R2: + m_r2 = value.toNumber(exec); + break; + case Angle: + m_angle = value.toNumber(exec); + break; + case LargeArcFlag: + m_largeArcFlag = value.toBoolean(exec); + break; + case SweepFlag: + m_sweepFlag = value.toBoolean(exec); + break; + default: + kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl; + } +} + +// vim:ts=4:noet |