Efficiency in expressing circles is important to me as my SmartGo program
will be creating PDF files that contain diagrams of a Go board, and thus a
single page can easily contain close to a thousand circles.
Thanks,
Anders Kierulf
www.smartgo.com
> What's the most efficient way to do that and make
> it look as close to a real circle as possible?
A 90-deg arc of radius 1 can be closely approximated
by a Bezier with the following control points:
(0, 1) (0.5523, 1) (1, 0.5523) (1, 0)
The exact magic number is (4/3)*(sqrt(2)-1).
To draw a full circle, you will need four Beziers. My rough estimations
showed that the deviation is at most 0.3% by radius (probably less).
There is no visible difference.
Best regards,
Nikolai Grigoriev
RenderX
In case any of you were wondering, he got that "magic number" by
requiring that the curve described by (0, 1), (a, 1), (1, a) and (1,
0) go through the midpoint of the arc, (sqrt(2)/2, sqrt(2)/2) and
solving for a.
Although PostScript has the arc operators, the Red Book states that
the curves they produce are actually represented by Bezier cubics. So
PDF isn't actually missing anything here.
Mike
Michael Malak <mma...@alum.mit.edu> wrote:
> In case any of you were wondering, he got that "magic number" by
> requiring that the curve described by (0, 1), (a, 1), (1, a) and (1,
> 0) go through the midpoint of the arc, (sqrt(2)/2, sqrt(2)/2) and
> solving for a.
You are right. Just to be precise, he (= I) was actually solving
the equation for a more general case, using the approach you describe.
For an arc of radius 1 and angle phi, the distance between
the first and the second control point is:
a = (4/3) * tg (phi/4)
Regards,
Nikolai
Would it be something like this, with 4 bezier curves
(for a 20-pixel radius, red circle, centered at position (100,700))?
q
0.05 w
20 0 0 20 100 700 cm
1 0 0 RG
0 1 m
.5523 1 1 .5523 1 0 c
1 -.5523 .5523 -1 0 -1 c
-.5523 -1 -1 -.5523 -1 0 c
-1 .5523 -.5523 1 0 1 c
S
Q
Jose.
--------------------------
Jose Fernando Tepedino
e-mail: jo...@wiser.com.br
Mobile S.A.
Recife - Brasil
An even more general case !
If a cubic Bezier segment ABCD :-
+ goes from A to B, with control points B abd C
+ has an axis of symmetry
+ has a midpoint M, obviously on the axis of symmetry
+ P is the midpoint of AD
+ Q is the midpoint of BC
then :-
+ ABCD is an isosceles trapezium
+ AB and DC are the tangents at A and B
+ M is on PQ and three-quarters of the way up
i.e. MQ = 3 x PM
Nearly all software that uses Bezier curves to approximate
a quarter circle uses this curve, but it is NOT actually the
'BEST FIT' because its `distance from the centre' is NEVER greater
than the true radius.
If you try using it for a semi-circle, it really looks bad; I
would always use at least four segments to a circle. ( You can
do a bad semicircle of diameter 6 in your
head: ABCD is a 4 x 6 rectangle )
Another point is that you don't need to know the angle-measure
and you don't need to use trigonometry. You can use
co-ordinates instead--for example, calculating the origin-centred
arc through (a,b) and (a,-b)
--
Ken Starks
Three points:
1. You should certainly use X-Objects (The PDF answer to 'Define once,
use many times )
2. You may wish to draw all possible stones onto your diagram, and
then just switch on and off a `hidden' attribute, or change the
fill and stroke colours. You can do that with JavaScript.
3. There's a Go package for LaTeX, I believe. You would find it on
CTAN. I am not familiar with it, but the LaTeX package for chess
can take a list of moves and draw the board at any stage, so the
Go package might do something similar.
--
Ken Starks
Anders Kierulf
www.smartgo.com
void PDF::Circle(unsigned int x, unsigned int y, unsigned int radius)
{
unsigned int offset;
if (p_page != NULL)
{
if (p_page->width > p_page->height) offset = (unsigned
int)(((float)radius * p_page->width) / p_page->height);
else offset = (unsigned int)(((float)radius * p_page->height) /
p_page->width);
Curve(x - radius, y, x - radius, y + offset, x + radius, y +
offset, x + radius, y);
Curve(x - radius, y, x - radius, y - offset, x + radius, y -
offset, x + radius, y);
}
}
Hope this helps...
-Paul K.
Such as:
10 w % set diameter
1 J % round line caps
100 100 m % center coordinates
100 100 l % line of zero length, only the caps remain and make the circle
But I guess, the "4 curved arcs" approach is more robust than these "zero
length" lines, as they might be disregarded by some PDF software.
Ralf
ArcPoints PDF::Arc(unsigned int x_, unsigned int y_, unsigned int
radius_, float start_, float end_, bool continuation_)
{
float start = start_;
float end = end_;
struct Coordinate
{
int x;
int y;
};
Coordinate start_point;
Coordinate start_offset;
Coordinate end_point;
Coordinate end_offset;
ArcPoints result;
result.start_x = 0;
result.start_y = 0;
result.end_x = 0;
result.end_y = 0;
float offset = 0;
if (p_page != NULL && end_ > start_)
{
//do 1/4 slice increments
if (end - start > (PI / 2)) end = start + (PI / 2);
//figure out start and end points
start_point.x = (int)(radius_ * cos(start));
start_point.y = (int)(radius_ * sin(start));
end_point.x = (int)(radius_ * cos(end));
end_point.y = (int)(radius_ * sin(end));
//figure out point offset
offset = radius_ * ((end - start) / PI);
//find middle curve points at 90 degree angles
start_offset.x = start_point.x + (int)(offset * cos(start + (PI /
2)));
start_offset.y = start_point.y + (int)(offset * sin(start + (PI /
2)));
end_offset.x = end_point.x + (int)(offset * cos(end - (PI / 2)));
end_offset.y = end_point.y + (int)(offset * sin(end - (PI / 2)));
//mark curve
Curve(x_ + start_point.x, y_ + start_point.y, x_ + start_offset.x,
y_ + start_offset.y, x_ + end_offset.x, y_ + end_offset.y, x_ +
end_point.x, y_ + end_point.y, continuation_);
//remember end point from last arc for continuations
result.end_x = x_ + end_point.x;
result.end_y = y_ + end_point.y;
//if entire arc is not drawn draw next segment
if (end_ - start_ > (PI / 2))
{
result = Arc(x_, y_, radius_, start_ + (PI / 2), end_, true);
}
//remember start point of original arc, recursion above
result.start_x = x_ + start_point.x;
result.start_y = y_ + start_point.y;
}
return result;
}