Hello I have a problem which I believe is very difficult to solve, I was searching everywhere for solution but I didn't find anything.
I want to draw profiles from list of points.
My problem is:
- I have a list of Points3D from text file, they arent in any order, just like random points. Of course I added them to List. I draw those points in 3D space using small 3D Ellipses. So far so good.
- Now I want to draw a 3D spline going through all the points from list. So i created class Spline3D which is using cubic interpolation to determine positions of points of curve between given points from text file. In my spline I calculate say like 400 new points then I am drawing small 3D Cylinders between each pair of points: point i and point i+1 have small cylinder betwen them + the cylinders are rotated properly so everything is looking like real spline (in theory).
The main problem is that points are unordered so if I am just doing that I get spline like this:
http://img5.imageshack.us/img5/4659/2b61.jpg
the raw points draw in space look like this:
http://img194.imageshack.us/img194/9016/hv8e.jpg
http://img5.imageshack.us/img5/659/nsz1.jpg
So i figure out that I have two solutions
Put points in some sort of order, then add them to Spline3D and calculate spline.
Calculate spline in some other way, which probably lead to order points in some way, so basically it still lead me to 1.
So I tried some kinds of reordering methods.
1. a) Nearest neighbor of point
int firstIndex = (new Random().Next(pointsCopy.Count));//0;//pointsCopy.Count / 2;//(new Random().Next(pointsCopy.Count));
NPoint3D point = pointsCopy[firstIndex];
pointsCopy.Remove(point);
spline3D.addPoint(point.ToPoint3D());
NPoint3D closestPoint = new NPoint3D();
double distance;
double nDistance;
Point3D secondPoint = new Point3D();
bool isSecondPoint = true;
while (pointsCopy.Count != 0)
{
distance = double.MaxValue;
for (int i = 0; i < pointsCopy.Count; i++)
{
nDistance = point.distanceToPoint(pointsCopy[i]);
if (nDistance < distance)
{
distance = nDistance;
closestPoint = pointsCopy[i];
}
}
if (isSecondPoint)
{
isSecondPoint = false;
secondPoint = closestPoint.ToPoint3D();
}
spline3D.addPoint(closestPoint.ToPoint3D());
point = closestPoint;
pointsCopy.Remove(closestPoint);
}
spline3D.addPoint(points[firstIndex].ToPoint3D()); //first point is also last point
This was my first idea, I thought that this will became ultimate solution to my problem. I choose randomly one point from list of points and this point became first point to spline. Then I find the closest point to this previous point I add him to spline and remove from list and so on...
http://img18.imageshack.us/img18/3650/mik0.jpg
http://img706.imageshack.us/img706/3834/u97b.jpg
Sadly sometimes (especially near edges of my profile) point down is closer then point near, so spline became there crooked.
2. b) TSP
distanceMatrix = new TSP.DistanceMatrix(pointsCopy, NPoint3D.distanceBetweenTwoPoints);
int[] indexes = TSP.Algorithms.TSPgreedySearch(distanceMatrix);
for (int i = 0; i < indexes.Length; i++)
spline3D.addPoint(pointsCopy[indexes[i]].ToPoint3D());
spline3D.addPoint(pointsCopy[indexes[0]].ToPoint3D());
Basically I use traveling salesman problem algorithm to determine shortest spline (shortest path) through all the points. Sadly this problem is NP-Hard, so to get good performance I use some heuristics.
http://img198.imageshack.us/img198/714/xiqy.jpg
http://img839.imageshack.us/img839/9530/exnu.jpg
Spline looks better than in 1.a but still it isn't enough.
3. c) Some weird methods using two splines
Some of my friends told me that I should split profile in two parts (upper-part and lower-part) and then calculate and draw two splines. Sadly I dont know how to do that, I mean I don't know how to determine if point should be in upper-part or lower-part. Please help me.
So how could I solve this problem? Any ideas?