Why the 2D spline graph is incorrect? - python-3.x

I started getting into spline principles to use them in my studies. However, I got stuck in programming the code for Wikipedia [example] . The final graph doesn't correspond to the Wiki's example. I get two curves that are not connected, despite the introduction of the parameter t(x):
Spline segments
Would you mind helping me in finding the cause of the error? Thanks.
import numpy as np
import matplotlib.pyplot as plt
x0, y0, x1, y1, x2, y2 = -1, 0.5, 0, 0, 3, 3
def spline(x0, y0, x1, y1, x2, y2):
a11 = 2 / (x1 - x0)
a12 = 1 / (x1 - x0)
a13 = 0
a21 = a12
a22 = 2 * (1 / (x1 - x0) + 1 / (x2 - x1))
a23 = 1 / (x2 - x1)
a31 = a13
a32 = a23
a33 = 2 / (x2 - x1)
b1 = 3 * ((y1 - y0) / (x1 - x0) ** 2)
b2 = 3 * ((y1 - y0) / (x1 - x0) ** 2 + (y2 - y1) / (x2 - x1) ** 2)
b3 = 3 * ((y2 - y1) / (x2 - x1) ** 2)
A = np.array([[a11, a12, a13], [a21, a22, a23], [a31, a32, a33]])
L = np.array([[-b1], [-b2], [-b3]])
AT = np.transpose(A)
ATA = np.matmul(AT, A)
invATA = np.linalg.inv(ATA)
ATL = np.matmul(AT, L)
X = - np.matmul(invATA, ATL)
[k0, k1, k2] = X
a1 = k0 * (x1 - x0) - (y1 - y0)
b1 = -k1 * (x1 - x0) + (y1 - y0)
a2 = k1 * (x2 - x1) - (y2 - y1)
b2 = -k2 * (x2 - x1) + (y2 - y1)
return a1[0], b1[0], a2[0], b2[0]
a1, b1, a2, b2 = spline(-1, 0.5, 0, 0, 3, 3)
def q1(t):
return (1 - t) * y0 + t * y1 + t *(1 - t) * ((1 - t) * a1 + t * b1)
def q2(t):
return (1 - t) * y1 + t * y2 + t *(1 - t) * ((1 - t) * a2 + t * b2)
x_list = []
y1_list = []
y2_list = []
for x in range(1000):
t = (x/1000 - x1) / (x2 - x1)
x_list.append(x)
y1_list.append(q1(t))
y2_list.append(q2(t))
plt.scatter(x_list, y1_list)
plt.scatter(x_list, y2_list)

I found it! The key was the proper x-range corresponding to the 3 given points.
import numpy as np
import matplotlib.pyplot as plt
x0, y0, x1, y1, x2, y2 = -1, 0.5, 0, 0, 3, 3
def spline(x0, y0, x1, y1, x2, y2):
a11 = 2 / (x1 - x0)
a12 = 1 / (x1 - x0)
a13 = 0
a21 = a12
a22 = 2 * (1 / (x1 - x0) + 1 / (x2 - x1))
a23 = 1 / (x2 - x1)
a31 = a13
a32 = a23
a33 = 2 / (x2 - x1)
b1 = 3 * ((y1 - y0) / (x1 - x0) ** 2)
b2 = 3 * ((y1 - y0) / (x1 - x0) ** 2 + (y2 - y1) / (x2 - x1) ** 2)
b3 = 3 * ((y2 - y1) / (x2 - x1) ** 2)
A = np.array([[a11, a12, a13], [a21, a22, a23], [a31, a32, a33]])
L = np.array([[-b1], [-b2], [-b3]])
AT = np.transpose(A)
ATA = np.matmul(AT, A)
invATA = np.linalg.inv(ATA)
ATL = np.matmul(AT, L)
X = - np.matmul(invATA, ATL)
[k0, k1, k2] = X
a1 = k0 * (x1 - x0) - (y1 - y0)
b1 = -k1 * (x1 - x0) + (y1 - y0)
a2 = k1 * (x2 - x1) - (y2 - y1)
b2 = -k2 * (x2 - x1) + (y2 - y1)
return a1[0], b1[0], a2[0], b2[0]
a1, b1, a2, b2 = spline(-1, 0.5, 0, 0, 3, 3)
def q1(t):
return (1 - t) * y0 + t * y1 + t *(1 - t) * ((1 - t) * a1 + t * b1)
def q2(t):
return (1 - t) * y1 + t * y2 + t *(1 - t) * ((1 - t) * a2 + t * b2)
x1_list = []
x2_list = []
y1_list = []
y2_list = []
for x in range(-1000, 0, 1):
t = (x/1000 - x0) / (x1 - x0)
x1_list.append(x)
y1_list.append(q1(t))
for x in range(3000):
t = (x/1000 - x1) / (x2 - x1)
x2_list.append(x)
y2_list.append(q2(t))
plt.scatter(x1_list, y1_list)
plt.scatter(x2_list, y2_list)

