I have function P which takes two points and returns true if they satisfy some condition, false otherwise. I want to plot all the points in range lx <= x <= hx, ly <= y <= hy that satisfy the condition. How to do this in scilab?
A combination of ndgrid and the find function is exactly suited for this. For instance:
lx = 0;
hx = 10;
ly = 0;
hy = 10;
// Create x and y lists
a = linspace(lx,hx);
b = linspace(ly,hy);
// Create arrays for function evaluation on a 2D grid
[A,B] = ndgrid(a,b)
// Define your predicate as a function
function result = P(a, b)
result = (a < b);
endfunction
// Evaluate your function for all values in A and B and as a result
// get a matrix p filled with booleans
p = P(A(:),B(:));
// Find all indices of TRUE
indices = find(p);
// Plot all points using A as x coordinate and B as y coordinate
plot(A(indices), B(indices), 'o')
// Scale the axis of the plot so that all points are visible
a=gca();
a.data_bounds = [lx,ly;hx,hy];
This will result in the plot below:
Related
I have a 3D point (x,y,z) and a facet which is defined by three (x,y,z) points. I am trying to calculate the angle between the facet and the point. This is so I can shade the facet appropriately as though a light were moving across it in 3D space.
Hopefully this image gives an idea of what I'm trying to work out. The 3 dots are points in space relative to the facet and have different angles relative to its facing direction. It is this angle that I want to find. If the dots were points of light, the black dot would provide the brightest light, the blue would be about 50% brightness and the green would be very dark.
While I can calculate the magnitude, length and dot product of any two points, I am at a loss as to how to calculate the angle between the facet itself and the point.
I would like to know how to calculate whether the point is above or level with the facet, i.e.: the angle of the point relative to the facet.
The code I have so far is:
-- Get length of 2D or 3D vector
local function vector2d3dLength( vector )
return math.sqrt( vector.x*vector.x + vector.y*vector.y + (vector.z or 0)*(vector.z or 0) )
end
-- Normalise 2D or 3D vector
local function normalise2d3dVector( vector )
local len = vector2d3dLength( vector )
if (len == 0) then
return vector
end
local normalised = { x=vector.x/len, y=vector.y/len }
if (vector.z) then
normalised.z = vector.z/len
end
return normalised
end
local function crossProduct3d( a, b )
return { x=a.y*b.z − a.z*b.y, y=a.z*b.x − a.x*b.z, z=a.x*b.y − a.y*b.x }
end
local function dotProduct3d( a, b )
return a.x*b.x + a.y*b.y + a.z*b.z
end
-- subtract vector b from vector a
local function subtract_vectors( a, b )
local sub = { x=a.x-b.x, y=a.y-b.y }
if (a.z ~= nil and b.z ~= nil) then
sub.z = a.z-b.z
end
return sub
end
-- black/blue/green point
local lightsource = { x = 111, y = 112, z = 113 }
-- 3 points on the facet, first point is the center
local facet = {{ x = 1, y = 2, z = 3 },
{ x = 4, y = 5, z = 6 },
{ x = 7, y = 8, z = 9 }}
local facet_normal = normalise2d3dVector(crossProduct3d(
subtract_vectors(facet[2], facet[1]),
subtract_vectors(facet[3], facet[1])))
local direction_to_lightsource =
normalise2d3dVector(subtract_vectors(lightsource, facet[1]))
local cos_angle = dotProduct3d( direction_to_lightsource, facet_normal )
-- cos_angle may be negative, it depends on whether facet points are CW or CCW
local facet_brightness = cos_angle * max_brightness
Hi have made this code to plot a function.
I need to mark with an red X all the crossings between x = 0 and the blue wave line in the graph.
I have made some tries but with '-xr' in the plot function but it places X marks out of the crossings.
Anyone knows how to do it. Many thanks.
Code:
% entrada
a = input('Introduza o valor de a: ');
% ficheiro fonte para a função
raizes;
% chamada à função
x = 0:.1:50;
or = x;
or(:) = 0;
h = #(x) cos(x);
g = #(x) exp(a*x)-1;
f = #(x) h(x) - g(x);
zeros = fzero(f,0);
plot(x,f(x));
hold on
plot(zeros,f(zeros),'-xr')
hold off
Graph (it only marks one zero, i need all the zero crossings):
As mentioned in the comments above, you need to look for the zeros of your function before you can plot them. You can do this mathematically (in this case set f(x) = g(x) and solve for x) or you can do this analytically with something like fsolve.
If you read the documentation for fsolve, you will see that it searches for the zero closest to the provided x0 if passed a scalar or the first zero if passed an interval. What we can do for a quick attempt at a solution is to pass our x values into fsolve as initial guesses and filter out the unique values.
% Set up sample data
a = .05;
x = 0:.1:50;
% Set up equations
h = #(x) cos(x);
g = #(x) exp(a*x)-1;
f = #(x) h(x) - g(x);
% Find zeros of f(x)
crossingpoints = zeros(length(x), 1); % Initialize array
for ii = 1:length(x) % Use x data points as guesses for fzero
try
crossingpoints(ii) = fzero(f, x(ii)); % Find zero closest to guess
end
end
crossingpoints(crossingpoints < 0) = []; % Throw out zeros where x < 0
% Find unique zeros
tol = 10^-8;
crossingpoints = sort(crossingpoints(:)); % Sort data for easier diff
temp = false(size(crossingpoints)); % Initialize testing array
% Find where the difference between 'zeros' is less than or equal to the
% tolerance and throw them out
temp(1:end-1) = abs(diff(crossingpoints)) <= tol;
crossingpoints(temp) = [];
% Sometimes catches beginning of the data set, filter it out if this happens
if abs(f(crossingpoints(1))) >= (0 + tol)
crossingpoints(1) = [];
end
% Plot data
plot(x, f(x))
hold on
plot(crossingpoints, f(crossingpoints), 'rx')
hold off
grid on
axis([0 20 -2 2]);
Which gives us the following:
Note that due to errors arising from floating point arithmetic we have to utilize a tolerance to filter our zeros rather than utilizing a function like unique.
I have this jsbin that shows my working.
In the jsbin, I am trying to draw a line through the altitude through point A (1, 1) that is perpendicular to Line BC which has points B (6, 18) and C (14, 6).
The way I have worked this out is to try and get 2 equations into the form y = mx + c and then rearrange them to y -mx = c and then solve them through simultaneous equations using matrices.
I have this altitude function that does the work:
function altitude(vertex, a, b) {
var slope = gradient(a, b),
x1 = - slope,
y1 = 1,
c1 = getYIntercept(a, slope),
perpendicularSlope = perpendicularGradient(a, b),
x2 = - perpendicularSlope,
y2 = 1,
c2 = getYIntercept(vertex, perpendicularSlope);
var matrix = [
[x1, y1],
[x2, y2]
];
var result = solve(matrix, [c1, c2]);
var g = svg.append('g');
g.append('line')
.style('stroke', 'red')
.attr('class', 'line')
.attr('x1', xScale(vertex.x))
.attr('y1', yScale(vertex.y))
.attr('x2', xScale(result.x))
.attr('y2', yScale(result.y));
}
I first of all get the gradient of BC using this function
var gradient = function(a, b) {
return (b.y - a.y) / (b.x - a.x);
};
Which is -1.5 and from that I can get the perpendicular gradient using this function:
var perpendicularGradient = function (a, b) {
return -1 / gradient(a, b);
};
I make that to be 0.66666 or (2/3).
I get the 2 equations to look like this:
y + 1.5 = 27
y -0.6666666666666666 = 0.33333333333333337
I have some functions in the jsbin that will solve these simultaneously using matrices and cramer's rule, the main one being solve:
function solve(matrix, r) {
var determinant = det(matrix);
var x = det([
[r[0], matrix[0][1]],
[r[1], matrix[1][1]]
]) / determinant;
var y = det([
[matrix[0][0], r[0]],
[matrix[1][0], r[1]]
]) / determinant;
return {x: Math.approx(x), y: Math.approx(y)};
}
function det(matrix) {
return (matrix[0][0]*matrix[1][1])-(matrix[0][1]*matrix[1][0]);
}
I get the coordinates of the intercept to be roughly (12.31, 8.54).
The problem is, it does not look right on the diagram.
Have I taken a wrong step somewhere? I think my calculations are right but I would not rule out them being wrong. It might be down to scale perhaps.
You want to find projection of point A onto line BC.
Let's make vectors
Q = C - B
P = A - B
normalized (unit length):
uQ = Q/ |Q|
Needed projection point D is
D = B + uQ * DotProduct(P, uQ)
For your example A(1,1), B(6,18), C(14,6)
Q = (8, -12)
|Q| = Sqrt(8*8+12*12)~14.4
uQ= (0.55, -0.83)
P=(-5,-17)
DotProduct(P, uQ)=0.55*(-5) -(0.83*-17)=11.39
D = (6+0.55*11.39, 18-0.83*11.39) = (12.26, 8,54)
So your calculation gives right result (though approach is not very efficient), but picture is not exact - different scales of X and Y axes deform angles.
P.S: Second line width = 660 - margin.left - margin.right, makes the picture more reliable
I have a formula that maps a random point in space to a point that sits in a sphere. I want to be able to reverse this formula to get the random point in space again.
My unspherize() function below is not working. Please show me the correct way to reverse the form.
function spherize(x,y,z){
var d = 1 / Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
x *= d;
y *= d;
z *= d;
return {x: x, y: y, z: z}
}
function unspherize(x,y,z){
var d = 1 * Math.pow(Math.sqrt(x) + Math.sqrt(y) + Math.sqrt(z), 2)
x /= d;
y /= d;
z /= d;
return {x: x, y: y, z: z}
}
There are an infinite number of points that get mapped to the same point on the sphere (e.g., for every (x,y,z) the point (2x,2y,2z) gets mapped to the same vector). Therefore, if you don't save the vector length d, the operation is not reversible.
Using r as the radius or Euclidean norm of the point (x,y,z),
x /= 1+r
y /= 1+r
z /= 1+r
gives you a point inside the sphere. Since this transformation is bijective, it can be reversed, for any point inside the sphere, the "unspherized" point is obtained as
x/= 1-r
y/= 1-r
z/= 1-r
I would like to uniformly distribute a predetermined set of points within a circle. By uniform distribution, I mean they should all be equally distanced from each other (hence a random approach won't work). I tried a hexagonal approach, but I had problems consistently reaching the outermost radius.
My current approach is a nested for loop where each outer iteration reduces the radius & number of points, and each inner loop evenly drops points on the new radius. Essentially, it's a bunch of nested circles. Unfortunately, it's far from even. Any tips on how to do this correctly?
The goals of having a uniform distribution within the area and a uniform distribution on the boundary conflict; any solution will be a compromise between the two. I augmented the sunflower seed arrangement with an additional parameter alpha that indicates how much one cares about the evenness of boundary.
alpha=0 gives the typical sunflower arrangement, with jagged boundary:
With alpha=2 the boundary is smoother:
(Increasing alpha further is problematic: Too many points end up on the boundary).
The algorithm places n points, of which the kth point is put at distance sqrt(k-1/2) from the boundary (index begins with k=1), and with polar angle 2*pi*k/phi^2 where phi is the golden ratio. Exception: the last alpha*sqrt(n) points are placed on the outer boundary of the circle, and the polar radius of other points is scaled to account for that. This computation of the polar radius is done in the function radius.
It is coded in MATLAB.
function sunflower(n, alpha) % example: n=500, alpha=2
clf
hold on
b = round(alpha*sqrt(n)); % number of boundary points
phi = (sqrt(5)+1)/2; % golden ratio
for k=1:n
r = radius(k,n,b);
theta = 2*pi*k/phi^2;
plot(r*cos(theta), r*sin(theta), 'r*');
end
end
function r = radius(k,n,b)
if k>n-b
r = 1; % put on the boundary
else
r = sqrt(k-1/2)/sqrt(n-(b+1)/2); % apply square root
end
end
Might as well tag on my Python translation.
from math import sqrt, sin, cos, pi
phi = (1 + sqrt(5)) / 2 # golden ratio
def sunflower(n, alpha=0, geodesic=False):
points = []
angle_stride = 360 * phi if geodesic else 2 * pi / phi ** 2
b = round(alpha * sqrt(n)) # number of boundary points
for k in range(1, n + 1):
r = radius(k, n, b)
theta = k * angle_stride
points.append((r * cos(theta), r * sin(theta)))
return points
def radius(k, n, b):
if k > n - b:
return 1.0
else:
return sqrt(k - 0.5) / sqrt(n - (b + 1) / 2)
# example
if __name__ == '__main__':
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
points = sunflower(500, alpha=2, geodesic=False)
xs = [point[0] for point in points]
ys = [point[1] for point in points]
ax.scatter(xs, ys)
ax.set_aspect('equal') # display as square plot with equal axes
plt.show()
Stumbled across this question and the answer above (so all cred to user3717023 & Matt).
Just adding my translation into R here, in case someone else needed that :)
library(tibble)
library(dplyr)
library(ggplot2)
sunflower <- function(n, alpha = 2, geometry = c('planar','geodesic')) {
b <- round(alpha*sqrt(n)) # number of boundary points
phi <- (sqrt(5)+1)/2 # golden ratio
r <- radius(1:n,n,b)
theta <- 1:n * ifelse(geometry[1] == 'geodesic', 360*phi, 2*pi/phi^2)
tibble(
x = r*cos(theta),
y = r*sin(theta)
)
}
radius <- function(k,n,b) {
ifelse(
k > n-b,
1,
sqrt(k-1/2)/sqrt(n-(b+1)/2)
)
}
# example:
sunflower(500, 2, 'planar') %>%
ggplot(aes(x,y)) +
geom_point()
Building on top of #OlivelsAWord , here is a Python implementation using numpy:
import numpy as np
import matplotlib.pyplot as plt
def sunflower(n: int, alpha: float) -> np.ndarray:
# Number of points respectively on the boundary and inside the cirlce.
n_exterior = np.round(alpha * np.sqrt(n)).astype(int)
n_interior = n - n_exterior
# Ensure there are still some points in the inside...
if n_interior < 1:
raise RuntimeError(f"Parameter 'alpha' is too large ({alpha}), all "
f"points would end-up on the boundary.")
# Generate the angles. The factor k_theta corresponds to 2*pi/phi^2.
k_theta = np.pi * (3 - np.sqrt(5))
angles = np.linspace(k_theta, k_theta * n, n)
# Generate the radii.
r_interior = np.sqrt(np.linspace(0, 1, n_interior))
r_exterior = np.ones((n_exterior,))
r = np.concatenate((r_interior, r_exterior))
# Return Cartesian coordinates from polar ones.
return r * np.stack((np.cos(angles), np.sin(angles)))
# NOTE: say the returned array is called s. The layout is such that s[0,:]
# contains X values and s[1,:] contains Y values. Change the above to
# return r.reshape(n, 1) * np.stack((np.cos(angles), np.sin(angles)), axis=1)
# if you want s[:,0] and s[:,1] to contain X and Y values instead.
if __name__ == '__main__':
fig, ax = plt.subplots()
# Let's plot three sunflowers with different values of alpha!
for alpha in (0, 1, 2):
s = sunflower(500, alpha)
# NOTE: the 'alpha=0.5' parameter is to control transparency, it does
# not have anything to do with the alpha used in 'sunflower' ;)
ax.scatter(s[0], s[1], alpha=0.5, label=f"alpha={alpha}")
# Display as square plot with equal axes and add a legend. Then show the result :)
ax.set_aspect('equal')
ax.legend()
plt.show()
Adding my Java implementation of previous answers with an example (Processing).
int n = 2000; // count of nodes
Float alpha = 2.; // constant that can be adjusted to vary the geometry of points at the boundary
ArrayList<PVector> vertices = new ArrayList<PVector>();
Float scaleFactor = 200.; // scale points beyond their 0.0-1.0 range for visualisation;
void setup() {
size(500, 500);
// Test
vertices = sunflower(n, alpha);
displayTest(vertices, scaleFactor);
}
ArrayList<PVector> sunflower(int n, Float alpha) {
Double phi = (1 + Math.sqrt(5)) / 2; // golden ratio
Double angle = 2 * PI / Math.pow(phi, 2); // value used to calculate theta for each point
ArrayList<PVector> points = new ArrayList<PVector>();
Long b = Math.round(alpha*Math.sqrt(n)); // number of boundary points
Float theta, r, x, y;
for (int i = 1; i < n + 1; i++) {
r = radius(i, n, b.floatValue());
theta = i * angle.floatValue();
x = r * cos(theta);
y = r * sin(theta);
PVector p = new PVector(x, y);
points.add(p);
}
return points;
}
Float radius(int k, int n, Float b) {
if (k > n - b) {
return 1.0;
} else {
Double r = Math.sqrt(k - 0.5) / Math.sqrt(n - (b+1) / 2);
return r.floatValue();
}
}
void displayTest(ArrayList<PVector> points, Float size) {
for (int i = 0; i < points.size(); i++) {
Float x = size * points.get(i).x;
Float y = size * points.get(i).y;
pushMatrix();
translate(width / 2, height / 2);
ellipse(x, y, 5, 5);
popMatrix();
}
}
Here's my Unity implementation.
Vector2[] Sunflower(int n, float alpha = 0, bool geodesic = false){
float phi = (1 + Mathf.Sqrt(5)) / 2;//golden ratio
float angle_stride = 360 * phi;
float radius(float k, float n, float b)
{
return k > n - b ? 1 : Mathf.Sqrt(k - 0.5f) / Mathf.Sqrt(n - (b + 1) / 2);
}
int b = (int)(alpha * Mathf.Sqrt(n)); //# number of boundary points
List<Vector2>points = new List<Vector2>();
for (int k = 0; k < n; k++)
{
float r = radius(k, n, b);
float theta = geodesic ? k * 360 * phi : k * angle_stride;
float x = !float.IsNaN(r * Mathf.Cos(theta)) ? r * Mathf.Cos(theta) : 0;
float y = !float.IsNaN(r * Mathf.Sin(theta)) ? r * Mathf.Sin(theta) : 0;
points.Add(new Vector2(x, y));
}
return points.ToArray();
}