HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
euclid/EUC_Expression.C
/*
* Copyright (c) 2024
* Side Effects Software Inc. All rights reserved.
*
* Redistribution and use of Houdini Development Kit samples 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. The name of Side Effects Software may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `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 SIDE EFFECTS SOFTWARE 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.
*
*----------------------------------------------------------------------------
* Defines the expressions that can be performed on sets of
* euclidean objects.
*/
#include "EUC_Expression.h"
#include <SYS/SYS_Math.h>
#include <UT/UT_Vector3.h>
using namespace HDK_Sample;
EUC_ExpressionList EUC_Expression::ourExpressionList;
int EUC_Expression::ourEvaluateTime = 0;
//
// EUC_Expression
//
{
myRefCount = 0;
myUid = ourExpressionList.size();
myLastEvaluateTime = 0;
myCd = 1;
myVisible = true;
ourExpressionList.append(this);
}
{
// Eliminate ourselves from the expression list.
ourExpressionList(getUid()) = 0;
}
void
{
myRefCount++;
}
void
{
myRefCount--;
if (myRefCount <= 0)
delete this;
}
{
// Out of bound is not created.
if (uid < 0 || uid >= ourExpressionList.size())
return 0;
return ourExpressionList(uid);
}
void
EUC_Expression::setLook(bool visible, const UT_Vector3 &cd)
{
myVisible = visible;
myCd = cd;
}
void
{
obj->setLook(myVisible, myCd);
}
void
{
// Reset the global evaluate time so we clear all the caches.
ourEvaluateTime++;
// Call the recursive evaluate. User wants total number of objects.
evaluateRecurse(tmp, results);
}
void
EUC_ObjectList &totalobj)
{
// Check to see if we are already cached.
if (myLastEvaluateTime == ourEvaluateTime)
{
result = myObjectCache;
return;
}
// Call subclass & cache.
myLastEvaluateTime = ourEvaluateTime;
myObjectCache.setSize(0);
evaluateSubclass(myObjectCache, totalobj);
result = myObjectCache;
}
//
// EUC_ExprPoint
//
{
myPos = pos;
}
void
EUC_ExprPoint::evaluateSubclass(EUC_ObjectList &result,
EUC_ObjectList &totalobj)
{
EUC_Point *pt;
pt = new EUC_Point(myPos);
applyLook(pt);
result.setSize(0);
result.append(pt);
totalobj.append(pt);
}
//
// EUC_ExprPointFromObject
//
{
src->addRef();
mySource = src;
myIndex = idx;
}
EUC_ExprPointFromObject::~EUC_ExprPointFromObject()
{
}
void
EUC_ObjectList &totalobj)
{
EUC_Point *pt;
EUC_ObjectList objlist;
EUC_Object *obj;
int i, n;
bool haspos;
result.setSize(0);
mySource->evaluateRecurse(objlist, totalobj);
n = objlist.size();
for (i = 0; i < n; i++)
{
obj = objlist(i);
haspos = false;
switch (obj->getType())
{
if (myIndex == 0)
{
haspos = true;
pos = ((EUC_Point *)obj)->getPos();
}
break;
if (myIndex >= 0 && myIndex <= 1)
{
haspos = true;
pos = ((EUC_Line *)obj)->getPt(myIndex);
}
break;
}
if (haspos)
{
pt = new EUC_Point(pos);
applyLook(pt);
result.append(pt);
totalobj.append(pt);
}
}
}
//
// EUC_ExprLineFromPoints
//
{
pta->addRef();
ptb->addRef();
myPtA = pta;
myPtB = ptb;
}
EUC_ExprLineFromPoints::~EUC_ExprLineFromPoints()
{
}
void
EUC_ObjectList &totalobj)
{
EUC_Line *line;
EUC_ObjectList ptalist, ptblist;
int i, n;
result.setSize(0);
myPtA->evaluateRecurse(ptalist, totalobj);
myPtB->evaluateRecurse(ptblist, totalobj);
n = SYSmin(ptalist.size(), ptblist.size());
for (i = 0; i < n; i++)
{
if (ptalist(i)->getType() == EUC_PointType &&
ptblist(i)->getType() == EUC_PointType)
{
a = ((EUC_Point *)ptalist(i))->getPos();
b = ((EUC_Point *)ptblist(i))->getPos();
line = new EUC_Line();
applyLook(line);
line->setPt(0, a);
line->setPt(1, b);
result.append(line);
totalobj.append(line);
}
}
}
//
// EUC_ExprCircleFromPoints
//
{
center->addRef();
pt->addRef();
myCenter = center;
myPoint = pt;
}
EUC_ExprCircleFromPoints::~EUC_ExprCircleFromPoints()
{
}
void
EUC_ObjectList &totalobj)
{
EUC_Circle *circle;
EUC_ObjectList ptalist, ptblist;
int i, n;
result.setSize(0);
myCenter->evaluateRecurse(ptalist, totalobj);
myPoint->evaluateRecurse(ptblist, totalobj);
n = SYSmin(ptalist.size(), ptblist.size());
for (i = 0; i < n; i++)
{
if (ptalist(i)->getType() == EUC_PointType &&
ptblist(i)->getType() == EUC_PointType)
{
a = ((EUC_Point *)ptalist(i))->getPos();
b = ((EUC_Point *)ptblist(i))->getPos();
circle = new EUC_Circle();
applyLook(circle);
circle->setPt(0, a);
circle->setPt(1, b);
result.append(circle);
totalobj.append(circle);
}
}
}
//
// EUC_ExprIntersect
//
{
expra->addRef();
exprb->addRef();
myExprA = expra;
myExprB = exprb;
}
EUC_ExprIntersect::~EUC_ExprIntersect()
{
}
void
EUC_ObjectList &totalobj)
{
EUC_Point *pt;
EUC_ObjectList ptalist, ptblist;
EUC_Object *obja, *objb;
int i, n;
result.setSize(0);
myExprA->evaluateRecurse(ptalist, totalobj);
myExprB->evaluateRecurse(ptblist, totalobj);
n = SYSmin(ptalist.size(), ptblist.size());
for (i = 0; i < n; i++)
{
// Sort the types so lowest is obja.
if (ptalist(i)->getType() < ptblist(i)->getType())
{
obja = ptalist(i);
objb = ptblist(i);
}
else
{
objb = ptalist(i);
obja = ptblist(i);
}
// This simplifies this double-switch...
if (obja->getType() == EUC_PointType)
{
// Points never intersect anything.
continue;
}
if (obja->getType() == EUC_LineType)
{
// Either Line-Line or Line-Circle
if (objb->getType() == EUC_LineType)
{
// Line-Line intersection
UT_Vector3 p1, p2, v1, v2, isect;
int retcode;
pos = ((EUC_Line *)obja)->getPt(0);
p1.assign(pos.x(), pos.y(), 0);
pos = ((EUC_Line *)obja)->getPt(1);
v1.assign(pos.x(), pos.y(), 0);
v1 -= p1;
pos = ((EUC_Line *)objb)->getPt(0);
p2.assign(pos.x(), pos.y(), 0);
pos = ((EUC_Line *)objb)->getPt(1);
v2.assign(pos.x(), pos.y(), 0);
v2 -= p2;
retcode = isect.lineIntersect(p1, v1, p2, v2);
// Non-parallel lines get a single intersection.
if (retcode != -1)
{
pos = isect;
pt = new EUC_Point(pos);
applyLook(pt);
result.append(pt);
totalobj.append(pt);
}
}
else
{
// Line-Circle isect.
float radius, a, b, c, t0, t1;
// x = p.x + v.x * t
// y = p.y + v.y * t
// Solve for:
// (x - c.x)^2 + (y - c.y) ^ 2 = r^2
// (v.x*t + (p.x - c.x))^2 + (v.y*t + (p.y - c.y))^2 = r^2
// Let c = p - c
// (v.x^2+v.y^2)*t^2
// + 2*(v.x*c.x+v.y*c.y)*t
// + (c.x^2+c.y^2-r^2) = 0
//
p = ((EUC_Line *)obja)->getPt(0);
v = ((EUC_Line *)obja)->getPt(1);
v -= p;
center = ((EUC_Circle *)objb)->getCenter();
radius = ((EUC_Circle *)objb)->getRadius();
center = p - center;
a = dot(v, v);
b = 2 * dot(v, center);
c = dot(center, center) - radius*radius;
if (UT_RootFinder::quadratic(a, b, c, t0, t1))
{
// We consider it two intersections.
pos = p + t0 * v;
pt = new EUC_Point(pos);
applyLook(pt);
result.append(pt);
totalobj.append(pt);
pos = p + t1 * v;
pt = new EUC_Point(pos);
applyLook(pt);
result.append(pt);
totalobj.append(pt);
}
}
}
else
{
// Must be Circle-Circle.
// Along the line between the centers, parameterized
// with arclength with t, height one one circle is
// hA(t)^2 = rA^2 - t^2
// Height on the other circle, where distance between them is d,
// hB(t)^2 = rB^2 - (t-d)^2
// We want hA == hB.
// We thus get
// rA^2 - t^2 = rB^2 - t^2 + 2td - d^2
// 2td = (rA^2 - rB^2 + d^2)
// t = (rA^2 - rB^2 + d^2) / 2d
// We can then sanity test t & directly compute the intersection.
float rA, rB, t, d, hA2, hB2;
UT_Vector2 cA, cB, v, perpv;
rA = ((EUC_Circle *)obja)->getRadius();
cA = ((EUC_Circle *)obja)->getCenter();
rB = ((EUC_Circle *)objb)->getRadius();
cB = ((EUC_Circle *)objb)->getCenter();
v = cB;
v -= cA;
d = v.length();
v.normalize();
if (!SYSequalZero(d))
{
// Non-zero difference, a chance for intersection.
t = (rA*rA - rB*rB + d*d) / (2.0 * d);
// Make sure neither of the squared heights are negative.
hA2 = rA*rA - t*t;
hB2 = rB*rB - (t-d)*(t-d);
if (hA2 >= 0 && hB2 >= 0)
{
// Get the perpindicular
perpv.x() = v.y();
perpv.y() = -v.x();
hA2 = SYSsqrt(hA2);
// Compute our new positions.
pos = cA + t * v + hA2 * perpv;
pt = new EUC_Point(pos);
applyLook(pt);
result.append(pt);
totalobj.append(pt);
pos = cA + t * v - hA2 * perpv;
pt = new EUC_Point(pos);
applyLook(pt);
result.append(pt);
totalobj.append(pt);
}
}
}
}
}
//
// EUC_ExprSelect
//
{
src->addRef();
mySource = src;
myIndex = idx;
}
EUC_ExprSelect::~EUC_ExprSelect()
{
}
void
EUC_ObjectList &totalobj)
{
EUC_ObjectList objlist;
result.setSize(0);
mySource->evaluateRecurse(objlist, totalobj);
if (myIndex >= 0 && myIndex < objlist.size())
result.append(objlist(myIndex));
}