354 lines
13 KiB
C
354 lines
13 KiB
C
#ifndef lint
|
|
static char sccsid[] = "@(#)circarc3.c 1.1 94/10/31 Copyr 1985-9 Sun Micro";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1985, 1986, 1987, 1988, 1989 by Sun Microsystems, Inc.
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose and without fee is hereby granted, provided that the above
|
|
* copyright notice appear in all copies and that both that copyright
|
|
* notice and this permission notice are retained, and that the name
|
|
* of Sun Microsystems, Inc., not be used in advertising or publicity
|
|
* pertaining to this software without specific, written prior permission.
|
|
* Sun Microsystems, Inc., makes no representations about the suitability
|
|
* of this software or the interface defined in this software for any
|
|
* purpose. It is provided "as is" without express or implied warranty.
|
|
*/
|
|
/*
|
|
* CGI circular arc functions
|
|
*/
|
|
|
|
/*
|
|
circular_arc_3pt_close
|
|
cgipw_circular_arc_3pt_close
|
|
_cgi_circular_arc_3pt_close
|
|
circular_arc_3pt
|
|
cgipw_circular_arc_3pt
|
|
_cgi_circular_arc_3pt
|
|
_cgi_determine_center_arc
|
|
_cgi_check_colinear
|
|
*/
|
|
/*
|
|
bugs:
|
|
3pt test
|
|
overlap in box
|
|
floats
|
|
*/
|
|
|
|
#include "cgipriv.h" /* defines types used in this file */
|
|
#ifndef window_hs_DEFINED
|
|
#include <sunwindow/window_hs.h>
|
|
#endif
|
|
#include <math.h>
|
|
|
|
View_surface *_cgi_vws; /* current view surface */
|
|
Outatt *_cgi_att; /* structure containing current attributes */
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* FUNCTION: circular_arc_3pt_close */
|
|
/* */
|
|
/* Draws closed circular arc starting at c1 and ending at c3 */
|
|
/* which is guaranteed to pass through point c2. */
|
|
/* Arc is closed with either PIE or CHORD. */
|
|
/* If points are colinear (or coincident, draw line c1->c3). */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
Cerror circular_arc_3pt_close(c1, c2, c3, close)
|
|
Ccoor *c1, *c2, *c3; /* starting, intermediate and ending points */
|
|
Cclosetype close; /* PIE or CHORD */
|
|
{
|
|
int ivw;
|
|
Cerror err; /* error */
|
|
Ccoor ca;
|
|
|
|
err = _cgi_err_check_4();
|
|
if (!err)
|
|
{
|
|
ca = *c1;
|
|
ivw = 0;
|
|
while (_cgi_bump_vws(&ivw))
|
|
{
|
|
err = _cgi_circular_arc_3pt_close(_cgi_vws, c1, c2, c3, close);
|
|
*c1 = ca;
|
|
}
|
|
}
|
|
return (_cgi_errhand(err));
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* FUNCTION: cgipw_circular_arc_3pt_close */
|
|
/* */
|
|
/* Draws closed circular arc starting at c1 and ending at c3 */
|
|
/* which is guaranteed to pass through point c2. */
|
|
/* Arc is closed with either PIE or CHORD. */
|
|
/* If points are colinear (or coincident, draw line c1->c3). */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
Cerror cgipw_circular_arc_3pt_close(desc, c1, c2, c3, close)
|
|
Ccgiwin *desc;
|
|
Ccoor *c1, *c2, *c3; /* starting, intermediate and ending points */
|
|
Cclosetype close; /* PIE or CHORD */
|
|
{
|
|
Cerror err;
|
|
|
|
err = _cgi_err_check_4();
|
|
if (!err)
|
|
{
|
|
SETUP_CGIWIN(desc);
|
|
err = _cgi_circular_arc_3pt_close(desc->vws, c1, c2, c3, close);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* FUNCTION: _cgi_circular_arc_3pt_close */
|
|
/* */
|
|
/* Draws closed circular arc starting at c1 and ending at c3 */
|
|
/* which is guaranteed to pass through point c2. */
|
|
/* Arc is closed with either PIE or CHORD. */
|
|
/* If points are colinear (or coincident, draw line c1->c3). */
|
|
/* */
|
|
/* wds: Rewritten to determine center & radius */
|
|
/* And then call cgipw_circular_arc_center with them. */
|
|
/* */
|
|
/* WDS: STILL needs code to check direction & always pass thru c2. */
|
|
/* (Reversing c1 and c3 args to this routine should have */
|
|
/* NO EFFECT. It should not draw the "other half" the circle. */
|
|
/****************************************************************************/
|
|
|
|
Cerror _cgi_circular_arc_3pt_close(vws, c1, c2, c3, close)
|
|
View_surface *vws;
|
|
Ccoor *c1, *c2, *c3; /* starting, intermediate and ending points */
|
|
Cclosetype close; /* PIE or CHORD */
|
|
{
|
|
Cerror err = NO_ERROR;
|
|
int colinear;
|
|
Ccoor center; /* center */
|
|
short rad;
|
|
|
|
colinear = _cgi_check_colinear(c1, c2, c3);
|
|
if (!colinear)
|
|
colinear = _cgi_determine_center_arc(c1, c2, c3, ¢er, &rad);
|
|
if (!colinear)
|
|
err = _cgi_circular_arc_center_close(vws, ¢er,
|
|
c1->x, c1->y,
|
|
c3->x, c3->y,
|
|
rad, close);
|
|
else
|
|
{
|
|
register Outatt *attP = vws->att;
|
|
Clinatt templin;
|
|
int itemp;
|
|
Ccoor pts[2];
|
|
|
|
pts[0] = *c1;
|
|
pts[2] = *c3;
|
|
templin = attP->line;
|
|
itemp = vws->conv.line_width;
|
|
/* substitute perimeter atts for line atts */
|
|
if (attP->fill.visible == ON)
|
|
{
|
|
/* WDS: CGI Manual says a line is drawn if points are colinear */
|
|
/* MDH: With current *edge* color & other attrs. */
|
|
attP->line.style = attP->fill.pstyle;
|
|
attP->line.width = attP->fill.pwidth;
|
|
attP->line.color = attP->fill.pcolor;
|
|
vws->conv.line_width = vws->conv.perimeter_width;
|
|
}
|
|
else
|
|
{
|
|
/* WDS: CGI Manual says a line is drawn if points are colinear */
|
|
/* MDH: draw a width 1, fill-color line */
|
|
attP->line.style = SOLID;
|
|
attP->line.width = 1.0;
|
|
attP->line.color = attP->fill.color;
|
|
vws->conv.line_width = 1;
|
|
}
|
|
err = _cgi_polyline(vws, 2, pts, POLY_DONTCLOSE, XFORM);
|
|
attP->line = templin;
|
|
vws->conv.line_width = itemp;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* FUNCTION: circular_arc_3pt */
|
|
/* */
|
|
/* Draws circular arc starting at c1 and ending at c3 */
|
|
/* which is guaranteed to pass through point c2. */
|
|
/* If points are colinear (or coincident, draw line c1->c3). */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
Cerror circular_arc_3pt(c1, c2, c3)
|
|
Ccoor *c1, *c2, *c3; /* starting, intermediate and ending points */
|
|
{
|
|
int ivw;
|
|
Cerror err; /* error */
|
|
Ccoor ca; /* JACK -- what is this var doing??? */
|
|
|
|
err = _cgi_err_check_4();
|
|
if (!err)
|
|
{
|
|
ca = *c1;
|
|
ivw = 0;
|
|
while (_cgi_bump_vws(&ivw))
|
|
{
|
|
err = _cgi_circular_arc_3pt(_cgi_vws, c1, c2, c3);
|
|
*c1 = ca;
|
|
}
|
|
}
|
|
return (_cgi_errhand(err));
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* FUNCTION: cgipw_circular_arc_3pt */
|
|
/* */
|
|
/* Draws circular arc starting at c1 and ending at c3 */
|
|
/* which is guaranteed to pass through point c2. */
|
|
/* If points are colinear (or coincident, draw line c1->c3). */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
Cerror cgipw_circular_arc_3pt(desc, c1, c2, c3)
|
|
Ccgiwin *desc;
|
|
Ccoor *c1, *c2, *c3; /* starting, intermediate and ending points */
|
|
{
|
|
Cerror err;
|
|
|
|
err = _cgi_err_check_4();
|
|
if (!err)
|
|
{
|
|
SETUP_CGIWIN(desc);
|
|
err = _cgi_circular_arc_3pt(desc->vws, c1, c2, c3);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* FUNCTION: _cgi_circular_arc_3pt */
|
|
/* */
|
|
/* Draws circular arc starting at c1 and ending at c3 */
|
|
/* which is guaranteed to pass through point c2. */
|
|
/* If points are colinear (or coincident, draw line c1->c3). */
|
|
/* */
|
|
/* WDS: STILL needs code to check direction & always pass thru c2. */
|
|
/* (Reversing c1 and c3 args to this routine should have */
|
|
/* NO EFFECT. It should not draw the "other half" the circle. */
|
|
/****************************************************************************/
|
|
|
|
Cerror _cgi_circular_arc_3pt(vws, c1, c2, c3)
|
|
View_surface *vws;
|
|
Ccoor *c1, *c2, *c3; /* starting, intermediate and ending points */
|
|
{
|
|
Ccoor center; /* center */
|
|
short rad; /* radius */
|
|
Cerror err = NO_ERROR;
|
|
int colinear;
|
|
|
|
colinear = _cgi_check_colinear(c1, c2, c3);
|
|
if (!colinear)
|
|
colinear = _cgi_determine_center_arc(c1, c2, c3, ¢er, &rad);
|
|
if (!colinear)
|
|
err = _cgi_circular_arc_center(vws, ¢er,
|
|
c1->x, c1->y, c3->x, c3->y, (int) rad, 0);
|
|
else
|
|
{
|
|
Ccoor pts[2];
|
|
/* WDS: CGI Manual says a line is drawn if points are colinear */
|
|
/* With current line color & other attrs. */
|
|
pts[0] = *c1;
|
|
pts[2] = *c3;
|
|
err = _cgi_polyline(vws, 2, pts, POLY_DONTCLOSE, XFORM);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* FUNCTION: _cgi_determine_center_arc */
|
|
/* */
|
|
/* Uses three points on circumference of circle */
|
|
/* to determine center and radius. */
|
|
/* Returns 0 if it works. */
|
|
/****************************************************************************/
|
|
int _cgi_determine_center_arc(c1, c2, c3, ca, radp)
|
|
Ccoor *c1, *c2, *c3; /* starting, intermediate and ending points */
|
|
Ccoor *ca; /* center -- an output value */
|
|
short *radp; /* radius -- an output value */
|
|
{
|
|
float xd21, yd21, xd32, yd32;
|
|
double rrad;
|
|
float b, b1, xr, yr, xdr, ydr;
|
|
float m10bis, m21bis;
|
|
|
|
/* find intersection points of three lines */
|
|
xd21 = c2->x - c1->x;
|
|
yd21 = c2->y - c1->y;
|
|
xd32 = c3->x - c2->x;
|
|
yd32 = c3->y - c2->y;
|
|
m10bis = -xd21 / yd21; /* slope of first perpindicular line */
|
|
m21bis = -xd32 / yd32; /* slope of second perpindicular line */
|
|
/*
|
|
* Since the two lines share point c2, if slopes are equal, they're
|
|
* colinear. but slopes won't be equal, just very close to it?
|
|
*/
|
|
# define EPS 0.5
|
|
if (fabs(m21bis - m10bis) <= EPS)
|
|
return (1); /* Too close to colinear or coincident */
|
|
|
|
b = (c2->y + c1->y) / 2 - m10bis * (c1->x + c2->x) / 2;
|
|
b1 = (c2->y + c3->y) / 2 - m21bis * (c3->x + c2->x) / 2;
|
|
xr = (b1 - b) / (m10bis - m21bis);
|
|
yr = m10bis * xr + b;
|
|
xr +=.5;
|
|
yr +=.5;
|
|
ca->x = xr;
|
|
ca->y = yr;
|
|
xdr = ca->x - c1->x; /* find center */
|
|
ydr = ca->y - c1->y;
|
|
|
|
rrad = (xdr * xdr);
|
|
rrad += (ydr * ydr);
|
|
rrad = pow((double) (rrad), 0.5) + 0.5;
|
|
*radp = rrad;
|
|
|
|
return (0); /* Normal return */
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* FUNCTION: _cgi_check_colinear */
|
|
/* */
|
|
/* */
|
|
/****************************************************************************/
|
|
int _cgi_check_colinear(c1, c2, c3)
|
|
Ccoor *c1, *c2, *c3; /* starting, intermediate and ending points */
|
|
{
|
|
|
|
#define SAME_POINT(p1,p2) ( (p1->x == p2->x) && ( p1->y == p2->y) )
|
|
#define X_DIST(p1,p2) (p2->x - p1->x) /* Final minus initial */
|
|
#define Y_DIST(p1,p2) (p2->y - p1->y) /* Final minus initial */
|
|
if (SAME_POINT(c1, c2) || SAME_POINT(c2, c3) || SAME_POINT(c3, c1))
|
|
return (1);
|
|
if ((X_DIST(c1, c2) == X_DIST(c2, c3)) && (Y_DIST(c1, c2) == Y_DIST(c2, c3)))
|
|
return (1);
|
|
if ((X_DIST(c2, c3) == X_DIST(c3, c1)) && (Y_DIST(c2, c3) == Y_DIST(c3, c1)))
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|