#include "art.h"
Image *color;
/*
* return the closest point on arc ip to point testp.
*/
Dpoint neararc(Item *ip, Dpoint testp){
Flt d;
Dpoint p, cen;
cen=circumcenter(ip->p[0], ip->p[1], ip->p[2]);
p=dsub(testp, cen);
d=dlen(p);
if(d!=0){
p=dlerp(cen, p, dist(ip->p[0], cen)/d);
if(triarea(ip->p[0], p, ip->p[2])*triarea(ip->p[0], ip->p[1], ip->p[2])>0) return p;
}
if(dist(testp, ip->p[0])<dist(testp, ip->p[2])) return ip->p[0];
return ip->p[2];
}
/*
* given three points, p[0], p[1], p[2] which indicate the points on the circle.
* p[0] and p[2] makes two end points, and p[1] indicates inner point in the arc
*/
void drawarc(Item *ip, Image *b, Image *color){
Dpoint cen;
int alpha, phi, p0, p2;
if(pldist(ip->p[1], ip->p[0], ip->p[2])<CLOSE){ /* not quite right, but ok */
line(b, D2P(ip->p[0]), D2P(ip->p[2]), Endsquare, Endsquare, 0, color, ZP);
if(ip->style&ARROW0)
line(b, D2P(ip->p[0]), D2P(ip->p[2]), Endsquare, Endarrow, 0, color, ZP);
if(ip->style&ARROW1)
line(b, D2P(ip->p[0]), D2P(ip->p[2]), Endarrow, Endsquare, 0, color, ZP);
return;
}
cen=circumcenter(ip->p[0], ip->p[1], ip->p[2]);
p0 = datan2((ip->p[0].y - cen.y), (ip->p[0].x - cen.x));
p2 = datan2((ip->p[2].y - cen.y), (ip->p[2].x - cen.x));
if(p2 > p0) { /* phi > 0 */
alpha = p0;
phi = p2 - p0;
}else {
alpha = p2;
phi = p0 - p2;
}
arc(b, D2P(cen), (int)(dist(cen, ip->p[0])*DPI), (int)(dist(cen, ip->p[0])*DPI), 0, color, ZP, alpha, phi);
if(ip->style&ARROW0) {
line(b, D2P(cen), D2P(ip->p[0]), Endsquare, Endarrow, 0, color, ZP);
line(b, D2P(cen), D2P(ip->p[2]), Endsquare, Endarrow, 0, color, ZP);
}else if(ip->style&ARROW1){
line(b, D2P(cen), D2P(ip->p[0]), Endarrow, Endsquare, 0, color, ZP);
line(b, D2P(cen), D2P(ip->p[2]), Endarrow, Endsquare, 0, color, ZP);
}else{
line(b, D2P(cen), D2P(ip->p[0]), Endsquare, Endsquare, 0, color, ZP);
line(b, D2P(cen), D2P(ip->p[2]), Endsquare, Endsquare, 0, color, ZP);
}
}
void editarc(void){
Flt l0=dist(arg[0], selection->p[0]);
Flt l1=dist(arg[0], selection->p[1]);
Flt l2=dist(arg[0], selection->p[2]);
if(l0<l1 && l0<l2){
hotpoint(selection->p[1]);
hotpoint(selection->p[2]);
track(movep, 0, selection);
}
else if(l1<l2){
hotpoint(selection->p[0]);
hotpoint(selection->p[2]);
track(movep, 1, selection);
}
else{
hotpoint(selection->p[0]);
hotpoint(selection->p[1]);
track(movep, 2, selection);
}
}
void translatearc(Item *ip, Dpoint delta){
ip->p[0]=dadd(ip->p[0], delta);
ip->p[1]=dadd(ip->p[1], delta);
ip->p[2]=dadd(ip->p[2], delta);
}
void deletearc(Item *ip){
}
void writearc(Item *ip, int f){
fprint(f, "a %.3f %.3f %.3f %.3f %.3f %.3f",
ip->p[0].x, ip->p[0].y, ip->p[1].x, ip->p[1].y, ip->p[2].x, ip->p[2].y);
writestyle(f, ip->style);
fprint(f, "\n");
}
void activatearc(Item *ip){
hotarc(ip->p[0], ip->p[1], ip->p[2]);
}
int inboxarc(Item *ip, Drectangle r){
Dpoint i[2];
return dptinrect(ip->p[0], r)
|| seginterarc(r.min, Dpt(r.min.x, r.max.y), ip->p[0], ip->p[1], ip->p[2], i)
|| seginterarc(r.min, Dpt(r.max.x, r.min.y), ip->p[0], ip->p[1], ip->p[2], i)
|| seginterarc(r.max, Dpt(r.min.x, r.max.y), ip->p[0], ip->p[1], ip->p[2], i)
|| seginterarc(r.max, Dpt(r.max.x, r.min.y), ip->p[0], ip->p[1], ip->p[2], i);
}
/*
* This can overestimate the size of the box.
*/
Drectangle bboxarc(Item *ip){
Drectangle r;
r.min=dsub(ip->p[0], Dpt(ip->r, ip->r));
r.max=dadd(ip->p[0], Dpt(ip->r, ip->r));
return r;
}
Dpoint nearvertarc(Item *ip, Dpoint testp){
if(dist(ip->p[0], testp)<dist(ip->p[2], testp)) return ip->p[0];
return ip->p[2];
}
Itemfns arcfns={
deletearc,
writearc,
activatearc,
neararc,
drawarc,
editarc,
translatearc,
inboxarc,
bboxarc,
nearvertarc,
};
Item *addarc(Item *head, Dpoint p0, Dpoint p1, Dpoint p2){
return additem(head, ARC, 0., 0, 0, 0, &arcfns, 3, p0, p1, p2);
}
|