You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/ksvg/impl/SVGPathSegArcImpl.cpp

494 lines
10 KiB

/*
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;
}
}