/*
* Copyright (c) 2006-2007 Hypertriton, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Basic circle.
*/
#include
#include
#include "sk.h"
#include "sk_gui.h"
SK_Circle *
SK_CircleNew(void *pnode)
{
SK_Circle *circle;
circle = Malloc(sizeof(SK_Circle));
SK_CircleInit(circle, SK_GenNodeName(SKNODE(pnode)->sk, "Circle"));
SK_NodeAttach(pnode, circle);
return (circle);
}
SK_Circle *
SK_CircleFromValue(void *pnode, M_Circle2 C)
{
SK_Circle *Cn;
Cn = SK_CircleNew(pnode);
Cn->r = C.r;
Cn->p = SK_PointNew(pnode);
SK_Translatev(Cn->p, &C.p);
return (Cn);
}
M_Circle2
SK_CircleValue(SK_Circle *Cn)
{
M_Circle2 C;
C.p = SK_Pos2(Cn->p);
C.r = Cn->r;
return (C);
}
void
SK_CircleInit(void *p, Uint name)
{
SK_Circle *circle = p;
SK_NodeInit(circle, &skCircleOps, name, 0);
circle->color = M_ColorBlack();
circle->width = 0.0;
circle->r = 0.0f;
circle->p = NULL;
}
int
SK_CircleLoad(SK *sk, void *p, AG_DataSource *buf)
{
SK_Circle *circle = p;
circle->color = M_ReadColor(buf);
circle->width = M_ReadReal(buf);
circle->r = M_ReadReal(buf);
circle->p = SK_ReadRef(buf, sk, "Point");
if (circle->p == NULL) {
AG_SetError("Missing center point (%s)", AG_GetError());
return (-1);
}
SK_NodeAddReference(circle, circle->p);
return (0);
}
int
SK_CircleSave(SK *sk, void *p, AG_DataSource *buf)
{
SK_Circle *circle = p;
M_WriteColor(buf, &circle->color);
M_WriteReal(buf, circle->width);
M_WriteReal(buf, circle->r);
SK_WriteRef(buf, circle->p);
return (0);
}
void
SK_CircleDraw(void *p, SK_View *skv)
{
SK_Circle *circle = p;
M_Vector3 v = SK_Pos(circle->p);
M_Color color = SK_NodeColor(circle, &circle->color);
M_Real i, incr;
SK_PointDraw(circle->p, skv);
if (circle->r < skv->wPixel)
return;
/* XXX */
incr = (2.0*M_PI)/30.0;
GL_Translatev(&v);
GL_Begin(GL_LINE_LOOP);
GL_Color3v(&color);
for (i = 0.0; i < M_PI*2.0; i+=incr) {
GL_Vertex2(Cos(i)*circle->r,
Sin(i)*circle->r);
}
GL_End();
GL_Translate(M_VecFlip3(v));
}
void
SK_CircleEdit(void *p, AG_Widget *box, SK_View *skv)
{
SK_Circle *circle = p;
const char *unit = skv->sk->uLen->abbr;
// AG_HSVPal *pal;
M_NumericalNewReal(box, 0, unit, _("Radius: "), &circle->r);
M_NumericalNewReal(box, 0, unit, _("Width: "), &circle->width);
// pal = AG_HSVPalNew(box, AG_HSVPAL_EXPAND);
// M_BindReal(pal, "RGBAv", (void *)&circle->color);
}
M_Real
SK_CircleProximity(void *p, const M_Vector3 *v, M_Vector3 *vC)
{
SK_Circle *circle = p;
M_Vector3 c = SK_Pos(circle->p);
M_Vector3 vRel = M_VecSub3p(v, &c);
M_Real theta = Atan2(vRel.y, vRel.x);
vC->x = c.x + circle->r*Cos(theta);
vC->y = c.y + circle->r*Sin(theta);
vC->z = 0.0;
return M_VecDistance3p(v, vC);
}
int
SK_CircleDelete(void *p)
{
SK_Circle *circle = p;
SK *sk = SKNODE(circle)->sk;
int rv;
SK_NodeDelReference(circle, circle->p);
if (SKNODE(circle->p)->nRefs == 0) {
SK_NodeDel(circle->p);
}
rv = SK_NodeDel(circle);
SK_Update(sk);
return (rv);
}
int
SK_CircleMove(void *p, const M_Vector3 *pos, const M_Vector3 *vel)
{
SK_Circle *c = p;
if (!(SKNODE(c->p)->flags & SK_NODE_MOVED)) {
SK_Translatev(c->p, vel);
SKNODE(c->p)->flags |= SK_NODE_MOVED;
}
return (1);
}
/*
* Circles in 2D require three constraints, two for the center point
* and one for the radius.
*/
SK_Status
SK_CircleConstrained(void *p)
{
SK_Circle *C = p;
SKNODE(C->p)->flags |= SK_NODE_CHECKED;
if (SKNODE(C->p)->nEdges == 2) {
if (SKNODE(C)->nEdges == 1) {
return (SK_WELL_CONSTRAINED);
} else if (SKNODE(C)->nEdges < 1) {
return (SK_UNDER_CONSTRAINED);
} else if (SKNODE(C)->nEdges > 1) {
return (SK_OVER_CONSTRAINED);
}
} else if (SKNODE(C->p)->nEdges < 2) {
return (SK_UNDER_CONSTRAINED);
}
return (SK_OVER_CONSTRAINED);
}
void
SK_CircleColor(SK_Circle *circle, M_Color c)
{
circle->color = c;
}
SK_NodeOps skCircleOps = {
"Circle",
sizeof(SK_Circle),
0,
SK_CircleInit,
NULL, /* destroy */
SK_CircleLoad,
SK_CircleSave,
SK_CircleDraw,
NULL, /* redraw */
SK_CircleEdit,
SK_CircleProximity,
SK_CircleDelete,
SK_CircleMove,
SK_CircleConstrained
};
#ifdef EDITION
struct sk_circle_tool {
SK_Tool tool;
SK_Circle *curCircle;
};
static void
ToolInit(void *_Nonnull p)
{
struct sk_circle_tool *t = p;
t->curCircle = NULL;
}
static int
ToolMouseMotion(void *_Nonnull p, M_Vector3 pos, M_Vector3 vel, int btn)
{
struct sk_circle_tool *t = p;
M_Vector3 vCenter, vC;
/* SK_Point *overPoint; */
(void)SK_ViewOverPoint(SKTOOL(t)->skv, &pos, &vC, NULL);
if (t->curCircle != NULL) {
vCenter = SK_Pos(t->curCircle->p);
t->curCircle->r = M_VecDistance3(vCenter, pos);
}
return (0);
}
static int
ToolMouseButtonDown(void *_Nonnull p, M_Vector3 pos, int btn)
{
struct sk_circle_tool *t = p;
SK_View *skv = SKTOOL(t)->skv;
SK *sk = skv->sk;
SK_Circle *circle;
SK_Point *overPoint;
M_Vector3 vC;
if (btn != AG_MOUSE_LEFT)
return (0);
if (t->curCircle != NULL) {
t->curCircle = NULL;
return (1);
}
overPoint = SK_ViewOverPoint(skv, &pos, &vC, NULL);
circle = SK_CircleNew(sk->root);
if (overPoint != NULL) {
circle->p = overPoint;
} else {
circle->p = SK_PointNew(sk->root);
SK_Translatev(circle->p, &pos);
}
SK_NodeAddReference(circle, circle->p);
t->curCircle = circle;
SK_Update(sk);
return (1);
}
SK_ToolOps skCircleToolOps = {
N_("Circle"),
N_("Insert a circle into the sketch"),
NULL,
sizeof(struct sk_circle_tool),
0,
ToolInit,
NULL, /* destroy */
NULL, /* edit */
ToolMouseMotion,
ToolMouseButtonDown,
NULL, /* buttonup */
NULL, /* keydown */
NULL /* keyup */
};
#endif /* EDITION */