0

Let say I've 5 points, where p0 and p4 are fixed with values 0.0 and 4.0:

0 | 1.0 | 2.0 | 3.0 | 4

The points in the middle can change, but they must stretch the others once moving.

So for a stretch "to right", it must enlarge the prev values around the moving point and press the next ones between the moving point and the last point, keeping the proportions between each points.

I've write this code which move the 3° point to 2.5 from its original 2.0 x-position:

const int numPoints = 5;
double points[numPoints] = { 0.0, 1.0, 2.0, 3.0, 4.0 };

int stretchedPoint = 2;
double prevX = points[stretchedPoint];
points[stretchedPoint] = 2.5;

std::cout<< points[0];
for (int prevPoint = 1; prevPoint < numPoints - 1; prevPoint++) {
    // prev points
    if (prevPoint < stretchedPoint) {
        double ratio = points[stretchedPoint] / prevX;
        points[prevPoint] *= ratio;
    // next points
    } else if (prevPoint > stretchedPoint) {
        double ratio = (points[numPoints - 1] - prevX) / (points[numPoints - 1] - points[stretchedPoint]);
        points[prevPoint] *= ratio;
    }

    std::cout << " | " << points[prevPoint];
}
std::cout << " | " << points[numPoints - 1];

which give to me right result for prev points:

0 | 1.25 | 2.5 | 0.76 | 4

but when I try to apply the "same-wrapped-math" for the next points, I get a non-proportional scaling, which give weird results (4?)

Can anyone help me?

markzzz
  • 47,390
  • 120
  • 299
  • 507

2 Answers2

1

You forgot about non-zero starting point

 points[prevPoint] = points[stretchedPoint] + ratio * (points[prevPoint] - prevX)

Note that same logic should be applied to previos points, if start value is non-zero

In general, to apply linear interpolation for initial X0..X1 interval and final X0new..X1new interval, one have to use

 (Xnew - X0new) / (X1new - X0new) = (X - X0) / (X1 - X0)
 so
 XNew = X0new + (X1new - X0new) * (X - X0) / (X1 - X0)
MBo
  • 77,366
  • 5
  • 53
  • 86
  • Uhm, which ratio do you use? 0.96 now here http://coliru.stacked-crooked.com/a/f5671e6fbfba8419 – markzzz Apr 19 '17 at 10:33
  • 3,25 is wrong anyway! The proportional is not kept. – markzzz Apr 19 '17 at 10:49
  • your coliru example uses 0.1 0.2 0.3 values instead of 1,2,3. 3.25 is middle between 2.5 and 4 like 3 was middle between 2 and 4 - proportionality preserves – MBo Apr 19 '17 at 10:53
  • Yes, but see the A.S.H answer: it should be `2.53947` (duality on stretching). – markzzz Apr 19 '17 at 10:56
  • It is true for 0.1 0.2 0.3 input data: http://coliru.stacked-crooked.com/a/cb243e3b41095346 `0 | 1.25 | 2.5 | 2.53947 | 4` – MBo Apr 19 '17 at 10:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/142072/discussion-between-paizza-and-mbo). – markzzz Apr 19 '17 at 11:00
1

What you did on the left side of the point (and which is working) can be rewritten somehow like this:

//  double ratio = (points[stretchedPoint] - 0) / (prevX - 0);
//  points[prevPoint] = 0 + ratio * (points[prevPoint] - 0);

To achieve exactly the dual on the right side, it should be:

} else if (prevPoint > stretchedPoint) {
    double ratio = (points[numPoints - 1] - points[stretchedPoint]) /
         (points[numPoints - 1] - prevX);
    points[prevPoint] = points[numPoints - 1] -
        ratio * (points[numPoints-1] - points[prevPoint]);
}
A.S.H
  • 29,101
  • 5
  • 23
  • 50
  • Your algo seems to works perfect. Is the "linear interpolation" formula suggested by @MBo? p.s. warning to `points[prevPoint])` typo – markzzz Apr 19 '17 at 10:50
  • 1
    Well in fact, yes, it is the correct linear transformation. Also not that to start with any point on the left side instead of zero, you can take the commented code and replace `0` by `points[0]` – A.S.H Apr 19 '17 at 11:03