Related

Allocating values in Haskell

Im very new to haskell and I have to define the elliptic curve functions from the RFC6090 Definition in Haskell. (RFC6090: https://www.rfc-editor.org/rfc/rfc6090#section-3)
For that I have to implement a function called ecAdd.
ecAdd returns values from the type ECPoint. I defined them but Im not sure why the values x1 and x2 are not recognized. I get the following error for every section where x1,x2,y1 or y2 appears.
error:
• Couldn't match expected type ‘(Double -> Double) -> Fq -> Fq’
with actual type ‘galois-field-1.0.0:Data.Field.Galois.Prime.Prime
Q’
• The function ‘y2 - y1’ is applied to two arguments,
but its type ‘galois-field-1.0.0:Data.Field.Galois.Prime.Prime Q’
has none
In the first argument of ‘(^)’, namely
‘((y2 - y1) recip (x2 - x1))’
In the first argument of ‘(-)’, namely
‘((y2 - y1) recip (x2 - x1)) ^ 2’
|
64 | x3 = ((y2 - y1) recip (x2 - x1))^2 - x1 - x2
Here is my function code
ecAdd
:: ECPoint -- ^ Punkt P
-> ECPoint -- ^ Punkt Q
-> ECPoint -- ^ Ergebnis P + Q
ecAdd q O = q
ecAdd O p = p
ecAdd (A x1 y1) (A x2 y2) =
if (A x1 y1) /= (A x2 y2)
then
if x1 == x2
then O
else let x3 = ((y2-y1) recip (x2-x1))^2 - x1 - x2
y3 = (x1-x3)*(y2-y1) recip (x2-x1) - y1 in A x3 y3
else
if y1 == 0
then O
else let x4 = ((3*x1^2 + P256K1._a) recip (2*y1))^2 - 2*x1
y4 = (x1-x3)*(3*x1^2 + P256K1._a) recip (2*y1) - y1
in A x4 y4

Rotate array of points according one point

I have 4 points and angle (as shown on the picture). How to get new point values for rotated object?
picture(x/y axis inverted, mistake. Vertical should be Y, horizontal - X)
At first, get coordinates relative to the rotation origin (x0, y0)
x' = x1 - x0
y' = y1 - y0
Then rotate
x'' = x' * Cos(Fi) - y' * Sin(Fi)
y'' = x' * Sin(Fi) + y' * Cos(Fi)
And now shift coordinates back
x_r = x'' + x0
y_r = y'' + y0

calculate distance between two points (Haskell)

Given an input of two tupples, i want to be able to calculate the distance between two points using the formula:
distance = sqrt ( (x1 - x2) ^ 2 + (y1 - y2) ^2 )
so i want the function call and output to look like this:
-- > distance (5 , 10) (3 , 5)
-- 5.385...
when i try to run my code below, it tells me parse error on input 'where'. Can anyone help me resolve my issue? Here is my code:
distance (x1 , y1) (x2 , y2) = sqrt (x'*x' + y'*y')
where
x' = x1 - x2
y' = y1 - y2
You are making an indendation error, this should work- see how where clause is indented:
distance (x1 , y1) (x2 , y2) = sqrt (x'*x' + y'*y')
where
x' = x1 - x2
y' = y1 - y2

Interpolation of a triangle

I have a unit right triangle and a value at each of the 3 vertices.
I need to interpolate to find the value at a point inside the triangle.
Hours of searching have turned up nothing that actually tells me how to do this.
Here is my closest attempt, which is actually pretty close but not quite right -
result =
v1 * (1 - x) * (1 - y) +
v2 * x * (1 - y) +
v3 * x * y;
v1, v2, and v3 are the values at the 3 vertices of the triangle.
(x, y) is the point in the triangle that you are trying to find the value of.
Any kind of method would help me here. It doesn't necessarily need to be a unit/right triangle.
Updated info:
I have a grid of evenly spaced points and a value at each point.
I make a triangle out of the nearest 3 points on the grid.
Here is a picture to illustrate it -
So I have to interpolate between 5, 3, and 7 to find the value of x.
The point could also be inside the other triangle, meaning you would interpolate between 5, 7, and the value of the bottom left corner of the square.
In the code I showed, v1 = 5, v2 = 3, v3 = 7.
x is the fractional distance (range [0-1]) in the "x" direction, and y is the fractional distance in the "y" direction.
In the picture's example, x would probably be about 0.75 and y would be about 0.2
Here are my closest attempts -
Created using -
if (x > y) //if x > y then the point is in the upper right triangle
return
v1 * (1 - x) * (1 - y) +
v2 * x * (1 - y) +
v3 * x * y;
else //bottom left triangle
return
v1 * (1 - x) * (1 - y) +
v4 * (1 - x) * y +
v3 * x * y;
And another attempt -
Created using -
if (x > y)
return
(1 - x) * v1 + (x - y) * v2 + y * v3;
else
return
(1 - y) * v1 + (y - x) * v4 + x * v3;
They're both close to what I need but obviously not quite right.
You should use barycentric coordinates. There is a very thorough write-up here that also discusses alternative solutions and why barycentric coordinates are best: CodePlea - Interpolating in a Triangle
Basically, the weights will end up looking like this:
Actually the simplest and most robust solution is based on barycentric coordinates -
http://answers.unity3d.com/questions/383804/calculate-uv-coordinates-of-3d-point-on-plane-of-m.html
I asked this 3 years ago and have still been working on a way to do this. I do believe it is impossible to do it without artifacts unless using an equilateral triangle.
Here is a decent way to do it using barycentric coordinates and then adding a technique that gets rid of most of the artifacts.
v1, v2, v3 are the values at the three points of the triangle. x, y is the point you want to find a value for.
if (x > y)
{
b1 = -(x - 1);
b2 = (x - 1) - (y - 1);
b3 = 1 - b1 - b2;
}
else
{
b1 = -(y - 1);
b2 = -((x - 1) - (y - 1));
b3 = 1 - b1 - b2;
}
float
abs = x - y;
if (abs < 0) abs *= -1;
if (abs < 0.25f)
{
abs = 0.25f - abs;
abs *= abs;
b1 -= abs;
b3 -= abs;
}
b1 *= b1;
b2 *= b2;
b3 *= b3;
float fd = 1 / (b1 + b2 + b3);
b1 *= fd;
b2 *= fd;
b3 *= fd;
return
v1 * b1 +
v2 * b2 +
v3 * b3;
Ok, so we will do a linear interpolation, assuming that the gradient is constant with respect to x and to y. d/dx = v2 - v1 and d/dy = v3 - v2, and f(0,0) = v1. We have a simple two dimensional differential equation.
d{f(x,y)} = (v2 - v1)*dx
f(x,y) = (v2 - v1)*x + g(y)
d{f(x,y)} = g'(y) = (v3 - v2)*dy
g(y) = (v3 - v2)*y + C
f(x,y) = (v2 - v1)*x + (v3 - v2)*y + C
f(0,0) = v1 = (v2 - v1)*0 + (v3 - v2)*0 + C = C
f(x,y) = (v2 - v1)*x + (v3 - v2)*y + v1
or in terms of v1 v2 and v3
f(x,y) = (1 - x)*v1 + (x - y)*v2 + y*v3
If you want to do it in a square for four vertices, as above with v4 in the bottom left at x=0 y=1, here are the conditions: d/dx = (v2 - v1) (1 - y) + (v3 - v4) y, d/dy = (v3 - v2) x + (v4 - v1) (1 - x), f(0,0) = v1
d/dx = (v2 - v1) (1 - y) + (v3 - v4) y
f(x,y) = (v2 - v1) (1 - y) x + (v3 - v4) y x + g(y)
d/dy = (v3 - v2) x + (v4 - v1) (1 - x) = -(v2 - v1) x + (v3 - v4) x + g'(y)
v3 - v2 + (v4 - v1) / x + v4 - v1 = -v2 + v1 + v3 - v4 + g'(y) / x
(v4 - v1) / x + 2*(v4 - v1) = g'(y) / x
g'(y) = (v4 - v1) + 2 x (v4 - v1)
g(y) = (v4 - v1) (1 + 2 x) y + C
f(x,y) = (v2 - v1) (1 - y) x + (v3 - v4) y x + (v4 - v1) (1 + 2 x) y + C
f(0,0) = (v2 - v1) (1 - 0) 0 + (v3 - v4) 0 0 + (v4 - v1) (1 + 2 0) 0 + C = v1
f(x,y) = (v2 - v1) (1 - y) x + (v3 - v4) y x + (v4 - v1) (1 + 2 x) y + v1
Here is some pseudocode for nearest-neighbor:
if( dist( p, p1 ) <= dist( p, p2 ) && dist( p, p1 ) <= dist( p, p3 ) )
return val( p1 )
if( dist( p, p2 ) <= dist( p, p3 ) && dist( p, p2 ) <= dist( p, p1 ) )
return val( p2 )
if( dist( p, p3 ) <= dist( p, p1 ) && dist( p, p3 ) <= dist( p, p2 ) )
return val( p3 )
I think this also generates a voronoi diagram

defining a procedure using graphics-draw-line

Can you see what is wrong with this:
(define (box d x1 y1 x2 y2) (
(graphics-draw-line d x1 y1 x1 y2)
(graphics-draw-line d x1 y2 x2 y2)
(graphics-draw-line d x2 y2 x2 y1)
(graphics-draw-line d x2 y1 x1 y1) ))
When I call it like this:
( begin
(define w (make-graphics-device 'x))
(box w .10 .10 .20 .20) )
I get an errer:
;The object #!unspecific is not applicable.
;To continue, call RESTART with an option number:
; (RESTART 2) => Specify a procedure to use in its place.
; (RESTART 1) => Return to read-eval-print level 1.
2 error>
This works:
(begin
(define w (make-graphics-device 'x))
(graphics-draw-line w .1 .1 .1 .2)
(graphics-draw-line w .1 .2 .2 .2)
(graphics-draw-line w .2 .2 .2 .1)
(graphics-draw-line w .2 .1 .1 .1) )
I can't see the difference!
Don't just group expressions with ()s -- that will try to use the result of the first as a function, but the value is #!unspecific -- definitely not a function.
Use this:
(define (box d x1 y1 x2 y2)
(graphics-draw-line d x1 y1 x1 y2)
(graphics-draw-line d x1 y2 x2 y2)
(graphics-draw-line d x2 y2 x2 y1)
(graphics-draw-line d x2 y1 x1 y1))

Resources