Calculate the length of a segment of a quadratic bezier - math

I use this algorithm to calculate the length of a quadratic bezier:
http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/
However, what I wish to do is calculate the length of the bezier from 0 to t where 0 < t < 1
Is there any way to modify the formula used in the link above to get the length of the first segment of a bezier curve?
Just to clarify, I'm not looking for the distance between q(0) and q(t) but the length of the arc that goes between these points.
(I don't wish to use adaptive subdivision to aproximate the length)

Since I was sure a similar form solution would exist for that variable t case - I extended the solution given in the link.
Starting from the equation in the link:
Which we can write as
Where b = B/(2A) and c = C/A.
Then transforming u = t + b we get
Where k = c - b^2
Now we can use the integral identity from the link to obtain:
So, in summary, the required steps are:
Calculate A,B,C as in the original equation.
Calculate b = B/(2A) and c = C/A
Calculate u = t + b and k = c -b^2
Plug these values into the equation above.
[Edit by Spektre] I just managed to implement this in C++ so here the code (and working correctly matching naively obtained arc lengths):
float x0,x1,x2,y0,y1,y2; // control points of Bezier curve
float get_l_analytic(float t) // get arclength from parameter t=<0,1>
{
float ax,ay,bx,by,A,B,C,b,c,u,k,L;
ax=x0-x1-x1+x2;
ay=y0-y1-y1+y2;
bx=x1+x1-x0-x0;
by=y1+y1-y0-y0;
A=4.0*((ax*ax)+(ay*ay));
B=4.0*((ax*bx)+(ay*by));
C= (bx*bx)+(by*by);
b=B/(2.0*A);
c=C/A;
u=t+b;
k=c-(b*b);
L=0.5*sqrt(A)*
(
(u*sqrt((u*u)+k))
-(b*sqrt((b*b)+k))
+(k*log(fabs((u+sqrt((u*u)+k))/(b+sqrt((b*b)+k)))))
);
return L;
}
There is still room for improvement as some therms are computed more than once ...

While there may be a closed form expression, this is what I'd do:
Use De-Casteljau's algorithm to split the bezier into the 0 to t part and use the algorithm from the link to calculate its length.

You just have to evaluate the integral not between 0 and 1 but between 0 and t. You can use the symbolic toolbox of your choice to do that if you're not into the math. For instance:
http://integrals.wolfram.com/index.jsp?expr=Sqrt\[a*x*x%2Bb*x%2Bc\]&random=false
Evaluate the result for x = t and x = 0 and subtract them.

Related

Initial state starts at y(1), how to go backwards to find y(0)? [duplicate]

I would like to solve a differential equation in R (with deSolve?) for which I do not have the initial condition, but only the final condition of the state variable. How can this be done?
The typical code is: ode(times, y, parameters, function ...) where y is the initial condition and function defines the differential equation.
Are your equations time reversible, that is, can you change your differential equations so they run backward in time? Most typically this will just mean reversing the sign of the gradient. For example, for a simple exponential growth model with rate r (gradient of x = r*x) then flipping the sign makes the gradient -r*x and generates exponential decay rather than exponential growth.
If so, all you have to do is use your final condition(s) as your initial condition(s), change the signs of the gradients, and you're done.
As suggested by #LutzLehmann, there's an even easier answer: ode can handle negative time steps, so just enter your time vector as (t_end, 0). Here's an example, using f'(x) = r*x (i.e. exponential growth). If f(1) = 3, r=1, and we want the value at t=0, analytically we would say:
x(T) = x(0) * exp(r*T)
x(0) = x(T) * exp(-r*T)
= 3 * exp(-1*1)
= 1.103638
Now let's try it in R:
library(deSolve)
g <- function(t, y, parms) { list(parms*y) }
res <- ode(3, times = c(1, 0), func = g, parms = 1)
print(res)
## time 1
## 1 1 3.000000
## 2 0 1.103639
I initially misread your question as stating that you knew both the initial and final conditions. This type of problem is called a boundary value problem and requires a separate class of numerical algorithms from standard (more elementary) initial-value problems.
library(sos)
findFn("{boundary value problem}")
tells us that there are several R packages on CRAN (bvpSolve looks the most promising) for solving these kinds of problems.
Given a differential equation
y'(t) = F(t,y(t))
over the interval [t0,tf] where y(tf)=yf is given as initial condition, one can transform this into the standard form by considering
x(s) = y(tf - s)
==> x'(s) = - y'(tf-s) = - F( tf-s, y(tf-s) )
x'(s) = - F( tf-s, x(s) )
now with
x(0) = x0 = yf.
This should be easy to code using wrapper functions and in the end some list reversal to get from x to y.
Some ODE solvers also allow negative step sizes, so that one can simply give the times for the construction of y in the descending order tf to t0 without using some intermediary x.

Where can I find the Scilab balanc() function to calculate the similarity transform to program it in Maxima

I'm trying to program the z-transform in wxMaxima which doesn't have it programmed but not by definition but by using the Scilab approach. Scilab to calculate the z-transform first converts the transfer function to the state space, after that the system must be discretized and after that converted to z transfer function, I need this because of some algebraic calculations that I need to do to analyze stability of a system in function of the sample period.
Right now I'm stranded with the function balanc() which finds a similarity transform such that
Ab = X^(-1) . A . X
as approximately equal row and column norms.
Most of my code in wxMaxima to reach in the near future has been done by translating the Scilab code into wxMaxima, currently I'm writing the tf2ss() function an inside that function the balanc() function is called, the problem is that I couldn't find the code for that function in Scilab installation directory, I've searched info in books and papers but every example starts with the Ab matrix given as an input to the problem, Scilab instead has the option to have as an input only the A matrix and it calculates the Ab and X matrices, so, I need help to make this function exactly as Scilab has it programmed to been able to compare all the steps that I'm doing.
Finally, wxMaxima has a function to calculate similarity transforms but it don't have the same output as Scilab what it means to me that they uses different criteria to calculate the similarity transform.
Note: I've tried to make the calculations in wxMaxima to have Ab and X matrices as elements with variables but the system of equations remains with too many variables and couldn't be solved.
Thanks in advance for the help in doing this.
In Scilab balanc() is hard-coded and based on LAPACK's dgebal (see the Fortran source at Netlib). In the algorithm the operations are quite simple (computing inf and 2-norms, swaping columns or rows of a matrix), maybe this could easily translated ?
A more readable version of the algorithm can be found on page 3 (Algorithm 2) of the following document: https://arxiv.org/abs/1401.5766.
Here is a Scilab implementation of Algorithm 3:
function [A,X]=bal(Ain)
A = Ain;
n = size(A,1);
X = ones(n,1);
β = 2; // multiply or divide by radix preserves precision
p = 2; // eventually change to 1-norm
converged = 0;
while converged == 0
converged = 1;
for i=1:n
c = norm(A(:,i),p);
r = norm(A(i,:),p);
s = c^p+r^p;
f = 1;
while c < r/β
c = c*β;
r = r/β;
f = f*β;
end
while c >= r*β
c = c/β;
r = r*β;
f = f/β;
end
if (c^p+r^p) < 0.95*s
converged = 0;
X(i) = f*X(i);
A(:,i) = f*A(:,i);
A(i,:) = A(i,:)/f;
end
end
end
X = diag(X);
endfunction
On this example the above implementation gives the same balanced matrix:
--> A=rand(5,5,"normal"); A(:,1)=A(:,1)*1024; A(2,:)=A(2,:)/1024
A =
897.30729 -1.6907865 -1.0217046 -0.9181476 -0.1464695
-0.5430253 -0.0011318 -0.0000356 -0.001277 -0.00038
-774.96457 3.1685332 0.1467254 -0.410953 -0.6165827
155.22118 0.1680727 -0.2262445 -0.3402948 1.6098294
1423.0797 -0.3302511 0.5909125 -1.2169245 -0.7546739
--> [Ab,X]=balanc(A)
Ab =
897.30729 -0.8453932 -32.694547 -14.690362 -9.3740507
-1.0860507 -0.0011318 -0.0022789 -0.0408643 -0.0486351
-24.217643 0.0495083 0.1467254 -0.2054765 -1.2331655
9.7013239 0.0052523 -0.452489 -0.3402948 6.4393174
22.23562 -0.0025801 0.2954562 -0.3042311 -0.7546739
X =
0.03125 0. 0. 0. 0.
0. 0.015625 0. 0. 0.
0. 0. 1. 0. 0.
0. 0. 0. 0.5 0.
0. 0. 0. 0. 2.
--> [Ab,X]=bal(A)
Ab =
897.30729 -0.8453932 -32.694547 -14.690362 -9.3740507
-1.0860507 -0.0011318 -0.0022789 -0.0408643 -0.0486351
-24.217643 0.0495083 0.1467254 -0.2054765 -1.2331655
9.7013239 0.0052523 -0.452489 -0.3402948 6.4393174
22.23562 -0.0025801 0.2954562 -0.3042311 -0.7546739
X =
1. 0. 0. 0. 0.
0. 0.5 0. 0. 0.
0. 0. 32. 0. 0.
0. 0. 0. 16. 0.
0. 0. 0. 0. 64.

With known parameters in equation, how to calculate a third unknown one

The following equation f(t)= b*pow(1-exp(-k*t), b-1) – (b-1)*pow(1-exp(-k*t), b) is used to describe a curve.
When f(t)=0.5 with known b and k, how to calculate it in R?
b*pow(1-exp(-k*t),b-1) –(b-1)*pow(1-exp(-k*t),b) = 0.5
e.g. when b=5, k=0.5, t=?
You could use uniroot, but first plot the function to check for roots, if any. I extract 0.5 from the function, since that is what you want to solve for. Plotting shows that there are two roots, so you have to play with th interval in the uniroot function. I'll leave that to you, let me know if you struggle with it.
f <- function(x)
{
b=5
k=0.5
return( b* (1- exp(-k*x))^(b-1) - (b-1) * (1-exp(-k*x))^b -0.5 )
}
uniroot(f, interval = c(0, 1e+08))

SVM: Why is Maximize margin == minimize Euclidean norm?

In the SVM opimization problem, we either want to maximise the margin of 2/||w||,
or minimise the Euclidean Norm of weight vector w:
(1/2)*w^t*w
Can somebody explain to me why the Euclidean Norm is the formula above? And not 1/sqrt(w^t*w)?
I assume euclidean norm is the Euclidean distance, how do we get to that formula?
The reason is that the following three are equivalent (under suitable mathematical conditions which are usually met):
Maximize a quantity z.
Maximize f(z), where f is a strictly growing function.
Minimize g(z), where g is a strictly decreasing function.
In your case, set z=||w||, and apply the above the other way round. Then minimizing||w|| is equivalent to minimizing f(z) = 1/2 ||w||^2, and to maximizing g(z) = 2/||w||.
We have two boundaries 𝑤⋅𝑥+𝑏=1 and 𝑤⋅𝑥+𝑏=−1 and a middle one which is 𝑤⋅𝑥+𝑏=0. Now we want to figure out the distance between each of these two lines with the middle one. If we call the distance 𝜆.
We consider a point z on 𝑤⋅𝑥+𝑏=1, then setting this point z as the origin, the point on 𝑤⋅𝑥+𝑏=0 would be 𝑧−𝜆⋅𝑤||𝑤||, here, the distance between the middle line and 𝑤⋅𝑥+𝑏=1 is the distance between z and 𝑧−𝜆⋅𝑤||𝑤||
now since this point is on 𝑤⋅𝑥+𝑏=0, we would have:
𝑤⋅(𝑧−𝜆⋅𝑤 / ||𝑤||)+𝑏 = 0
𝑤⋅𝑧+𝑏 −𝑤⋅𝜆⋅𝑤 / ||𝑤|| = 0
we know that since z is located on 𝑤⋅𝑥+𝑏=1, then 𝑤⋅𝑧+𝑏 equals 1, hence:
1 −𝑤⋅𝜆⋅𝑤 / ||𝑤|| = 0
𝑤⋅𝜆⋅𝑤 / ||𝑤|| = 1
𝜆 ⋅ ||𝑤||^2 / ||𝑤|| = 1
𝜆 ⋅ ||𝑤|| = 1
𝜆 = 1/||𝑤||

Fast, inaccurate sin function without lookup

For an ocean shader, I need a fast function that computes a very approximate value for sin(x). The only requirements are that it is periodic, and roughly resembles a sine wave.
The taylor series of sin is too slow, since I'd need to compute up to the 9th power of x just to get a full period.
Any suggestions?
EDIT: Sorry I didn't mention, I can't use a lookup table since this is on the vertex shader. A lookup table would involve a texture sample, which on the vertex shader is slower than the built in sin function.
It doesn't have to be in any way accurate, it just has to look nice.
Use a Chebyshev approximation for as many terms as you need. This is particularly easy if your input angles are constrained to be well behaved (-π .. +π or 0 .. 2π) so you do not have to reduce the argument to a sensible value first. You might use 2 or 3 terms instead of 9.
You can make a look-up table with sin values for some values and use linear interpolation between that values.
A rational algebraic function approximation to sin(x), valid from zero to π/2 is:
f = (C1 * x) / (C2 * x^2 + 1.)
with the constants:
c1 = 1.043406062
c2 = .2508691922
These constants were found by least-squares curve fitting. (Using subroutine DHFTI, by Lawson & Hanson).
If the input is outside [0, 2π], you'll need to take x mod 2 π.
To handle negative numbers, you'll need to write something like:
t = MOD(t, twopi)
IF (t < 0.) t = t + twopi
Then, to extend the range to 0 to 2π, reduce the input with something like:
IF (t < pi) THEN
IF (t < pi/2) THEN
x = t
ELSE
x = pi - t
END IF
ELSE
IF (t < 1.5 * pi) THEN
x = t - pi
ELSE
x = twopi - t
END IF
END IF
Then calculate:
f = (C1 * x) / (C2 * x*x + 1.0)
IF (t > pi) f = -f
The results should be within about 5% of the real sine.
Well, you don't say how accurate you need it to be. The sine can be approximated by straight lines of slopes 2/pi and -2/pi on intervals [0, pi/2], [pi/2, 3*pi/2], [3*pi/2, 2*pi]. This approximation can be had for the cost of a multiplication and an addition after reducing the angle mod 2*pi.
Using a lookup table is probably the best way to control the tradeoff between speed and accuracy.

Resources