I need to find the smallest number of steps it takes to get between two points in a grid. If you are positioned at the center, and you can only move in 8 directions to the integer points surrounding you, then what's the least number of steps to take to get to a destination point?
I have a solution for this, but it is massively ugly and I'm honestly a bit ashamed of it:
/**
* #details Each point in the graph is a linear combination of these vectors:
*
* [x] = a[0] + b[1] + c[1] + d[ 1]
* [y] [1] [1] [0] [-1]
*
* EQ1: c + b + d == x
* EQ2: a + b - d == y
*
* Any path can be simplified to involve at most two of these variables, so we
* can solve the linear equations above with the knowledge that at least two of
* a, b, c, and d are 0. The sum of the absolute value of the coefficients is
* the number of steps taken in the grid.
*/
unsigned min_distance(point_t start, point_t goal)
{
int a, b, c, d;
int swap, steps;
int x, y;
x = goal.x - start.x;
y = goal.y - start.y;
/* Possible simple shortcuts */
if (x == 0 || y == 0) {
steps = abs(x) + abs(y);
} else if (abs(x) == abs(y)) {
steps = abs(y);
} else {
b = x, a = y - b;
steps = abs(a) + abs(b);
c = x, a = y;
swap = abs(a) + abs(c);
if (steps > swap)
steps = swap;
d = x, a = y + d;
swap = abs(a) + abs(d);
if (steps > swap)
steps = swap;
b = y, c = x - b;
swap = abs(b) + abs(c);
if (steps > swap)
steps = swap;
b = (x + y) / 2, d = b - y;
swap = abs(b) + abs(d);
if ((x + y) % 2 == 0 && steps > swap)
steps = swap;
d = -y, c = x - d;
swap = abs(c) + abs(d);
if (steps > swap)
steps = swap;
}
return steps;
}
The comment at the top explains the actual algorithm: represent each valid step as a column vector in a matrix, then find the smallest solution to the resulting system of linear equations.
In this case I saw the best answer would use at most two variables, and solved the equation six times by setting different combinations of the variables to 0. That's too specific! I want to be able to change the rules about which steps are valid and still be able to find the min distance.
EDIT: I realize this is a very poor simple example of what I'm trying to do, because of how easy it is to simplify the problem in this case. The goal is to calculate the number of steps given arbitrary stepping rules. If it the allowed steps instead looked like this then I'd start with a different matrix ([0 2 3 4 x; 1 2 0 -4 y]) and find the least solution to a different system of equations (2b + 3c + 4d = x, a + 2b - 4d = y). I'm actually trying to write a procedure that can work with any set of vectors to find the minimum number of steps.
...Any advice or criticism?
Related
Given the array: A[N]. There are some queries including Li and Ri. We must Find the number that appears more than (Ri-Li+1)/2 times in range [Li:Ri].
For example:
INPUT:
N=7
1 1 3 2 3 4 3
OUTPUT:
Ranges:
[1:3] ans is :>1
[1:4] no answer
[1:7] ans is :>3
[2:7] no answer
First, I think we can use map to store the times that A[i] appears from 1 to j
And it's take up a lot of memories if N up to 5e5.
Then I sort(Increasing order) the queries so that Ri, and no more idea.
Suggestions:
Is there any efficient algorithm to this problem or any data structure to stores the frequency of A[i]: from 1 to j?
I have no idea about such data structure, but I find an solution for this problem.
If Ri - Li + 1 is odd, there may have two elements appear (Ri - Li + 1) / 2 times. Which one do you want to get? We can use the algorithm beblow to get one of them and the algorithm can get all of these two if you want.
If there are just few queries satisfy \sum (Ri - Li) are small enough, get the answer for each [Li, Ri] separately.
For each [Li, Ri],we can use a O(Ri - Li) time, O(1) auxiliary memory algorithm to get the answer. If there is a x appears exactly (Ri - Li + 1) / 2 times, at least one of three case below must happend (suppose Ri > Li).
x appears (Ri - Li + 1) / 2 times in [Li, Ri - 1].
x appears (Ri - Li + 1) / 2 times in [Li + 1, Ri].
A[Li] == A[Ri] == x.
For case 1,2 we can use 'Heavy Hitters' algorithm to find the candidate x.
So can get three candidate x for one travese, and check each of them to find the answer(see cpp code below).
int getCandidateX(int L, int R) {
int x = A[L], count = 1;
for(int i = L + 1; i <= R; ++i){
if(A[i] == x) ++count;
else if(--count == 0){
x = A[i];
count = 1;
}
}
return x;
}
int getFrequency(int L, int R, int x) {
int count = 0;
for(int i = L; i <= R; ++i) {
if(A[i] == x) ++count;
}
return count;
}
/**
* if Ri == Li, no answer
* suppose Ri > Li
* return {x, 0} and {-1,-1} if no such element
*/
pair<int,int> getAnswer(int Li, int Ri) {
int t = (Ri - Li + 1) / 2;
int x;
if((Ri - Li) & 1) {
x = getCandidateX(Li, Ri);
if(getFrequency(Li, Ri, x) == t) return {x, 0};
return {-1, -1}
}
x = getCandidateX(Li, Ri - 1);
if(getFrequency(Li, Ri, x) == t) return {x, 0};
x = getCandidateX(Li + 1, Ri);
if(getFrequency(Li, Ri, x) == t) return {x, 0};
if(A[Li] == A[Ri] && getFrequency(Li, Ri, A[Li]) == t)
return {Li, 0};
return {-1,-1}
}
When \sum (Ri - Li) is large, I found an O((m + n)logn) online solution, but it also cost a lot of memory. I conduct it as a RMQ(Range Maximum Query) problem and solve it by ST(sparse table) algorithm.
First, we can get the frequency in [L, R] of any x with O(logn) time.
We can store all the position of x in map[x] where map maps x to its position array.(we can use treemap or hashmap)
Then we can get the frequency of x in [L, R] by binary search which cost O(logn) time.
Define num[L][R] be a set of elements appear more than (R - L + 1) / 4 times in interavl [L,R]. Let val[i][k] = num[L][L + 2^k - 1], k >= 2.
Every val[i][k] has at most 4 elements, and we can calculate all val[i][k] for 0 <= i <= n and i + 2^k <= n in O(nlogn) time and O(nlogn) memory.
Because for every interval [L,R] and M1, M2 such that L <= M < R it is obvious to see that num[L][R] \subset num[L][M] \cup num[M + 1][R]. Then val[i][k] \subset val[i][k - 1] \cup val[i + 2^{k - 1} - 1][k - 1]`.
Let t as the greatest number such that 2^t <= R - L + 1 we can draw a conclusion that if x \in [L,R] appears not less than (R - L + 1) / 2 times,x must in val[L][t] or val[R - 2^t + 1][R]。
This means it is sufficient to check the frequency of every element in val[L][t] \cup val[R - 2^t - 1][t].
For every query [L,R] we can check every element in O(logn) time, so the total time is O((m + n)logn) where n is the element number of A and m is the query number.
If the question is to get the element appears exactly (Ri-Li+1)/2 + 1 times (or more), it can be solve in a more simply way.
My try
double sum_squares_from(double x, double n){
return n<=0 ? 0 : x*x + sum_squares_from((x+n-1)*(x+n-1),n-1);
}
Instead of using loops my professor wants us to write functions like this...
What the exercise asks for is a function sum_squares_from() with double x being the starting number and n is the number of number. For example if you do x = 2 and n = 4 you get 2*2+3*3+4*4+5*5. It returns zero if n == 0.
My thinking was that in my example what I have is basically x*x+(x+1)(x+1)+(x+1+1)(x+1+1)+(x+1+1+1)(x+1+1+1) = (x+0)(x+0)+(x+1)(x+1)+(x+2)(x+2)+(x+3)(x+3) = (x+n-1)^2 repeated n times where n gets decremented every time by one until it becomes zero and then you sum everything.
Did I do it right?
(if my professor seems a bit demanding... he somehow does this sort of thing all in his head without auxiliary calculations. Scary guy)
It's not recursive, but it's one line:
int
sum_squares(int x, int n) {
return ((x + n - 1) * (x + n) * (2 * (x + n - 1) + 1) / 6) - ((x - 1) * x * (2 * (x - 1) + 1) / 6);
}
Sum of squares (of integers) has a closed-form solution for 1 .. n. This code calculates the sum of squares from 1 .. (x+n) and then subtracts the sum of squares from 1 .. (x-1).
The original version of this answer used ASCII art.
So,
∑i:0..n i = n(n+1)(½)
∑i:0..n i2 = n(n+1)(2n+1)(⅙)
We note that,
∑i:0..n (x+i)2
= ∑i:0...n x2 + 2xi + i2
= (n+1)x2 + (2x)∑i:0..n i + ∑i:0..n i2
= (n+1)x2 + n(n+1)x + n(n+1)(2n+1)(⅙)
Thus, your sum has the closed form:
double sum_squares_from(double x, int n) {
return ((n-- > 0)
? (n + 1) * x * x
+ x * n * (n + 1)
+ n * (n + 1) * (2 * n + 1) / 6.
: 0);
}
If I apply some obfuscation, the one-line version becomes:
double sum_squares_from(double x, int n) {
return (n-->0)?(n+1)*(x*x+x*n+n*(2*n+1)/6.):0;
}
If the task is to implement the summation in a loop, use tail recursion. Tail recursion can be mechanically replaced with a loop, and many compilers implement this optimization.
static double sum_squares_from_loop(double x, int n, double s) {
return (n <= 0) ? s : sum_squares_from_loop(x+1, n-1, s+x*x);
}
double sum_squares_from(double x, int n) {
return sum_squares_from_loop(x, n, 0);
}
As an illustration, if you observe the generated assembly in GCC at a sufficient optimization level (-Os, -O2, or -O3), you will notice that the recursive call is eliminated (and sum_squares_from_loop is inlined to boot).
Try it online!
As mentioned in my original comment, n should not be type double, but instead be type int to avoid floating point comparison problems with n <= 0. Making the change and simplifying the multiplication and recursive call, you do:
double sum_squares_from(double x, int n)
{
return n <= 0 ? 0 : x * x + sum_squares_from (x + 1, n - 1);
}
If you think about starting with x * x and increasing x by 1, n times, then the simple x * x + sum_squares_from (x + 1, n - 1) is quite easy to understand.
Maybe this?
double sum_squares_from(double x, double n) {
return n <= 0 ? 0 : (x + n - 1) * (x + n - 1) + sum_squares_from(x, n - 1);
}
I'm trying to understand the implementation of the Shamir's Secret Sharing Scheme from this (old) implementation on github, and I'm struggling with Horner's rule in extended fields GF(p^n):
void horner(int n, mpz_t y, const mpz_t x, const mpz_t coeff[])
{
int i;
mpz_set(y, x);
for(i = n - 1; i; i--) {
field_add(y, y, coeff[i]);
field_mult(y, y, x);
}
field_add(y, y, coeff[0]);
}
Why does add come first and only then mult? What's the algorithm? Why not something like:
mpz_set(y,coeff[n-1]);
for(i = n - 2; i!=-1; i--) {
field_mult(y, y, x);
field_add(y,y,coeff[i]);
}
Translating this horner function with normal addition and multiplication symbols, we get:
y = x; // mpz_set(y, x);
for(i = n - 1; i; i--) {
y = y + coeff[i]; // field_add(y, y, coeff[i]);
y = y * x // field_mult(y, y, x);
}
y = y + coeff[0] // field_add(y, y, coeff[0]);
Hence this computes the following:
You can see it does not compute any polynomial, but it is a variant of Horner's algorithm to compute a monic polynomial.
Now what you propose:
y = coeff[n-1]; // mpz_set(y,coeff[n-1]);
for(i = n - 2; i!=-1; i--) {
y = y * x; // field_mult(y, y, x);
y = y + coeff[i]; // field_add(y,y,coeff[i]);
}
Thus you compute the following:
You can see the highest-order term is missing.
If you want to have all the operations inside the body of the loop, you can.
After all, it's only two ways of decomposing a series of alternating instructions differently:
operation value of y loop iteration
add-mult loop mult-add loop
x initialization n-1
add x + coeff[n-1] n-1 n-1
mult (x + coeff[n-1]) * x n-1 n-2
add (x + coeff[n-1]) * x + coeff[n-2] n-2 n-2
mult ((x + coeff[n-1]) * x + coeff[n-2]) * x n-2 n-3
...etc...
But you need to explicitly initialize y to the value 1 (which is the implicit coeff[n]) so that you can start by multiplying by x and get the correct highest-order term.
y = 1; // mpz_set(y,1);
for(i = n - 1; i!=-1; i--) { // NOTICE n - 1 NOT n - 2
y = y * x; // field_mult(y, y, x);
y = y + coeff[i]; // field_add(y,y,coeff[i]);
}
You can count that you now perform one more multiplication, and it is multiplying 1 * x. On a finite field this is typically done with log and antilog tables, so you might as well avoid such a useless multiplication, especially if you're going to evaluate polynomials a lot.
TL;DR: This way of writing Horner's algorithm puts the last addition and the first multiplication outside of the loop's body. Because the highest-order coefficient is 1 this multiplication is then completely removed.
To clarify: the highest-order term is kept, but is then x^n instead of being 1 * x^n. You spare one multiplication for the exact same result.
Having some trouble optimizing a function that returns the number of neighbors of a cell in a Conway's Game of Life implementation. I'm trying to learn C and just get better at coding. I'm not very good at recognizing potential optimizations, and I've spent a lot of time online reading various methods but it's not really clicking for me yet.
Specifically I'm trying to figure out how to unroll this nested for loop in the most efficient way, but each time I try I just make the runtime longer.
I'm including the function, I don't think any other context is needed. Thanks for any advice you can give!
Here is the code for the countNeighbors() function:
static int countNeighbors(board b, int x, int y)
{
int n = 0;
int x_left = max(0, x-1);
int x_right = min(HEIGHT, x+2);
int y_left = max(0, y-1);
int y_right = min(WIDTH, y+2);
int xx, yy;
for (xx = x_left; xx < x_right; ++xx) {
for (yy = y_left; yy < y_right; ++yy) {
n += b[xx][yy];
}
}
return n - b[x][y];
}
Instead of declaring board as b[WIDTH][HEIGHT] declare it as b[WIDTH + 2][HEIGHT + 2]. This gives an extra margin which will have zeros, but it prevents from index out of bounds. So, instead of:
x x
x x
We will have:
0 0 0 0
0 x x 0
0 x x 0
0 0 0 0
x denotes used cells, 0 will be unused.
Typical trade off: a bit of memory for speed.
Thanks to that we don't have to call min and max functions (which have bad for performance if statements).
Finally, I would write your function like that:
int countNeighborsFast(board b, int x, int y)
{
int n = 0;
n += b[x-1][y-1];
n += b[x][y-1];
n += b[x+1][y-1];
n += b[x-1][y];
n += b[x+1][y];
n += b[x-1][y+1];
n += b[x][y+1];
n += b[x+1][y+1];
return n;
}
Benchmark (updated)
Full, working source code.
Thanks to Jongware comment I added linearization (reducing array's dimensions from 2 to 1) and changing int to char.
I also made the main loop linear and calculate the returned sum directly, without an intermediate n variable.
2D array was 10002 x 10002, 1D had 100040004 elements.
The CPU I have is Pentium Dual-Core T4500 at 2.30 GHz, further details here (output of cat /prof/cpuinfo).
Results on default optimization level O0:
Original: 15.50s
Mine: 10.13s
Linear: 2.51s
LinearAndChars: 2.48s
LinearAndCharsAndLinearLoop: 2.32s
LinearAndCharsAndLinearLoopAndSum: 1.53s
That's about 10x faster compared to the original version.
Results on O2:
Original: 6.42s
Mine: 4.17s
Linear: 0.55s
LinearAndChars: 0.53s
LinearAndCharsAndLinearLoop: 0.42s
LinearAndCharsAndLinearLoopAndSum: 0.44s
About 15x faster.
On O3:
Original: 10.44s
Mine: 1.47s
Linear: 0.26s
LinearAndChars: 0.26s
LinearAndCharsAndLinearLoop: 0.25s
LinearAndCharsAndLinearLoopAndSum: 0.24s
About 44x faster.
The last version, LinearAndCharsAndLinearLoopAndSum is:
typedef char board3[(HEIGHT + 2) * (WIDTH + 2)];
int i;
for (i = WIDTH + 3; i <= (WIDTH + 2) * (HEIGHT + 1) - 2; i++)
countNeighborsLinearAndCharsAndLinearLoopAndSum(b3, i);
int countNeighborsLinearAndCharsAndLinearLoopAndSum(board3 b, int pos)
{
return
b[pos - 1 - (WIDTH + 2)] +
b[pos - (WIDTH + 2)] +
b[pos + 1 - (WIDTH + 2)] +
b[pos - 1] +
b[pos + 1] +
b[pos - 1 + (WIDTH + 2)] +
b[pos + (WIDTH + 2)] +
b[pos + 1 + (WIDTH + 2)];
}
Changing 1 + (WIDTH + 2) to WIDTH + 3 won't help, because compiler takes care of it anyway (even on O0 optimization level).
An analytical solution for cubic bezier length
seems not to exist, but it does not mean that
coding a cheap solution does not exist. By cheap I mean something like in the range of 50-100 ns (or less).
Does someone know anything like that? Maybe in two categories:
1) less error like 1% but more slow code.
2) more error like 20% but faster?
I scanned through google a bit but it doesn't
find anything which looks like a nice solution. Only something like divide on N line segments
and sum the N sqrt - too slow for more precision,
and probably too inaccurate for 2 or 3 segments.
Is there anything better?
Another option is to estimate the arc length as the average between the chord and the control net. In practice:
Bezier bezier = Bezier (p0, p1, p2, p3);
chord = (p3-p0).Length;
cont_net = (p0 - p1).Length + (p2 - p1).Length + (p3 - p2).Length;
app_arc_length = (cont_net + chord) / 2;
You can then recursively split your spline segment into two segments and calculate the arc length up to convergence. I tested myself and it actually converges pretty fast. I got the idea from this forum.
Simplest algorithm: flatten the curve and tally euclidean distance. As long as you want an approximate arc length, this solution is fast and cheap. Given your curve's coordinate LUT—you're talking about speed, so I'm assuming you use those, and don't constantly recompute the coordinates—it's a simple for loop with a tally. In generic code, with a dist function that computes the euclidean distance between two points:
var arclength = 0,
last=LUT.length-1,
i;
for (i=0; i<last; i++) {
arclength += dist(LUT[i], LUT[i+1]);
}
Done. arclength is now the approximate arc length based on the maximum number of segments you can form in the curve based on your LUT. Need things faster with a larger potential error? Control the segment count.
var arclength = 0,
segCount = ...,
last=LUT.length-2,
step = last/segCount,
s, i;
for (s=0; s<=segCount; s++) {
i = (s*step/last)|0;
arclength += dist(LUT[i], LUT[i+1]);
}
This is pretty much the simplest possible algorithm that still generates values that come even close to the true arc length. For anything better, you're going to have to use more expensive numerical approaches (like the Legendre-Gauss quadrature technique).
If you want to know why, hit up the arc length section of "A Primer on Bézier Curves".
in my case a fast and valid approach is this. (Rewritten in c# for Unity3d)
public static float BezierSingleLength(Vector3[] points){
var p0 = points[0] - points[1];
var p1 = points[2] - points[1];
var p2 = new Vector3();
var p3 = points[3]-points[2];
var l0 = p0.magnitude;
var l1 = p1.magnitude;
var l3 = p3.magnitude;
if(l0 > 0) p0 /= l0;
if(l1 > 0) p1 /= l1;
if(l3 > 0) p3 /= l3;
p2 = -p1;
var a = Mathf.Abs(Vector3.Dot(p0,p1)) + Mathf.Abs(Vector3.Dot(p2,p3));
if(a > 1.98f || l0 + l1 + l3 < (4 - a)*8) return l0+l1+l3;
var bl = new Vector3[4];
var br = new Vector3[4];
bl[0] = points[0];
bl[1] = (points[0]+points[1]) * 0.5f;
var mid = (points[1]+points[2]) * 0.5f;
bl[2] = (bl[1]+mid) * 0.5f;
br[3] = points[3];
br[2] = (points[2]+points[3]) * 0.5f;
br[1] = (br[2]+mid) * 0.5f;
br[0] = (br[1]+bl[2]) * 0.5f;
bl[3] = br[0];
return BezierSingleLength(bl) + BezierSingleLength(br);
}
I worked out the closed form expression of length for a 3 point Bezier (below). I've not attempted to work out a closed form for 4+ points. This would most likely be difficult or complicated to represent and handle. However, a numerical approximation technique such as a Runge-Kutta integration algorithm (see my Q&A here for details) would work quite well by integrating using the arc length formula.
Here is some Java code for the arc length of a 3 point Bezier, with points a,b, and c.
v.x = 2*(b.x - a.x);
v.y = 2*(b.y - a.y);
w.x = c.x - 2*b.x + a.x;
w.y = c.y - 2*b.y + a.y;
uu = 4*(w.x*w.x + w.y*w.y);
if(uu < 0.00001)
{
return (float) Math.sqrt((c.x - a.x)*(c.x - a.x) + (c.y - a.y)*(c.y - a.y));
}
vv = 4*(v.x*w.x + v.y*w.y);
ww = v.x*v.x + v.y*v.y;
t1 = (float) (2*Math.sqrt(uu*(uu + vv + ww)));
t2 = 2*uu+vv;
t3 = vv*vv - 4*uu*ww;
t4 = (float) (2*Math.sqrt(uu*ww));
return (float) ((t1*t2 - t3*Math.log(t2+t1) -(vv*t4 - t3*Math.log(vv+t4))) / (8*Math.pow(uu, 1.5)));
public float FastArcLength()
{
float arcLength = 0.0f;
ArcLengthUtil(cp0.position, cp1.position, cp2.position, cp3.position, 5, ref arcLength);
return arcLength;
}
private void ArcLengthUtil(Vector3 A, Vector3 B, Vector3 C, Vector3 D, uint subdiv, ref float L)
{
if (subdiv > 0)
{
Vector3 a = A + (B - A) * 0.5f;
Vector3 b = B + (C - B) * 0.5f;
Vector3 c = C + (D - C) * 0.5f;
Vector3 d = a + (b - a) * 0.5f;
Vector3 e = b + (c - b) * 0.5f;
Vector3 f = d + (e - d) * 0.5f;
// left branch
ArcLengthUtil(A, a, d, f, subdiv - 1, ref L);
// right branch
ArcLengthUtil(f, e, c, D, subdiv - 1, ref L);
}
else
{
float controlNetLength = (B-A).magnitude + (C - B).magnitude + (D - C).magnitude;
float chordLength = (D - A).magnitude;
L += (chordLength + controlNetLength) / 2.0f;
}
}
first of first you should Understand the algorithm use in Bezier,
When i was coding a program by c# Which was full of graphic material I used beziers and many time I had to find a point cordinate in bezier , whic it seem imposisble in the first look. so the thing i do was to write Cubic bezier function in my costume math class which was in my project. so I will share the code with you first.
//--------------- My Costum Power Method ------------------\\
public static float FloatPowerX(float number, int power)
{
float temp = number;
for (int i = 0; i < power - 1; i++)
{
temp *= number;
}
return temp;
}
//--------------- Bezier Drawer Code Bellow ------------------\\
public static void CubicBezierDrawer(Graphics graphics, Pen pen, float[] startPointPixel, float[] firstControlPointPixel
, float[] secondControlPointPixel, float[] endPointPixel)
{
float[] px = new float[1111], py = new float[1111];
float[] x = new float[4] { startPointPixel[0], firstControlPointPixel[0], secondControlPointPixel[0], endPointPixel[0] };
float[] y = new float[4] { startPointPixel[1], firstControlPointPixel[1], secondControlPointPixel[1], endPointPixel[1] };
int i = 0;
for (float t = 0; t <= 1F; t += 0.001F)
{
px[i] = FloatPowerX((1F - t), 3) * x[0] + 3 * t * FloatPowerX((1F - t), 2) * x[1] + 3 * FloatPowerX(t, 2) * (1F - t) * x[2] + FloatPowerX(t, 3) * x[3];
py[i] = FloatPowerX((1F - t), 3) * y[0] + 3 * t * FloatPowerX((1F - t), 2) * y[1] + 3 * FloatPowerX(t, 2) * (1F - t) * y[2] + FloatPowerX(t, 3) * y[3];
graphics.DrawLine(pen, px[i - 1], py[i - 1], px[i], py[i]);
i++;
}
}
as you see above, this is the way a bezier Function work and it draw the same Bezier as Microsoft Bezier Function do( I've test it). you can make it even more accurate by incrementing array size and counter size or draw elipse instead of line& ... . All of them depend on you need and level of accuracy you need and ... .
Returning to main goal ,the Question is how to calc the lenght???
well The answer is we Have tons of point and each of them has an x coorinat and y coordinate which remember us a triangle shape & especially A RightTriabgle Shape. so if we have point p1 & p2 , we can calculate the distance of them as a RightTriangle Chord. as we remeber from our math class in school, in ABC Triangle of type RightTriangle, chord Lenght is -> Sqrt(Angle's FrontCostalLenght ^ 2 + Angle's SideCostalLeghth ^ 2);
and there is this relation betwen all points we calc the lenght betwen current point and the last point before current point(exmp p[i - 1] & p[i]) and store sum of them all in a variable. lets show it in code bellow
//--------------- My Costum Power Method ------------------\\
public static float FloatPower2(float number)
{
return number * number;
}
//--------------- My Bezier Lenght Calculator Method ------------------\\
public static float CubicBezierLenghtCalculator(float[] startPointPixel
, float[] firstControlPointPixel, float[] secondControlPointPixel, float[] endPointPixel)
{
float[] tmp = new float[2];
float lenght = 0;
float[] px = new float[1111], py = new float[1111];
float[] x = new float[4] { startPointPixel[0], firstControlPointPixel[0]
, secondControlPointPixel[0], endPointPixel[0] };
float[] y = new float[4] { startPointPixel[1], firstControlPointPixel[1]
, secondControlPointPixel[1], endPointPixel[1] };
int i = 0;
for (float t = 0; t <= 1.0; t += 0.001F)
{
px[i] = FloatPowerX((1.0F - t), 3) * x[0] + 3 * t * FloatPowerX((1.0F - t), 2) * x[1] + 3F * FloatPowerX(t, 2) * (1.0F - t) * x[2] + FloatPowerX(t, 3) * x[3];
py[i] = FloatPowerX((1.0F - t), 3) * y[0] + 3 * t * FloatPowerX((1.0F - t), 2) * y[1] + 3F * FloatPowerX(t, 2) * (1.0F - t) * y[2] + FloatPowerX(t, 3) * y[3];
if (i > 0)
{
tmp[0] = Math.Abs(px[i - 1] - px[i]);// calculating costal lenght
tmp[1] = Math.Abs(py[i - 1] - py[i]);// calculating costal lenght
lenght += (float)Math.Sqrt(FloatPower2(tmp[0]) + FloatPower2(tmp[1]));// calculating the lenght of current RightTriangle Chord & add it each time to variable
}
i++;
}
return lenght;
}
if you wish to have faster calculation just need to reduce px & py array lenght and loob count.
We also can decrease memory need by reducing px and py to array lenght to 1 or make a simple double variable but becuase of Conditional situation Happend which Increase Our Big O I didn't do that.
Hope it helped you so much. if have another question just ask.
With Best regards, Heydar - Islamic Republic of Iran.