Position in ellipse formula - math

So let's say I got a coordinate grid. I need to know whether or not p0 is located on ellipse starting from p1 ending with p2.
Example with other geometric objects:
-- Rectangle
function PositiongOnRectangle(posx, posy, x1, y1, x2, y2)
return (posx >= x1 and posy >= y1 and posx <= x2 and posy <= y2)
end
-- circle
function PositionOnCircle(posx, posy, x1, y1, radius)
local distance = math.sqrt((posx - x1)^2 + (posy - y1)^2)
return (radius >= distance)
end
Exmaples above are witten in Lua, however pseudo code will do. I want to do the same but with ellipse.
Thanks in advance!

For ellipse, inscribed in axis-aligned rectangle, defined by two vertices p1, p2:
PositionOnEllipse(posx, posy, x1, y1, x2, y2)
///center of ellipse coordinates:
mx = (x1+x2)/2
my = (y1+y2)/2
///ellipse semiaxes:
ax = (x1-x2)/2
ay = (y1-y2)/2
////due to ellipse equation
return = (posx-mx)^2/ax^2 + (posy-my)^2/ay^2 <= 1

Related

How to calculate coordinates of tangent points?

I need to make a svg file for a project and I need some parameters that I haven't figured out how to calculate yet.
I have a point of coordinates x1,y1 and a circumference with a center of coordinates x2,y2 with radius r. The point x1,y1 is outside the circumference. How do I calculate the coordinates of the points belonging to the circumference (x3,y3 and x4,y4) from which the two tangent lines would pass? The outer point (x1,y1) will never touch the circumference and will never belong to the circumference.
This is the drawing to make the concept better understood, in red the values to be calculated.
Tangents scheme
Shift coordinate system to make origin in circle center (to get simpler equations). Now point is
x1' = x1 - x2
y1' = y1 - y2
Solve the next equation system (point belongs to circumference and radius is perpendicular to tangent)
x^2 + y^2 = r^2
(x - x1') * x + (y - y1') * y = 0
for unknown x, y.
To get final result, add x2, y2 to solution results (should be two solutions)
import math
def tangpts(px, py, cx, cy, r):
px -= cx
py -= cy
r2 = r*r
r4 = r2*r2
a = px*px+py*py
b = -2*r2*px
c = r4 - r2*py*py
d = b*b-4*a*c
if d < 0:
return None
d = math.sqrt(d)
xx1 = (-b - d) / (2*a)
xx2 = (-b + d) / (2*a)
if (abs(py) > 1.0e-8):
yy1 = (r2 - px * xx1) / py
yy2 = (r2 - px * xx2) / py
else:
yy1 = math.sqrt(r2 - xx1*xx1)
yy2 = -yy1
return((xx1+cx,yy1+cy),(xx2+cx,yy2+cy))
print(tangpts(0.5, 0.5, 0, 0, 1))
print(tangpts(1, 1, 0, 0, 1))
print(tangpts(0, 0, -3, -3, 3))
print(tangpts(2, 0, 0, 0, 1))
print(tangpts(0, 1, 0, 0, 1))
>>>
None #point inside
((0.0, 1.0), (1.0, 0.0)) #common case
((-3.0, 0.0), (0.0, -3.0)) #common case
((0.5, 0.8660254037844386), (0.5, -0.8660254037844386)) #py is zero case
((0.0, 1.0), (0.0, 1.0)) # single tangent case - point at circumference
In order to post the python code for the solution, I'm copying the explanation originally in comments:
The center of the circle is P2(x2, y2), the radius is r. The unknown point P3(x3, y3) satisfies the equation of the circle:
(x3-x2)^2 + (y3-y2)^2 = r^2 (1).
The tangent P1P3 is perpendicular to the radius of the circle P2P3. So apply the Pythagorean theorem to the triangle P1P2P3:
a) the distance between P1 and P2 is (x1-x2)^2 + (y1-y2)^2,
b) the distance between P1 and P3 is (x1-x3)^2 + (y1-y3)^2
c) the distance P2P3 is r, the radius
(x1-x3)^2 + (y1-y3)^2 + r^2 = (x1-x2)^2 + (y1-y2)^2 (2)
We have thus to solve the equations (1) and (2) for x3 and y3.
We now separate the unknowns (a linear relation between x3 and y3 can be obtained by (1)-(2) => (x3-x2)(x1-x2) + (y3-y2)(y1-y2) = r^2), and we get the two equations of second degree.
The python implementation:
import math
def tangentPoints(x1, y1, x2, y2, r):
a = (y1-y2)**2+(x1-x2)**2
bx = -r**2 * (x1-x2)
cx = r**2 * (r**2-(y1-y2)**2)
sqDeltax = math.sqrt(bx**2 - a*cx)
x3 = x2 + (-bx + sqDeltax)/a
x4 = x2 + (-bx - sqDeltax)/a
by = -r**2 * (y1-y2)
cy = r**2 * (r**2 - (x1-x2)**2)
sqDeltay = math.sqrt(by**2 - a*cy)
y3 = y2 + (-by - sqDeltay)/a
y4 = y2 + (-by + sqDeltay)/a
return (x3, y3), (x4, y4)

