ultimatepp/uppsrc/Painter/Arc.cpp
cxl c01865a3ef Added Painter - high quality, AGG based, software renderer, also NEVER_(msg)
git-svn-id: svn://ultimatepp.org/upp/trunk@745 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2009-01-14 10:46:18 +00:00

111 lines
3.3 KiB
C++

#include "Painter.h"
NAMESPACE_UPP
//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all coM_PIes.
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
// mcseemagg@yahoo.com
// http://www.antigrain.com
//----------------------------------------------------------------------------
//
// Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e.,
// 4, 7, 10, or 13 vertices.
//
//----------------------------------------------------------------------------
// Recycled for U++ by Miroslav Fidler 2008
void sSubArc(double cx, double cy, double rx, double ry,
double start_angle, double sweep_angle,
double *px, double *py)
{
double x0 = cos(sweep_angle / 2.0);
double y0 = sin(sweep_angle / 2.0);
double tx = (1.0 - x0) * 4.0 / 3.0;
double ty = y0 - tx * x0 / y0;
double x[4], y[4];
x[0] = x0;
y[0] = -y0;
x[1] = x0 + tx;
y[1] = -ty;
x[2] = x0 + tx;
y[2] = ty;
x[3] = x0;
y[3] = y0;
double sn = sin(start_angle + sweep_angle / 2.0);
double cs = cos(start_angle + sweep_angle / 2.0);
unsigned i;
for(i = 0; i < 4; i++) {
px[i] = cx + rx * (x[i] * cs - y[i] * sn);
py[i] = cy + ry * (x[i] * sn + y[i] * cs);
}
}
Painter& Painter::Arc(double x, double y, double rx, double ry,
double start_angle, double sweep_angle, bool startline)
{
const double bezier_arc_angle_epsilon = 0.01;
start_angle = fmod(start_angle, 2.0 * M_PI);
if(sweep_angle >= 2.0 * M_PI) sweep_angle = 2.0 * M_PI;
if(sweep_angle <= -2.0 * M_PI) sweep_angle = -2.0 * M_PI;
if(fabs(sweep_angle) < 1e-10) {
double px = x + rx * cos(start_angle);
double py = y + ry * sin(start_angle);
if(startline)
Line(px, py);
else
Move(px, py);
Line(x + rx * cos(start_angle + sweep_angle), y + ry * sin(start_angle + sweep_angle));
return *this;
}
double total_sweep = 0.0;
double local_sweep = 0.0;
double prev_sweep;
bool done = false;
bool first = true;
for(int i = 0; !done && i < 4; i++) {
if(sweep_angle < 0.0) {
prev_sweep = total_sweep;
local_sweep = -M_PI * 0.5;
total_sweep -= M_PI * 0.5;
if(total_sweep <= sweep_angle + bezier_arc_angle_epsilon) {
local_sweep = sweep_angle - prev_sweep;
done = true;
}
}
else {
prev_sweep = total_sweep;
local_sweep = M_PI * 0.5;
total_sweep += M_PI * 0.5;
if(total_sweep >= sweep_angle - bezier_arc_angle_epsilon) {
local_sweep = sweep_angle - prev_sweep;
done = true;
}
}
double px[4];
double py[4];
sSubArc(x, y, rx, ry, start_angle, local_sweep, px, py);
if(first)
if(startline)
Line(px[0], py[0]);
else
Move(px[0], py[0]);
first = false;
Cubic(px[1], py[1], px[2], py[2], px[3], py[3]);
start_angle += local_sweep;
}
return *this;
}
END_UPP_NAMESPACE