catmull-rom length

Started by
16 comments, last by DonTzzy 10 years, 9 months ago

It means it isn't worth converting it to C++ ;) Use numerical methods to find the length.

The length of a curve y = f(x) between x = a and x = b is

integral(from a to b)(sqrt(1 + (dy/dx)2)) which is not a nice thing to integrate analytically. (EDIT: Because of the square root. It would be easy for polynomials if the sqrt wasn't there).

Wikipedia page about it is here: https://en.wikipedia.org/wiki/Arc_length

EDIT2: So, for the simple function y = x3 the integration involves complex numbers, inverse hyperbolic sin function, and elliptic integrals. Not nice at all ;)

The arc length for a parabola y = x2 is a little bit nicer, http://www.wolframalpha.com/input/?i=integral%28sqrt%281+%2B+4x^2%29%29 , it only involves inverse hyperbolic sin (asinh)... which is now standard in cmath with C++11, but it wasn't in cmath as standard before that.

EDIT3: It's easy for y = x though, here is the full working for that.

Arc length for y = x:

dy/dx = 1

integral(sqrt(1 + (dy/dx)2)) = integral(sqrt(1 + 12)) = integral(sqrt(1 + 1)) = integral(sqrt(2)) = x * sqrt(2) + constant. (note: the integral is with respect to x)

so for arc length between a and b the answer is integrate(a to b)(sqrt(2)) = F(b) - F(a) where F(x) = integral(sqrt(2)) = x * sqrt(2) + c

= b * sqrt(2) + c - (a * sqrt(2) + c) = (b-a)sqrt(2) + (c - c) = (b-a)sqrt(2)

so arc length from 0 to 1 of y = x is (1 - 0)sqrt(2) = sqrt(2) as expected.

EDIT4: Lots of edits ;)

EDIT5: Last edit, I promise. The derivation of the arc length for a parabola is explained here http://planetmath.org/arclengthofparabola

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley
Advertisement

Compute the integral numerically using something like an adaptive version of Simpson's rule. That's probably what I would do.

Yeah, I'd recommend that too. If there is a parametric way to get approx. constant speed I'd use that to find the intervals to sum the line length over. I was just pointing out how impractical and difficult an analytic approach would be (length of a parabola involves hyperbolic trig functions, and length of a cubic involves special functions i.e. elliptic integrals).

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

Here is what I am currently using:


void ApproximateCatMullRomLength3D(double *Length,const D3DXVECTOR3* p0, const D3DXVECTOR3* p1, const D3DXVECTOR3* p2, const D3DXVECTOR3* p3){
	D3DXVECTOR3 v0,v1;
	v0=*p1;
	*Length=0;
	for (int t=1;t<1000;t++){
		float time=t/1000.0f;
		CatmullRom_Evaluate(&v1,p0,p1,p2,p3,time);//a simple CMR function
		*Length+=double(D3DXVec3Length(&(v1-v0)));
		v0=v1;
	}
}

All it does is evaluate 1000 points along the curve and sums up the lengths between each one..... I may not need that many samples, but I'm using 1000 until I get something that works right in my AutoPilot function.

Ok. Picture time:

This illustrates what I am trying to do (as best as I can draw it). I originally have all the "waypoints" calculated for avoidance of an object represented here as "start", "wp1", "wp2", and "end". I then calculate the CMR points by shooting vectors from the WP to its neighbors (or start/end). I'm doing the calc for WP1 in this illustration..... The inner control points (p1 and p2) are determined by some max half-way length and placed in-line between their respective WPs. The outer control points (p0 and p3) are simply shot out using the same vectors but the length is a multiple of the "max half-way length" I determined earlier. The multiple I use gives varying results of sometimes strange curves. I think I'm doing it wrong..... You may be thinking I should just use the waypoints as the control points, but that won't work in most cases for my application......

If it is for avoidance definitely go with the control points not being on the spline. The convex hull of the 4 control points always contains the spline, so as long that doesn't intersect your object you are guaranteed the spline won't intersect the object. I think you need 2 control points between each waypoint rather than just one though. You can see the diagram is going to be incorrect since the convex hull formed by p0, p1, p2, p3 intersects your object.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

I think I didn't explain my second image correctly. There are 4 separate examples in it. Each one is a different example of the multiplier I use. Here is the code. I have since modified it and it works a little better with the mod:

(In the code "p#" is "CV#" representing the control points)


void AUTOPILOT::CalculateCurves(SHIP *Ship){
	if (WP.size()<2) return;//no need to do the function
	for (UINT wp=0;wp<WP.size()-1;wp++){
		//find the max distance. max is shortest WP away from WP[wp]
		D3DXVECTOR3 dir1,dir2;
		double dist;
		if (wp==0){//wp-1 is the ship's location
			HUGEVECTOR3 hvDir1=Ship->V_Location-WP[wp].vWP;
			dir1=hvDir1.Normalize();
			dist=hvDir1.Length/2.50;
		}
		else {
			HUGEVECTOR3 hvDir1=WP[wp-1].vWP-WP[wp].vWP;
			dir1=hvDir1.Normalize();
			dist=hvDir1.Length/2.50;
		}
		HUGEVECTOR3 hvDir2=WP[wp+1].vWP-WP[wp].vWP;
		dir2=hvDir2.Normalize();
		double dist2=hvDir2.Length/2.0;
		if (dist2<dist) dist=dist2;
		if (dist>WP[wp].MaxAllowedVel*10.0) dist=WP[wp].MaxAllowedVel*10.0;

		WP[wp].CV1=dir1;
		WP[wp].CV1*=float(dist);
		WP[wp].CV0=dir1*6.0f*float(dist);
		WP[wp].CV2=dir2;
		WP[wp].CV2*=float(dist);
		WP[wp].CV3=dir2*6.0f*float(dist);//this one WAS *8.0
              //***************
              //this is part of the modification
		dir1=WP[wp].CV0-WP[wp].CV3;
		dir1/=6.0f;
		WP[wp].CV0-=dir1;
		WP[wp].CV3+=dir1;
              //********************

		ApproximateCatMullRomLength3D(&WP[wp].CurveSize,&WP[wp].CV0,&WP[wp].CV1,&WP[wp].CV2,&WP[wp].CV3);
	}
}

I annotated where I changed the position of CV0 & CV3 and my "multiplier" is x6. This gives me a more gradual curve between CV1 &CV2.

.

This topic is closed to new replies.

Advertisement