Basically this boils down to finding the most extreme X and Y values of
the arc, then checking to see if the extremes are inside the working
area.

The most extreme points of a circle are at the angles that are multiples
of π/2 (for instance, if you consider a circle as going from 0 to 2π
radians, then it's the angles 0, π/2, π, and 3π/2)

The most extreme points of an arc are any of those 4 points that lie on
the arc, and also the start and end points of the arc.

So first, test the start and end points.  Next, convert the arc to the
representation
    center
    radius
    start angle
    end angle
using atan2 to convert the start and end points to radians.  If
necessary, add or subtract 2π from the ending angle in order to make the
rotation go in the right direction.  Because atan2 returns a value in
the range [-π..π], this means the possible angles after the addition or
subtraction of 2π are [-3π, 3π].  For each multiple of π/2 between the
angles, compute that point on the arc and test it against the working
area.

The following lightly-tested Python code implements the method I've
described:
#!/usr/bin/python
from math import sin, cos, atan2, pi, hypot

def arc_bounds(cx, cy, x0, y0, x1, y1, winding):
    """Return the bounding box of an arc given center, first point, final
    point, and winding direction (-1 means CW, +1 means CCW)"""

    rad = hypot(y0-cy, x0-cx)
    theta1 = atan2(y0-cy, x0-cx)
    theta2 = atan2(y1-cy, x1-cx)

    if winding < 0:
        while theta2 - theta1 > -1e-12: theta2 -= 2*pi;
    else:
        while theta2 - theta1 < 1e-12: theta2 += 2*pi;

    if theta2 < theta1: theta1, theta2 = theta2, theta1

    # xpts, ypts accumulate the points that could be the most extreme points of
    # the arc -- the endpoints
    xpts = [x0, x1]
    ypts = [y0, y1]
    
    # .. as well as the quadrant points that are included in the arc
    for j in range(-6, 7):
        th = j * pi / 2 
        if th < theta1: continue  # before start of arc
        if th > theta2: break     # after end of arc
        
        x = cx + rad * cos(th)
        y = cy + rad * sin(th)
        
        xpts.append(x)
        ypts.append(y)
    
    return min(xpts), max(xpts), min(ypts), max(ypts)

And here are the test cases I tried:
# Full radius-1 circle centered at origin
>>> print "% 4.1f % 4.1f % 4.1f % 4.1f" % arc_bounds(0, 0, 1, 0, 1, 0, 1)
-1.0  1.0 -1.0  1.0

# Full radius=sqrt(2) circle centered at origin
>>> print "% 4.1f % 4.1f % 4.1f % 4.1f" % arc_bounds(0, 0, 1, 1, 1, 1, 1)
-1.4  1.4 -1.4  1.4

# Partial radius=sqrt(2) circle centered at origin
>>> print "% 4.1f % 4.1f % 4.1f % 4.1f" % arc_bounds(0, 0, 1, 1, -1, 1, 1)
-1.0  1.0  1.0  1.4

Jeff

------------------------------------------------------------------------------
Colocation vs. Managed Hosting
A question and answer guide to determining the best fit
for your organization - today and in the future.
http://p.sf.net/sfu/internap-sfd2d
_______________________________________________
Emc-users mailing list
Emc-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/emc-users

Reply via email to