1

I have two 3D points: (x1, y1, z1) and (x3, y3, z3) and want to find a point (x2, y2, z2) on that line given z2, which is between z1 and z3.

Here is what I have currently:

#include<math.h>
#include<stdlib.h>
#include<stdio.h>

double *findPoint (double x1, double y1, double z1, double x3, double y3, double z3, double z2)
{
  double *ret = malloc(3 * sizeof(double));
  double dot = (x1 * x3) + (y1 * y3) + (z1 * z3);
  printf("dot %e\n", dot);
  double magprd = ((x1 * x1) + (y1 * y1) + (z1 * z1)) * ((x3 * x3) + (y3 * y3) + (z3 * z3));
  printf("magprd %e\n", magprd);
  double angle = acos(dot / magprd);
  printf("angle %e\n", angle);
  double distance = z2 / asin(angle);
  printf("distance %e\n", distance);
  double x2 = x1 - ((distance * x1) / 3);
  double y2 = y1 - ((distance * y1) / 3);
  ret[0] = x2;
  ret[1] = y2;
  ret[2] = z2;

  return ret;
}

int main() {
    // return pointer to array containing x2, y2, z2 corresponding to
    // z=4 on line between point at x1, y1, z1 and x3, y3, z3
    double *p = findPoint(1, 2, 3, 11, 12, 13, 4);

    if(p) {
        printf("point on line at z=4 is %e, %e, %e\n", p[0], p[1], p[2]);
        free(p);
    }

    return 0;
}

This doesn't work properly, though:

$ clang -lm test.c -o test
$ ./test 
dot 7.400000e+01
magprd 6.076000e+03
angle 1.558617e+00
distance nan
point on line at z=4 is nan, nan, 4.000000e+00

How can I fix findPoint so that it solves this problem? Thanks!

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62

2 Answers2

2

You math looks very complicated. I would suggest this code:

typedef struct { double x,y,z; } Point;

Point findPoint(Point a, Point b, double z) {
    double dx = b.x - a.x;
    double dy = b.y - a.y;
    double dz = b.z - a.z;
    if(dz == 0.0) {
        // ERROR
        return (Point){ 0,0,0 };
    }
    double p = (z - a.z) / dz;
    return (Point){ a.x + p*dx, a.y + p*dy, a.z + p*dz };
}

If you do not want to use by value I suggest this:

int findPoint(const Point* a, const Point* b, double z, Point* c) {
    double dx = b->x - a->x;
    double dy = b->y - a->y;
    double dz = b->z - a->z;
    if(dz == 0.0) {
        // ERROR
        return 0;
    }
    double p = (z - a.z) / dz;
    c->x = a.x + p*dx;
    c->y = a.y + p*dy;
    c->z = a.z + p*dz };
    return 1;
}

Point* a = malloc(sizeof(Point));
a->x = 1;
a->y = 2;
a->z = 3;
Point* b = malloc(sizeof(Point));
b->x = 11;
b->y = 12;
b->z = 13;
Point* c = malloc(sizeof(Point));
if(findPoint(a,b,4,c)) {
    printf("Result: %e %e %e\n", c->x, c->y, c->z);
}
else {
    printf("Error!\n");
}
Danvil
  • 22,240
  • 19
  • 65
  • 88
  • Should return value be prototyped as `Point *`? – ryyker Apr 10 '14 at 20:45
  • Lol, - maybe. I have just never returned a non-pointer from a function. I will have to try it. Regardless, I like the simplicity of your function (answer). – ryyker Apr 10 '14 at 20:59
  • I found ***[this link](http://stackoverflow.com/a/1454992/645128)*** which expands on what I was trying to ask... Although may not be completely relevant, as topic address array, not struct. – ryyker Apr 10 '14 at 21:05
  • Thanks! Struct to define Point is a great idea. – user3519634 Apr 10 '14 at 21:30
  • @ryyker: I think the tradeoff is, that passing/returning by values copies data. You can as well use pointers. But then i would use this signature `int findPoint(const Point* a, const Point* b, double z, Point* c)`. So that the function does actually not have to allocate memory. You can also use the return type to indicate failure. – Danvil Apr 10 '14 at 21:46
  • @Danvil - I agree with your assessment on _tradeoff_, and how to re-prototype the function to avoid memory issues. I habitually use pointers when dealing with `struct` data types, due mainly to the large amount of data they hold, and frequency of calls made passing them. These conditions do not always warrant using pointers, but often enough. By the way, nice answer. +1. – ryyker Apr 14 '14 at 19:48
1

You can simplify your function to

double *findPoint (double x1, double y1, double z1, double x3, double y3, double z3, double z2)
{
    double *ret = malloc(3 * sizeof(double));

    double tmp = (z2 - z1)/(z3 - z1); // Assuming that z1 != z3
    double x2 = x1 + tmp * (x3 - x1);
    double y2 = y1 + tmp * (y3 - y1);
    ret[0] = x2;
    ret[1] = y2;
    ret[2] = z2;

    return ret;
}

That gives the result

point on line at z=4 is 2.000000e+00, 3.000000e+00, 4.000000e+00
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Nice answer. But in OP (before OP edited it) is it not true that the local scope of `p` in `main()` would have prevented it from accepting the return of findPoint ? – ryyker Apr 10 '14 at 20:58
  • @ryyker: No. The return value of findPoint() is a pointer to the allocated memory. That pointer is assigned to p. – Martin R Apr 10 '14 at 21:02
  • Thanks, I see your point now. Assigning `double *p` equal to a function prototyped `double * func(...);` will work as long as memory is allocated properly in called function. I put the comment here because I deleted my answer. (it was misleading) – ryyker Apr 10 '14 at 21:12
  • Awesome! Great solution! Also, switched it back to malloc in findPoint, thanks! – user3519634 Apr 10 '14 at 21:23