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.
494 lines
10 KiB
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;
|
|
}
|
|
}
|