THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 17/03/2009 at 12:43, xxxxxxxx wrote:
Well, first you need a LineObject which can be tricky. Here is the routine I used for IvyGrower to get the proper one from a Spline of some sort:
> // Prepare spline (primitive to real, consider deformers) \> //\*---------------------------------------------------------------------------\* \> Bool Ivy::PrepareSpline(SplineObject\* sobj) \> //\*---------------------------------------------------------------------------\* \> { \> Matrix mg = sobj->GetMg(); \> // GetRealSpline (returns self if already 'real') \> Bool free = FALSE; \> SplineObject\* test = sobj->GetRealSpline(); \> if (!test) return ErrorException::Throw(GeLoadString(SIVY_ERR_GENERAL), "Ivy.PrepareSpline.GetRealSpline"); \> if (test != sobj) \> { \> // Clone Spline \> sobj = ToSpline(sobj->GetClone(0L, NULL)); \> if (!sobj) return ErrorException::Throw(GeLoadString(SIVY_ERR_GENERAL), "Ivy.PrepareSpline.GetClone"); \> // MakeEditable \> ModelingCommandData mcd; \> mcd.doc = doc; \> mcd.op = sobj; \> mcd.mode = 0L; \> if (!SendModelingCommand(MCOMMAND_MAKEEDITABLE, mcd)) \> { \> return ErrorException::Throw(GeLoadString(SIVY_ERR_GENERAL), "Ivy.PrepareSpline.SendModelingCommand(MAKEEDITABLE)"); \> } \> sobj = ToSpline(mcd.result->GetIndex(0L)); \> if (!sobj) return ErrorException::Throw(GeLoadString(SIVY_ERR_GENERAL), "Ivy.PrepareSpline.sobj"); \> free = TRUE; \> } \> // CurrentStateToObject obj \> ModelingCommandData mcd; \> BaseContainer mbc; \> mbc.SetBool(MDATA_CURRENTSTATETOOBJECT_INHERITANCE, TRUE); \> mbc.SetBool(MDATA_CURRENTSTATETOOBJECT_KEEPANIMATION, FALSE); \> #ifdef C4D_R95 \> mbc.SetBool(MDATA_CURRENTSTATETOOBJECT_NOGENERATE, FALSE); \> #endif // C4D_R95 \> mcd.doc = doc; \> mcd.flags = 0L; \> mcd.bc = &mbc; \> mcd.mode = MODIFY_ALL; \> mcd.op = sobj; \> if (!SendModelingCommand(MCOMMAND_CURRENTSTATETOOBJECT, mcd)) \> { \> if (free) SplineObject::Free(sobj); \> return ErrorException::Throw(GeLoadString(SIVY_ERR_GENERAL), "Ivy.PrepareSpline.SendModelingCommand(CURRENTSTATETOOBJECT)"); \> } \> if (free) SplineObject::Free(sobj); \> SplineObject\* cstoObj = static_cast<SplineObject\*>(mcd.result->GetIndex(0L)); \> if (!cstoObj) return ErrorException::Throw(GeLoadString(SIVY_ERR_GENERAL), "Ivy.PrepareSpline.cstoObj"); \> // Get LineObject \> followSpline = cstoObj->GetLineObject(doc, 1.0f, NULL); \> SplineObject::Free(cstoObj); \> if (!followSpline) return ErrorException::Throw(GeLoadString(SIVY_ERR_GENERAL), "Ivy.PrepareSpline.GetLineObject()"); \> if (!followSpline->GetSegmentCount()) \> { \> LineObject::Free(followSpline); \> followSpline = NULL; \> return ErrorException::Throw(GeLoadString(SIVY_ERR_GENERAL), "Ivy Grower doesn't support following multi-segmented splines"); \> } \> followSPtCnt = followSpline->GetPointCount(); \> #ifdef C4D_R10 \> followSPoint = followSpline->GetPointW(); \> #else \> followSPoint = followSpline->GetPoint(); \> #endif \> if ((followSPtCnt < 2L) || !followSPoint) \> { \> LineObject::Free(followSpline); \> followSpline = NULL; \> return ErrorException::Throw(GeLoadString(SIVY_ERR_GENERAL), "Ivy.PrepareSpline.followSPoint"); \> } \> // Apply global matrix to points \> for (LONG n = 0L; n != followSPtCnt; ++n) \> { \> followSPoint[n] \*= mg; \> } \> // Always considering pairs of points (line segments) \> --followSPtCnt; \> \> return TRUE; \> }
And then here you can see how I test for distance. Not optimized for speed in any way (always tests all line segments) :
> // Get the distance of a line segment from a Sphere surface. \> // Input: a Line Segment P0-P1 and a Sphere C,r \> // Return: whether or not line segment is outside sphere \> // Pn contains the closest point on the line segment \> // dist contains the shortest distance from P0-P1 to C,r \> //\*---------------------------------------------------------------------------\* \> Bool DistanceSegmentSphere(const Vector& P0, const Vector& P1, const Vector& C, const Real r, Vector& Pn, Real& dist) \> //\*---------------------------------------------------------------------------\* \> { \> Vector v = P1 - P0; \> Vector w = C - P0; \> \> double c1 = w \* v; \> if (c1 > 0.0) \> { \> double c2 = v \* v; \> if (c1 < c2) \> { \> c1 /= c2; \> Pn = P0 + c1 \* v; \> } \> else Pn = P1; \> } \> else Pn = P0; \> \> v = C-Pn; \> // Inside sphere \> if (Len(v) < r) return FALSE; \> // Outside/on sphere \> dist = Sqrt(v\*v); \> return TRUE; \> } \> //\*---------------------------------------------------------------------------\* \> Bool Ivy::computeTowardsSpline(const Real& floatLength, const Vector& oldPos, Vector& newPos, Bool& climbing) \> //\*---------------------------------------------------------------------------\* \> { \> Vector nearPt = newPos; \> Vector segPt; \> Real r = Len(newPos-oldPos); \> Real minDistance = MAXREAL; \> Real distance; \> \> climbing = FALSE; \> for (LONG n = 0L; n != followSPtCnt; ++n) \> { \> // LineSegment-Sphere Distance calculation - return if a line segment is found to be interpenetrating sphere \> if (!DistanceSegmentSphere(followSPoint[n], followSPoint[n+1], oldPos, r, segPt, distance)) \> { \> climbing = TRUE; \> return TRUE; \> } \> if (distance >= minDistance) continue; \> minDistance = distance; \> nearPt = segPt; \> } \> // get a point along line segment 'nearPt to newPos' using a 0.0 to 1.0 parameter (splineWeight with some random variation) \> nearPt = !(nearPt - oldPos); \> newPos = !(newPos - oldPos); \> segPt = newPos + ((nearPt - newPos) \* splineWeight \* rand() \* irand); \> newPos = (!segPt \* r) + oldPos; \> climbing = (minDistance <= floatLength); \> return climbing; \> }
Hope that helps a bit. 