Add labels to the center of a geom_curve line (ggplot)

Is there any way to add a label on or near the center of a geom_curve line? Currently, I can only do so by labeling either the start or end point of the curve.
library(tidyverse)
library(ggrepel)
df <- data.frame(x1 = 1, y1 = 1, x2 = 2, y2 = 3, details = "Object Name")
ggplot(df, aes(x = x1, y = y1, label = details)) +
geom_point(size = 4) +
geom_point(aes(x = x2, y = y2),
pch = 17, size = 4) +
geom_curve(aes(x = x1, y = y1, xend = x2, yend = y2)) +
geom_label(nudge_y = 0.05) +
geom_label_repel(box.padding = 2)
I would love some way to automatically label the curve near coordinates x=1.75, y=1.5. Is there a solution out there I haven't seen yet? My intended graph is quite busy, and labeling the origin points makes it harder to see what's happening, while labeling the arcs would make a cleaner output.
I've come to a solution for this problem. It's large and clunky, but effective.
The core problem is that geom_curve() does not draw a set path, but it moves and scales with the aspect ratio of the plot window. So short of locking the aspect ratio with coord_fixed(ratio=1) there is no way I can easily find to predict where the midpoint of a geom_curve() segment will be.
So instead I set about finding midpoint for a curve, and then forcing the curve to go through that point which I would later label. To find the midpoint I had to copy two functions from the grid package:
library(grid)
library(tidyverse)
library(ggrepel)
# Find origin of rotation
# Rotate around that origin
calcControlPoints <- function(x1, y1, x2, y2, curvature, angle, ncp,
debug=FALSE) {
# Negative curvature means curve to the left
# Positive curvature means curve to the right
# Special case curvature = 0 (straight line) has been handled
xm <- (x1 + x2)/2
ym <- (y1 + y2)/2
dx <- x2 - x1
dy <- y2 - y1
slope <- dy/dx
# Calculate "corner" of region to produce control points in
# (depends on 'angle', which MUST lie between 0 and 180)
# Find by rotating start point by angle around mid point
if (is.null(angle)) {
# Calculate angle automatically
angle <- ifelse(slope < 0,
2*atan(abs(slope)),
2*atan(1/slope))
} else {
angle <- angle/180*pi
}
sina <- sin(angle)
cosa <- cos(angle)
# FIXME: special case of vertical or horizontal line ?
cornerx <- xm + (x1 - xm)*cosa - (y1 - ym)*sina
cornery <- ym + (y1 - ym)*cosa + (x1 - xm)*sina
# Debugging
if (debug) {
grid.points(cornerx, cornery, default.units="inches",
pch=16, size=unit(3, "mm"),
gp=gpar(col="grey"))
}
# Calculate angle to rotate region by to align it with x/y axes
beta <- -atan((cornery - y1)/(cornerx - x1))
sinb <- sin(beta)
cosb <- cos(beta)
# Rotate end point about start point to align region with x/y axes
newx2 <- x1 + dx*cosb - dy*sinb
newy2 <- y1 + dy*cosb + dx*sinb
# Calculate x-scale factor to make region "square"
# FIXME: special case of vertical or horizontal line ?
scalex <- (newy2 - y1)/(newx2 - x1)
# Scale end points to make region "square"
newx1 <- x1*scalex
newx2 <- newx2*scalex
# Calculate the origin in the "square" region
# (for rotating start point to produce control points)
# (depends on 'curvature')
# 'origin' calculated from 'curvature'
ratio <- 2*(sin(atan(curvature))^2)
origin <- curvature - curvature/ratio
# 'hand' also calculated from 'curvature'
if (curvature > 0)
hand <- "right"
else
hand <- "left"
oxy <- calcOrigin(newx1, y1, newx2, newy2, origin, hand)
ox <- oxy$x
oy <- oxy$y
# Calculate control points
# Direction of rotation depends on 'hand'
dir <- switch(hand,
left=-1,
right=1)
# Angle of rotation depends on location of origin
maxtheta <- pi + sign(origin*dir)*2*atan(abs(origin))
theta <- seq(0, dir*maxtheta,
dir*maxtheta/(ncp + 1))[c(-1, -(ncp + 2))]
costheta <- cos(theta)
sintheta <- sin(theta)
# May have BOTH multiple end points AND multiple
# control points to generate (per set of end points)
# Generate consecutive sets of control points by performing
# matrix multiplication
cpx <- ox + ((newx1 - ox) %*% t(costheta)) -
((y1 - oy) %*% t(sintheta))
cpy <- oy + ((y1 - oy) %*% t(costheta)) +
((newx1 - ox) %*% t(sintheta))
# Reverse transformations (scaling and rotation) to
# produce control points in the original space
cpx <- cpx/scalex
sinnb <- sin(-beta)
cosnb <- cos(-beta)
finalcpx <- x1 + (cpx - x1)*cosnb - (cpy - y1)*sinnb
finalcpy <- y1 + (cpy - y1)*cosnb + (cpx - x1)*sinnb
# Debugging
if (debug) {
ox <- ox/scalex
fox <- x1 + (ox - x1)*cosnb - (oy - y1)*sinnb
foy <- y1 + (oy - y1)*cosnb + (ox - x1)*sinnb
grid.points(fox, foy, default.units="inches",
pch=16, size=unit(1, "mm"),
gp=gpar(col="grey"))
grid.circle(fox, foy, sqrt((ox - x1)^2 + (oy - y1)^2),
default.units="inches",
gp=gpar(col="grey"))
}
list(x=as.numeric(t(finalcpx)), y=as.numeric(t(finalcpy)))
}
calcOrigin <- function(x1, y1, x2, y2, origin, hand) {
# Positive origin means origin to the "right"
# Negative origin means origin to the "left"
xm <- (x1 + x2)/2
ym <- (y1 + y2)/2
dx <- x2 - x1
dy <- y2 - y1
slope <- dy/dx
oslope <- -1/slope
# The origin is a point somewhere along the line between
# the end points, rotated by 90 (or -90) degrees
# Two special cases:
# If slope is non-finite then the end points lie on a vertical line, so
# the origin lies along a horizontal line (oslope = 0)
# If oslope is non-finite then the end points lie on a horizontal line,
# so the origin lies along a vertical line (oslope = Inf)
tmpox <- ifelse(!is.finite(slope),
xm,
ifelse(!is.finite(oslope),
xm + origin*(x2 - x1)/2,
xm + origin*(x2 - x1)/2))
tmpoy <- ifelse(!is.finite(slope),
ym + origin*(y2 - y1)/2,
ifelse(!is.finite(oslope),
ym,
ym + origin*(y2 - y1)/2))
# ALWAYS rotate by -90 about midpoint between end points
# Actually no need for "hand" because "origin" also
# encodes direction
# sintheta <- switch(hand, left=-1, right=1)
sintheta <- -1
ox <- xm - (tmpoy - ym)*sintheta
oy <- ym + (tmpox - xm)*sintheta
list(x=ox, y=oy)
}
With that in place, I calculated a midpoint for each record
df <- data.frame(x1 = 1, y1 = 1, x2 = 10, y2 = 10, details = "Object Name")
df_mid <- df %>%
mutate(midx = calcControlPoints(x1, y1, x2, y2,
angle = 130,
curvature = 0.5,
ncp = 1)$x) %>%
mutate(midy = calcControlPoints(x1, y1, x2, y2,
angle = 130,
curvature = 0.5,
ncp = 1)$y)
I then make the graph, but draw two separate curves. One from the origin to the calculated midpoint, and another from the midpoint to the destination. The angle and curvature settings for both finding the midpoint and drawing these curves are tricky to keep the result from obviously looking like two different curves.
ggplot(df_mid, aes(x = x1, y = y1)) +
geom_point(size = 4) +
geom_point(aes(x = x2, y = y2),
pch = 17, size = 4) +
geom_curve(aes(x = x1, y = y1, xend = midx, yend = midy),
curvature = 0.25, angle = 135) +
geom_curve(aes(x = midx, y = midy, xend = x2, yend = y2),
curvature = 0.25, angle = 45) +
geom_label_repel(aes(x = midx, y = midy, label = details),
box.padding = 4,
nudge_x = 0.5,
nudge_y = -2)
Though the answer isn't ideal or elegant, it scales with a large number of records.
Maybe annotations would help here (see: http://ggplot2.tidyverse.org/reference/annotate.html)
library(tidyverse)
library(ggrepel)
df <- data.frame(x1 = 1, y1 = 1, x2 = 2, y2 = 3, details = "Object Name")
ggplot(df, aes(x = x1, y = y1, label = details)) +
geom_point(size = 4) +
geom_point(aes(x = x2, y = y2),
pch = 17, size = 4) +
geom_curve(aes(x = x1, y = y1, xend = x2, yend = y2)) +
geom_label(nudge_y = 0.05) +
geom_label_repel(box.padding = 2) +
annotate("label", x=1.75, y=1.5, label=df$details)

Mapping image on spherical surface

In simple words i need to map a image to be use in a spherical surface. I being trying to do this for several hours. searching in google I din't find any proper solution (explained for dumb people).
I thinks the code from this link:
https://www.codeproject.com/articles/19712/mapping-images-on-spherical-surfaces-using-c is what i need. but (i think everything is alright) can make it work in Julia.
This is my code so far:
image = brightNoise(height,width,seed,rand=true)
arr = Array{Float64}(height,width)
function MapCoordinate(i1, i2,w1,w2,p)
return ((p - i1) / (i2 - i1)) * (w2 - w1) + w1
end
function Rotate(angle, axisA, axisB)
return axisA * cos(angle) - axisB * sin(angle),axisA * sin(angle) + axisB * cos(angle)
end
phi0 = 0.0
phi1 = pi
theta0 = 0.0
theta1 = 2.0*pi
radius = 50
arr = Array{Float64}(height,width)
for i= 1:size(image)[1]
for j= 1:size(image)[2]
#map the angles from image coordinates
theta = MapCoordinate(0.0,width - 1,theta1, theta0, i)
phi = MapCoordinate(0.0,height - 1,phi0,phi1, j)
#find the cartesian coordinates
x = radius * sin(phi) * cos(theta);
y = radius * sin(phi) * sin(theta);
z = radius * cos(phi);
#apply rotation around X and Y axis to reposition the sphere
y,z=Rotate(1.5, y, z);
x,z=Rotate(pi/2, x, z);
#plot only positive points
if (z > 0)
color = image[i,j]
ix = floor(Int64,x)
iy = floor(Int64,y)
arr[ix,iy] = color
println(ix,iy)
end
end
end
The image is just a black and white noise generated in Julia, i need to wrap a sphere with it.
I have little idea what your code is doing, but fixing some of the indexing issues gives something that might help you get started. It looks like it's doing something spherical, anyway...
using Images, FileIO
mandrill = load(mandrill.png")
height, width = size(mandrill)
arr = colorim(Array{Float64}(height, width, 3))
function MapCoordinate(i1, i2, w1, w2, p)
return ((p - i1) / (i2 - i1)) * (w2 - w1) + w1
end
function Rotate(angle, axisA, axisB)
return axisA * cos(angle) - axisB * sin(angle),axisA * sin(angle) + axisB * cos(angle)
end
phi0 = 0.0
phi1 = pi
theta0 = 0.0
theta1 = 2.0 * pi
radius = 200
for i = 1:size(mandrill, 1)
for j = 1:size(mandrill, 2)
# map the angles from image coordinates
theta = MapCoordinate(1.0, width - 1, theta1, theta0, i)
phi = MapCoordinate(1.0, height - 1, phi0, phi1, j)
# find the cartesian coordinates
x = radius * sin(phi) * cos(theta)
y = radius * sin(phi) * sin(theta)
z = radius * cos(phi)
# apply rotation around X and Y axis to reposition the sphere
y, z = Rotate(1.5, y, z)
x, z = Rotate(pi/2, x, z)
# plot only positive points
if z > 0
color = mandrill[i, j]
ix = convert(Int, floor(x + width/2))
iy = convert(Int, floor(y + height/2))
arr[ix, iy, :] = [color.r, color.g, color.b]
end
end
end
save("/tmp/mandrill-output.png", arr)
run(`open /tmp/mandrill-output.png`)

find inverse (x, y pos) point in circle

I have a fixed point (x1, y1) and a moving/rotating point (x2, y2), how do I find the tangent inverse point (x3, y3)
My circle radius is 40.
Assuming p1 and p2 are 2-vectors, the following will do it.
v12 = normalize(p2 - p1) // the unit vector from p1 to p2
p3 = p1 - 40 * v12 // 40 away from p1 in the direction opposite p2
The value of normalize(u) is simply u / sqrt(u.x * u.x + u.y * u.y).
achieved it this way, modified to be rotated to any angle
http://jsfiddle.net/christianpugliese/g2Lk9k12/1/
var dx = x2 - x1;
var dy = y2 - y1;
var radianAngle = Math.atan2(dy, dx);
var diameter = -80;
p3x = x1 + diameter * Math.cos(radianAngle);
p3y = y1 + diameters * Math.sin(radianAngle);

How to randomize points on a sphere surface evenly?

Im trying to make stars on the sky, but the stars distribution isnt even.
This is what i tried:
rx = rand(0.0f, PI*2.0f);
ry = rand(0.0f, PI);
x = sin(ry)*sin(rx)*range;
y = sin(ry)*cos(rx)*range;
z = cos(ry)*range;
Which results to:
img http://img716.imageshack.us/img716/3320/sphererandom.jpg
And:
rx = rand(-1.0f, 1.0f);
ry = rand(-1.0f, 1.0f);
rz = rand(-1.0f, 1.0f);
x = rx*range;
y = ry*range;
z = rz*range;
Which results to:
img2 http://img710.imageshack.us/img710/5152/squarerandom.jpg
(doesnt make a sphere, but opengl will not tell a difference, though).
As you can see, there is always some "corner" where are more points in average. How can i create random points on a sphere where the points will be distributed evenly?
you can do
z = rand(-1, 1)
rxy = sqrt(1 - z*z)
phi = rand(0, 2*PI)
x = rxy * cos(phi)
y = rxy * sin(phi)
Here rand(u,v) draws a uniform random from interal [u,v]
You don't need trigonometry if you can generate random gaussian variables, you can do (pseudocode)
x <- gauss()
y <- gauss()
z <- gauss()
norm <- sqrt(x^2 + y^2 + z^2)
result = (x / norm, y / norm, z / norm)
Or draw points inside the unit cube until one of them is inside the unit ball, then normalize:
double x, y, z;
do
{
x = rand(-1, 1);
y = rand(-1, 1);
z = rand(-1, 1);
} while (x * x + y * y + z * z > 1);
double norm = sqrt(x * x + y * y + z * z);
x / norm; y /= norm; z /= norm;
It looks like you can see that it's the cartesian coordinates that are creating the concentrations.
Here is an explanation of one right (and wrong) way to get a proper distribution.

Resources