leocad/common/curve.cpp
2011-09-07 21:06:51 +00:00

872 lines
20 KiB
C++
Executable file

// Curve class, used to represent all flexible objects
//
#include <stdlib.h>
#include <math.h>
#include "globals.h"
#include "curve.h"
#include "opengl.h"
#include "matrix.h"
#include "vector.h"
#define LC_CURVE_SAVE_VERSION 1 // LeoCAD 0.73
#define LC_CURVE_POINT_SAVE_VERSION 1 // LeoCAD 0.73
GLuint CurvePoint::m_nArrowList = 0;
GLuint CurvePoint::m_nSphereList = 0;
static LC_OBJECT_KEY_INFO curve_point_key_info[LC_CURVE_POINT_KEY_COUNT] =
{
{ "Control Point Position", 3, LC_CURVE_POINT_KEY_POSITION },
{ "Control Point Direction 1", 3, LC_CURVE_POINT_KEY_DIRECTION1 },
{ "Control Point Direction 2", 3, LC_CURVE_POINT_KEY_DIRECTION2 },
{ "Control Point Angle", 1, LC_CURVE_POINT_KEY_ANGLE }
};
// =============================================================================
// CurvePoint class
CurvePoint::CurvePoint (Curve *pParent)
: Object (LC_OBJECT_CURVE_POINT)
{
m_pParent = pParent;
/*
FIXME
strcpy (m_strName, pParent->GetName ());
m_strName[LC_OBJECT_NAME_LEN-8] = '\0';
strcat (m_strName, ".Target");
*/
Initialize ();
}
CurvePoint::CurvePoint (Curve *pParent, const float *pos, const float *dir)
: Object (LC_OBJECT_CURVE_POINT)
{
m_pParent = pParent;
/*
FIXME
strcpy (m_strName, pParent->GetName ());
m_strName[LC_OBJECT_NAME_LEN-8] = '\0';
strcat (m_strName, ".Target");
*/
Initialize ();
float angle[1] = { 0 };
ChangeKey (1, false, true, pos, LC_CURVE_POINT_KEY_POSITION);
ChangeKey (1, false, true, dir, LC_CURVE_POINT_KEY_DIRECTION1);
ChangeKey (1, false, true, dir, LC_CURVE_POINT_KEY_DIRECTION2);
ChangeKey (1, false, true, angle, LC_CURVE_POINT_KEY_ANGLE);
ChangeKey (1, true, true, pos, LC_CURVE_POINT_KEY_POSITION);
ChangeKey (1, true, true, dir, LC_CURVE_POINT_KEY_DIRECTION1);
ChangeKey (1, true, true, dir, LC_CURVE_POINT_KEY_DIRECTION2);
ChangeKey (1, true, true, angle, LC_CURVE_POINT_KEY_ANGLE);
UpdatePosition (1, false);
}
void CurvePoint::Initialize ()
{
if (m_nSphereList == 0)
{
m_nSphereList = glGenLists (1);
glNewList (m_nSphereList, GL_COMPILE);
float radius = 0.2f;
int slices = 6, stacks = 6;
float rho, drho, theta, dtheta;
float x, y, z;
int i, j, imin, imax;
drho = 3.1415926536f/(float)stacks;
dtheta = 2.0f*3.1415926536f/(float)slices;
// draw +Z end as a triangle fan
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0, 0.0, radius);
for (j = 0; j <= slices; j++)
{
theta = (j == slices) ? 0.0f : j * dtheta;
x = (float)(-sin(theta) * sin(drho));
y = (float)(cos(theta) * sin(drho));
z = (float)(cos(drho));
glVertex3f(x*radius, y*radius, z*radius);
}
glEnd();
imin = 1;
imax = stacks-1;
for (i = imin; i < imax; i++)
{
rho = i * drho;
glBegin(GL_QUAD_STRIP);
for (j = 0; j <= slices; j++)
{
theta = (j == slices) ? 0.0f : j * dtheta;
x = (float)(-sin(theta) * sin(rho));
y = (float)(cos(theta) * sin(rho));
z = (float)(cos(rho));
glVertex3f(x*radius, y*radius, z*radius);
x = (float)(-sin(theta) * sin(rho+drho));
y = (float)(cos(theta) * sin(rho+drho));
z = (float)(cos(rho+drho));
glVertex3f(x*radius, y*radius, z*radius);
}
glEnd();
}
// draw -Z end as a triangle fan
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0, 0.0, -radius);
rho = 3.1415926536f - drho;
for (j = slices; j >= 0; j--)
{
theta = (j==slices) ? 0.0f : j * dtheta;
x = (float)(-sin(theta) * sin(rho));
y = (float)(cos(theta) * sin(rho));
z = (float)(cos(rho));
glVertex3f(x*radius, y*radius, z*radius);
}
glEnd();
glEndList();
}
m_nState = LC_CURVE_POINT_CONTINUOUS;
float *values[] = { m_fPos, m_fDir1, m_fDir2, &m_fAngle };
RegisterKeys (values, curve_point_key_info, LC_CURVE_POINT_KEY_COUNT);
}
CurvePoint::~CurvePoint ()
{
}
void CurvePoint::MinIntersectDist (LC_CLICKLINE* pLine)
{
float dist = (float)BoundingBoxIntersectDist (pLine);
if (dist < pLine->mindist)
{
pLine->mindist = dist;
pLine->pClosest = this;
m_nLastHit = 1;
}
m_nLastHit = 0;
// FIXME: check arrows
}
void CurvePoint::UpdatePosition (unsigned short nTime, bool bAnimation)
{
CalculateKeys (nTime, bAnimation);
}
bool CurvePoint::FileLoad (File& file)
{
// FIXME
return true;
}
void CurvePoint::FileSave (File& file) const
{
// FIXME
}
void CurvePoint::Move (unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz)
{
/*
if (m_nState & LC_CURVE_POINT_ARROW1_FOCUS)
if (m_nState & LC_CURVE_POINT_ARROW2_FOCUS)
if (m_nState & LC_CURVE_POINT_CONTINUOUS)
;
*/
}
void CurvePoint::Select (bool bSelecting, bool bFocus, bool bMultiple)
{
// FIXME: select arrows, use m_nLastHit
if (bSelecting == true)
{
m_nState |= LC_CURVE_POINT_SELECTED;
if (bFocus == true)
{
m_nState |= LC_CURVE_POINT_FOCUSED;
m_pParent->DeselectOtherPoints (this, bMultiple);
}
}
else
{
if (bFocus == true)
m_nState &= ~(LC_CURVE_POINT_SELECTED|LC_CURVE_POINT_FOCUSED);
else
m_nState &= ~(LC_CURVE_POINT_SELECTED);
}
}
void CurvePoint::Render (LC_RENDER_INFO* pInfo)
{
if (m_nState & LC_CURVE_POINT_FOCUSED)
glColor3ubv (FlatColorArray[LC_COL_FOCUSED]);
else if (m_nState & LC_CURVE_POINT_SELECTED)
glColor3ubv (FlatColorArray[LC_COL_SELECTED]);
else
glColor3f(0.5f, 0.8f, 0.5f); // FIXME: same as camera color, add to FlatColorArray
// glColor3ub (0, 0, 0); // FIXME: inverse of background
// FIXME: add a new color to the array and change the names from LC_COL to LC_COLOR ?
glPushMatrix ();
glTranslatef (m_fPos[0], m_fPos[1], m_fPos[2]);
glCallList (m_nSphereList);
// FIXME: create and use arrow display list
// if (m_pPoints[i].m_nFlags & LC_CURVE_POINT_FOCUSED)
{
glBegin (GL_LINES);
glVertex3f ( m_fDir1[0]/5, m_fDir1[1]/5, m_fDir1[2]/5);
glVertex3f (-m_fDir2[0]/5, -m_fDir2[1]/5, -m_fDir2[2]/5);
glEnd ();
}
glPopMatrix ();
}
// =============================================================================
// Curve class
Curve::Curve ()
: Object (LC_OBJECT_CURVE)
{
Initialize ();
}
Curve::Curve (PieceInfo *pInfo, const float *pos, unsigned char color)
: Object (LC_OBJECT_CURVE)
{
/*
Initialize ();
// FIXME: set the curve type and length based on the PieceInfo
m_fLength = 5;
m_nCurveType = LC_CURVE_TYPE_HOSE;
m_nColor = color;
float dir[3] = { 0, 20, 0 }, pos2[3] = { pos[0] + m_fLength, pos[1], pos[2] };
m_fUp0[0] = 0;
m_fUp0[1] = 0;
m_fUp0[2] = 1;
CurvePoint *pt;
pt = new CurvePoint (this, pos, dir);
m_Points.Add (pt);
dir[1] = 0;
dir[2] = -5;
pt = new CurvePoint (this, pos2, dir);
m_Points.Add (pt);
pos2[0] += 5;
dir[2] = 5;
pt = new CurvePoint (this, pos2, dir);
m_Points.Add (pt);
UpdatePosition (1, false);
*/
}
Curve::~Curve ()
{
/*
for (int i = 0; i < m_Points.GetSize (); i++)
delete m_Points[i];
glDeleteLists (m_nDisplayList, 1);
*/
}
void Curve::Initialize ()
{
m_nCurveType = (LC_CURVE_TYPE)0;
m_nState = 0;
m_nColor = 0;
m_nDisplayList = glGenLists (1);
}
bool Curve::FileLoad (File& file)
{
// FIXME
return true;
}
void Curve::FileSave (File& file) const
{
// FIXME
}
void Curve::MinIntersectDist (LC_CLICKLINE* pLine)
{
// FIXME
}
void Curve::UpdatePosition (unsigned short nTime, bool bAnimation)
{
for (int i = 0; i < m_Points.GetSize (); i++)
m_Points[i]->UpdatePosition (nTime, bAnimation);
glNewList (m_nDisplayList, GL_COMPILE);
switch (m_nCurveType)
{
case LC_CURVE_TYPE_HOSE:
TesselateHose ();
break;
}
glEndList ();
}
void Curve::Move (unsigned short nTime, bool bAnimation, bool bAddKey, float dx, float dy, float dz)
{
for (int i = 0; i < m_Points.GetSize (); i++)
m_Points[i]->Move (nTime, bAnimation, bAddKey, dx, dy, dz);
}
void Curve::Select (bool bSelecting, bool bFocus, bool bMultiple)
{
if (bSelecting == true)
{
if (bFocus == true)
{
m_nState |= (LC_CURVE_SELECTED|LC_CURVE_FOCUSED);
for (int i = 0; i < m_Points.GetSize (); i++)
m_Points[i]->Select (false, true, bMultiple);
}
else
m_nState |= LC_CURVE_SELECTED;
}
else
{
if (bFocus == true)
m_nState &= ~(LC_CURVE_SELECTED|LC_CURVE_FOCUSED);
else
m_nState &= ~(LC_CURVE_SELECTED);
for (int i = 0; i < m_Points.GetSize (); i++)
m_Points[i]->Select (false, bFocus, bMultiple);
}
}
void Curve::DeselectOtherPoints (CurvePoint *pSender, bool bFocusOnly)
{
CurvePoint *pt;
for (int i = 0; i < m_Points.GetSize (); i++)
{
pt = m_Points[i];
if (pt != pSender)
pt->Select (false, bFocusOnly, true);
}
}
/*
void Curve::TesselateHose ()
{
float x, y, z, t, t2, t3, cx[4], cy[4], cz[4];
const float *p1, *p2, *r1, *r2, *u1, *u2;
glEnableClientState (GL_VERTEX_ARRAY);
for (unsigned int i = 0; i < m_Points.GetSize () - 1; i++)
{
p1 = m_Points[i]->GetPosition ();
p2 = m_Points[i+1]->GetPosition ();
r1 = m_Points[i]->GetDirection1 ();
r2 = m_Points[i+1]->GetDirection2 ();
u1 = m_Points[i]->GetUpVector ();
u2 = m_Points[i+1]->GetUpVector ();
cx[0] = 2*p1[0] - 2*p2[0] + r1[0] + r2[0];
cx[1] = -3*p1[0] + 3*p2[0] - 2*r1[0] - r2[0];
cx[2] = r1[0];
cx[3] = p1[0];
cy[0] = 2*p1[1] - 2*p2[1] + r1[1] + r2[1];
cy[1] = -3*p1[1] + 3*p2[1] - 2*r1[1] - r2[1];
cy[2] = r1[1];
cy[3] = p1[1];
cz[0] = 2*p1[2] - 2*p2[2] + r1[2] + r2[2];
cz[1] = -3*p1[2] + 3*p2[2] - 2*r1[2] - r2[2];
cz[2] = r1[2];
cz[3] = p1[2];
int steps1 = 16, steps2 = 6, j, k;
float* verts = (float*)malloc ((steps1+1) * steps2 * 3 * sizeof (float));
float a, b, c;
float ux, uy, uz;
for (t = 0, j = 0; j <= steps1; j++, t += 1.0f/steps1)
{
t2 = t*t;
t3 = t2*t;
// position
x = cx[0]*t3 + cx[1]*t2 + cx[2]*t + cx[3];
y = cy[0]*t3 + cy[1]*t2 + cy[2]*t + cy[3];
z = cz[0]*t3 + cz[1]*t2 + cz[2]*t + cz[3];
// tangent
a = 3*cx[0]*t2 + 2*cx[1]*t + cx[2];
b = 3*cy[0]*t2 + 2*cy[1]*t + cy[2];
c = 3*cz[0]*t2 + 2*cz[1]*t + cz[2];
// gradient
ux = 6*cx[0]*t + 2*cx[1];
uy = 6*cy[0]*t + 2*cy[1];
uz = 6*cz[0]*t + 2*cz[1];
Vector side, front (a, b, c);
Vector up (ux, uy, uz);
side.Cross (front, up);
up.Cross (side, front);
up.Normalize ();
front.Normalize ();
side.Normalize ();
float f[16];
#define M(row,col) f[col*4+row]
M(0,0) = side[0]; M(0,1) = up[0]; M(0,2) = front[0]; M(0,3) = x;
M(1,0) = side[1]; M(1,1) = up[1]; M(1,2) = front[1]; M(1,3) = y;
M(2,0) = side[2]; M(2,1) = up[2]; M(2,2) = front[2]; M(2,3) = z;
M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
#undef M
float v[3];
Matrix m;
m.FromFloat (f);
for (int k = 0; k < steps2; k++)
{
float *o = &verts[(j*steps2+k)*3];
v[0] = cos (2.0 * M_PI * k / steps2) * 0.15f;
v[1] = sin (2.0 * M_PI * k / steps2) * 0.15f;
v[2] = 0;
m.TransformPoint (o, v);
glVertex3fv (o);
}
}
GLuint *index = (GLuint*)malloc (2 * (steps2+1) * sizeof (GLuint));
glVertexPointer (3, GL_FLOAT, 0, verts);
for (j = 0; j < steps1; j++)
{
for (k = 0; k < steps2; k++)
{
index[k*2] = j*steps2+k;
index[k*2+1] = (j+1)*steps2+k;
}
index[k*2] = index[0];
index[k*2+1] = index[1];
glDrawElements (GL_TRIANGLE_STRIP, 2*(steps2+1), GL_UNSIGNED_INT, index);
}
free (index);
free (verts);
}
}
*/
void Curve::TesselateHose ()
{
float x, y, z, t, t2, t3, cx[4], cy[4], cz[4];
const float *p1, *p2, *r1, *r2;
float u[3] = { m_fUp0[0], m_fUp0[1], m_fUp0[2] };
int steps1 = 16, steps2 = 6, j, k;
float* verts = (float*)malloc ((steps1+1) * steps2 * 3 * sizeof (float));
float a, b, c;
glEnableClientState (GL_VERTEX_ARRAY);
glVertexPointer (3, GL_FLOAT, 0, verts);
for (int i = 0; i < m_Points.GetSize () - 1; i++)
{
float a1, a2, angle_step; // axial rotation
p1 = m_Points[i]->GetPosition ();
p2 = m_Points[i+1]->GetPosition ();
r1 = m_Points[i]->GetDirection1 ();
r2 = m_Points[i+1]->GetDirection2 ();
a1 = m_Points[i]->GetAngle ();
a2 = m_Points[i+1]->GetAngle ();
angle_step = (a2 - a1) / steps1;
if (fabs (angle_step) < 0.01f)
angle_step = 0;
cx[0] = 2*p1[0] - 2*p2[0] + r1[0] + r2[0];
cx[1] = -3*p1[0] + 3*p2[0] - 2*r1[0] - r2[0];
cx[2] = r1[0];
cx[3] = p1[0];
cy[0] = 2*p1[1] - 2*p2[1] + r1[1] + r2[1];
cy[1] = -3*p1[1] + 3*p2[1] - 2*r1[1] - r2[1];
cy[2] = r1[1];
cy[3] = p1[1];
cz[0] = 2*p1[2] - 2*p2[2] + r1[2] + r2[2];
cz[1] = -3*p1[2] + 3*p2[2] - 2*r1[2] - r2[2];
cz[2] = r1[2];
cz[3] = p1[2];
for (t = 0, j = 0; j <= steps1; j++, t += 1.0f/steps1)
{
t2 = t*t;
t3 = t2*t;
// position
x = cx[0]*t3 + cx[1]*t2 + cx[2]*t + cx[3];
y = cy[0]*t3 + cy[1]*t2 + cy[2]*t + cy[3];
z = cz[0]*t3 + cz[1]*t2 + cz[2]*t + cz[3];
// tangent
a = 3*cx[0]*t2 + 2*cx[1]*t + cx[2];
b = 3*cy[0]*t2 + 2*cy[1]*t + cy[2];
c = 3*cz[0]*t2 + 2*cz[1]*t + cz[2];
Vector side, front (a, b, c);
Vector up (u);
side.Cross (front, up);
up.Cross (side, front);
up.Normalize ();
front.Normalize ();
side.Normalize ();
if (angle_step != 0)
{
Matrix rot;
rot.FromAxisAngle (front, angle_step);
rot.TransformPoint (u, up);
}
else
up.ToFloat (u);
float f[16];
#define M(row,col) f[col*4+row]
M(0,0) = side[0]; M(0,1) = up[0]; M(0,2) = front[0]; M(0,3) = x;
M(1,0) = side[1]; M(1,1) = up[1]; M(1,2) = front[1]; M(1,3) = y;
M(2,0) = side[2]; M(2,1) = up[2]; M(2,2) = front[2]; M(2,3) = z;
M(3,0) = 0.0; M(3,1) = 0.0; M(3,2) = 0.0; M(3,3) = 1.0;
#undef M
float v[3];
Matrix m;
m.FromFloat (f);
for (int k = 0; k < steps2; k++)
{
float *o = &verts[(j*steps2+k)*3];
v[0] = (float)(cos (2.0 * M_PI * k / steps2) * 0.15);
v[1] = (float)(sin (2.0 * M_PI * k / steps2) * 0.15);
v[2] = 0;
m.TransformPoint (o, v);
}
}
GLuint *index = (GLuint*)malloc (2 * (steps2+1) * sizeof (GLuint));
for (j = 0; j < steps1; j++)
{
for (k = 0; k < steps2; k++)
{
index[k*2] = j*steps2+k;
index[k*2+1] = (j+1)*steps2+k;
}
index[k*2] = index[0];
index[k*2+1] = index[1];
glDrawElements (GL_TRIANGLE_STRIP, 2*(steps2+1), GL_UNSIGNED_INT, index);
}
free (index);
}
free (verts);
}
void Curve::Render (LC_RENDER_INFO* pInfo)
{
if ((m_nState & LC_CURVE_HIDDEN) != 0)
return;
// FIXME: create a "set color" function in LC_RENDER_INFO
if (pInfo->lighting)
glColor4ubv (ColorArray[m_nColor]);
else
glColor3ubv (FlatColorArray[m_nColor]);
if (m_nColor > 13 && m_nColor < 22) // FIXME: use a #define
{
if (!pInfo->transparent)
{
pInfo->transparent = true;
glEnable (GL_BLEND);
glDepthMask (GL_FALSE);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
}
else
{
if (pInfo->transparent)
{
pInfo->transparent = false;
glDepthMask (GL_TRUE);
glDisable (GL_BLEND);
}
}
// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
glCallList (m_nDisplayList);
// if (m_nState & LC_CURVE_SELECTED)
{
// turn off transparency to draw the control points
if (pInfo->transparent)
{
pInfo->transparent = false;
if (pInfo->transparent)
{
glDepthMask (GL_TRUE);
glDisable (GL_BLEND);
}
}
for (int i = 0; i < m_Points.GetSize (); i++)
m_Points[i]->Render (pInfo);
}
/*
if (IsSelected ())
{
for (int i = 0; i < m_nNumPoints; i++)
{
if (m_pPoints[i].m_nFlags & LC_CURVE_POINT_FOCUSED)
glColor3ubv (FlatColorArray[LC_COL_FOCUSED]);
else if (m_pPoints[i].m_nFlags & LC_CURVE_POINT_SELECTED)
glColor3ubv (FlatColorArray[LC_COL_SELECTED]);
else
glColor3f(0.5f, 0.8f, 0.5f); // FIXME: same as camera color, add to FlatColorArray
// glColor3ub (0, 0, 0); // FIXME: inverse of background
// FIXME: add a new color to the array and change the names from LC_COL to LC_COLOR ?
glPushMatrix ();
// RenderSegment (m_pPoints[i].m_fPos, m_pPoints[i+1].m_fPos, m_pSegments[i].m_fR1, m_pSegments[i].m_fR2);
glTranslatef (m_pPoints[i].m_fPos[0], m_pPoints[i].m_fPos[1], m_pPoints[i].m_fPos[2]);
glCallList (m_nSphereList);
if (m_pPoints[i].m_nFlags & LC_CURVE_POINT_FOCUSED)
{
glBegin (GL_LINES);
if (i < m_nNumSegments)
{
glVertex3fv (m_pSegments[i].m_fR1);
glVertex3f (0, 0, 0);
}
else if (i > 0)
{
glVertex3f (-m_pSegments[i-1].m_fR2[0], -m_pSegments[i-1].m_fR2[1], -m_pSegments[i-1].m_fR2[2]);
glVertex3f (0, 0, 0);
}
glEnd ();
}
glPopMatrix ();
}
}
*/
/*
if (m_nFlags & LC_CURVE_LOOP)
{
i = m_nNumPoints - 1;
RenderSegment (m_pPoints[0].pos, m_pPoints[i].pos, m_pPoints[0].normal, m_pPoints[i].normal);
}
*/
}
#if 0
#define LC_CURVE_POINT_RADIUS 0.2f
// =============================================================================
// Static functions
#include <math.h>
/*
// TODO: optimize
static void RenderSegment (float p1[3], float p2[3], float r1[3], float r2[3])
{
float x, y, z, t, t2, t3, cx[4], cy[4], cz[4];
int i;
cx[0] = 2*p1[0] - 2*p2[0] + r1[0] + r2[0];
cx[1] = -3*p1[0] + 3*p2[0] - 2*r1[0] - r2[0];
cx[2] = r1[0];
cx[3] = p1[0];
cy[0] = 2*p1[1] - 2*p2[1] + r1[1] + r2[1];
cy[1] = -3*p1[1] + 3*p2[1] - 2*r1[1] - r2[1];
cy[2] = r1[1];
cy[3] = p1[1];
cz[0] = 2*p1[2] - 2*p2[2] + r1[2] + r2[2];
cz[1] = -3*p1[2] + 3*p2[2] - 2*r1[2] - r2[2];
cz[2] = r1[2];
cz[3] = p1[2];
glColor3f (1,0,0);
glBegin (GL_LINE_STRIP);
glVertex3f (cx[3], cy[3], cz[3]);
for (t = 0, i = 0; i < 10; i++)
{
t += 0.1f;
t2 = t*t;
t3 = t2*t;
x = cx[0]*t3 + cx[1]*t2 + cx[2]*t + cx[3];
y = cy[0]*t3 + cy[1]*t2 + cy[2]*t + cy[3];
z = cz[0]*t3 + cz[1]*t2 + cz[2]*t + cz[3];
glVertex3f (x, y, z);
}
glEnd ();
glColor3f (0,0,0);
float a, b, c;
for (t = 0, i = 0; i <= 10; i++, t += 0.1f)
{
t2 = t*t;
t3 = t2*t;
x = cx[0]*t3 + cx[1]*t2 + cx[2]*t + cx[3];
y = cy[0]*t3 + cy[1]*t2 + cy[2]*t + cy[3];
z = cz[0]*t3 + cz[1]*t2 + cz[2]*t + cz[3];
a = 3*cx[0]*t2 + 2*cx[1]*t + cx[2];
b = 3*cy[0]*t2 + 2*cy[1]*t + cy[2];
c = 3*cz[0]*t2 + 2*cz[1]*t + cz[2];
Vector v1 (0, 0, 1);
Vector v2 (a, b, c);
Vector v3;
v3.Cross (v1, v2);
a = v1.Angle (v2);
float v[3];
v3.ToFloat (v);
Matrix m;
m.FromAxisAngle (v, a);
glBegin (GL_LINE_LOOP);
for (int j = 0; j < 16; j++)
{
float o[3];
v[0] = cos (2.0 * M_PI * j / 16) * 0.15f;
v[1] = sin (2.0 * M_PI * j / 16) * 0.15f;
v[2] = 0;
m.TransformPoint (o, v);
glVertex3f (o[0]+x, o[1]+y, o[2]+z);
}
glEnd ();
}
}
*/
// =============================================================================
// Curve class
void Curve::MinIntersectDist (LC_CLICKLINE* pLine)
{
// FIXME: Curve segments and tangent arrows
for (int i = 0; i < m_nNumPoints; i++)
{
double dist = pLine->PointDistance (m_pPoints[i].m_fPos);
if ((dist < pLine->mindist) && (dist < LC_CURVE_POINT_RADIUS))
{
pLine->mindist = dist;
pLine->pClosest = this;
pLine->pParam = &m_pPoints[i];
}
}
}
void Curve::SetSelection (bool bSelect, void *pParam)
{
Object::SetSelection (bSelect, pParam);
if (pParam != NULL)
{
for (int i = 0; i < m_nNumPoints; i++)
if (&m_pPoints[i] == pParam)
{
if (bSelect)
m_pPoints[i].m_nState |= LC_CURVE_POINT_SELECTED;
else
m_pPoints[i].m_nState &= ~(LC_CURVE_POINT_SELECTED | LC_CURVE_POINT_FOCUSED);
}
}
else
{
for (int i = 0; i < m_nNumPoints; i++)
if (bSelect)
m_pPoints[i].m_nState |= LC_CURVE_POINT_SELECTED;
else
m_pPoints[i].m_nState &= ~(LC_CURVE_POINT_SELECTED | LC_CURVE_POINT_FOCUSED);
}
}
void Curve::SetFocus (bool bFocus, void *pParam)
{
Object::SetFocus (bFocus, pParam);
if (pParam != NULL)
{
for (int i = 0; i < m_nNumPoints; i++)
if (&m_pPoints[i] == pParam)
{
if (bFocus)
m_pPoints[i].m_nState |= (LC_CURVE_POINT_SELECTED | LC_CURVE_POINT_FOCUSED);
else
m_pPoints[i].m_nState &= ~LC_CURVE_POINT_FOCUSED;
}
else
{
m_pPoints[i].m_nState &= ~LC_CURVE_POINT_FOCUSED;
}
}
}
#endif