The formulars in HSV triangle - math

I do not know how the following two formulas are derived. Please kindly explain. My reputation point is so low that I can't ask the person who wrote the formula.
HSV triangle in C#
var sat = (1 - 2*y1) / (sqrt3*x1 - y1 + 2);
var val = (sqrt3*x1 - y1 + 2) / 3;

After the transformation, I needed the corners of the triangle to touch the unit circle at the points <0,-1> "top", <-√3/2,1/2> "bottom-left" and <√3/2,1/2> "bottom-right". I picked bottom-left to be the black point (val = 0), and when val = 1, the top would be the color point (val = 1 and sat = 1), and the bottom-right would be the white point (val = 1 and sat = 0).
To achieve this, I first defined the right edge as the equation
<x,y> = <0,-1>*sat + <√3/2,1/2>*(1-sat)
^ ^-- When sat = 0, the result is this point
'-- When sat = 1, the result is this point
I then scaled this line towards <-√3/2,1/2> when val goes to zero
<x,y> = ( <0,-1>*sat + <√3/2,1/2>*(1-sat) )*val + <-√3/2,1/2>*(1-val)
<x,y> = <0,-1>*sat*val + <√3/2,1/2>*(1-sat)*val + <-√3/2,1/2>*(1-val)
^ ^ ^-- When val = 0, the result is this point
| '-- When val = 1 and sat = 0, the result is this point
'-- When val = 1 and sat = 1, the result is this point
Converting from vector form:
x = 0*sat*val + √3/2*(1-sat)*val + -√3/2*(1-val)
y = -1*sat*val + 1/2*(1-sat)*val + 1/2*(1-val)
Expanding:
x = -√3/2*val*sat + √3*val - √3/2
y = -3/2*val*sat + 1/2
Rearranging:
(√3*x - y + 2)/3 = val
(1 - 2*y)/3 = sat*val
Solving for sat and val:
sat = (1 - 2*y)/(√3*x - y + 2)
val = (√3*x - y + 2)/3

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)

Binomial Tree Plot in R

I have a little issue with the binomial tree plot in R; I'm using the package fOptions. Given St=39, K=40, T1=0.5, r=0.02, sigma=0.2, n=2, I use the following code:
CRRTree<- BinomialTreeOption(TypeFlag='ce',39,40,0.5,0.02,0.02,0.2,2)
BinomialTreePlot(CRRTree)
and the corresponding plot is
I have two problems.
First: I want that the x axis starts from zero and goes to 2
Second: I don't undestand why the upper value of the tree is not showed in the picture; how can I fix it?
Thank you very much.
EDIT: I solved the second problem in the easiest way, I think. It was sufficient to code the plot in this way:
BinomialTreePlot(CRRTree,ylim=c(-2,2.5))
There is an easy way to solve also the problem of making the tree starts from 0?
You will have to modify the code for the BinomialTreePlot function. For example, you could try something like that:
my_BinomialTreePlot<-function (BinomialTreeValues, dx = -0.025, dy = 0.4, cex = 1,
digits = 2, ...)
{
Tree = round(BinomialTreeValues, digits = digits)
depth = ncol(Tree)
plot(x = c(0, depth-1), y = c(-depth + 1, depth - 1), type = "n",
col = 0, ...)
points(x = 0, y = 0)
text(0 + dx, 0 + dy, deparse(Tree[1, 1]), cex = cex)
for (i in 1:(depth - 1)) {
y = seq(from = -i, by = 2, length = i + 1)
x = rep(i, times = length(y)) + 0
points(x, y, col = 1)
for (j in 1:length(x)) text(x[j] + dx, y[j] + dy, deparse(Tree[length(x) +
1 - j, i + 1]), cex = cex)
y = (-i):i
x = rep(c(i, i-1), times = 2 * i)[1:length(y)]
lines(x, y, col = 2)
}
invisible()
}
Then use it like this:
CRRTree<- BinomialTreeOption(TypeFlag='ce',39,40,0.5,0.02,0.02,0.2,2)
my_BinomialTreePlot(CRRTree,xlim=c(-0.1,2), ylim=c(-2.5,2.5))

Smooth passage from one graph to another

Consider the two following graphs
require(ggplot2)
set.seed(5276)
my_mtcars = mtcars
my_mtcars$rand = rnorm(nrow(mtcars))
ggplot(my_mtcars, aes(rand, mpg)) + geom_point()
ggplot(my_mtcars, aes(wt, mpg)) + geom_point()
I would like to make a movie (or any animated picture that could easily be introduced in a .ppt) that would make a smooth passage from the first graph toward the second. During the passage, we would see the dots smoothly move horizontally to reach their destination. The x-axis scale and label should also appear (eventually smoothly).
I would try to create many .png that are intermediate pictures and then make a gif out of it using ImageMagick (Bash) but I am pretty sure there should be a better solution. I used ggplot2 to produce the plots but I am not strict on that. Here is what I tried for the moment
IntFormat = function(x,nbdigits=0){
cx = paste0(x)
l = length(strsplit(cx,"")[[1]])
if (nbdigits < l){nbdigits = l; print("WARNING: Parameter `nbdigits` too small")}
before = paste(rep("0",nbdigits-l), collapse="")
paste0(before, cx)
}
SmoothGraph = function(x1, x2, y1, y2, times = "NOTSET", ...){
path = "/Users/remi/Desktop/"
if (times == "NOTSET") {
times = c(seq(0,0.1,length.out=10), seq(0,0.2, length.out=5), seq(0.2,0.8, length.out=6), seq(0.8,0.9, length.out=5), seq(0.9,1,length.out=10))
}
nbdigits = length(times)
count = 0
x1_rel = x1 / (max(x1) - min(x1))
x1_rel = x1_rel - max(x1_rel) + 1
x2_rel = x2 / (max(x2) - min(x2))
x2_rel = x2_rel - max(x2_rel) + 1
y1_rel = y1 / (max(y1) - min(y1)) - min(y1)
y1_rel = y1_rel - max(y1_rel) + 1
y2_rel = y2 / (max(y2) - min(y2)) - min(y2)
y2_rel = y2_rel - max(y2_rel) + 1
x_diff = x2_rel - x1_rel
y_diff = y2_rel - y1_rel
for (time in times){
count = count + 1
xtmp = x1_rel + x_diff * time
ytmp = y1_rel + y_diff * time
print(count)
png(paste0(path, "SmoothGraph_", IntFormat(count, nbdigits=nbdigits), ".png"))
plot(x=xtmp, y=ytmp, ...)
dev.off()
}
system (command="
cd /Users/remi/Desktop/
convert SmoothGraph_*.png -delay 1 SmoothGraph.gif
rm SmoothGraph_*.png
")
}
SmoothGraph(x1=rnorm(12), y1=mtcars$mpg , x2 = mtcars$wt, y2=mtcars$mpg)
This seems like a good fit for the animation package. You could do something like this. First, define a function that can interpolate between the two plots
framedata<-function(x) {
subset(transform(my_mtcars,
x=rand + x*(wt-rand),
y=mpg
), select=c(x,y))
}
Then you can animate them with
library(animation)
frame <- seq(0, 1, length.out=20)
saveGIF(lapply(frame, function(f) {
print( ggplot(framedata(f), aes(x, y)) + geom_point() )
}), "go.gif", interval = 0.05, loop=1)
This will create a 20 frame animation with a .05 second delay between frames that plays once.

Calculating position of object based on number of objects

I have a simple question but am having a hard time coming up with an elegant solution.
Let's say that my app displays a deck of cards. Each time I draw a card, I want to display it in the center of the screen. When I draw a new card, I want to display that card next to the previous one and both be centered.
So more specifically if my code had the following variables and tables
N = total cards played. Assume N is between 1 and 10.
W = width to separate each card in pixels. For example 30px
C = width of screen / 2 ( center x value for the screen )
P = {} -- which denotes the position of the card and it's new X value. P[1] will be the x value for the first card played.
I want a formula so I can run a loop and calculate the new X value for each card.
Here is my expected output
N = 1, P[1] = C. If there is only 1 card, then the x value of that card will be the center
N = 2, P[1] = C - W/2, P[2] = C + W/2
N = 3, P[1] = C - W, P[2] = C, P[3] = C + W
N = 4, P[1] = C - 3/2 * W, P[2] = C - 1/2 * W, P[3] = C + 1/2 * W, P[4] = C + 3/2 * W
So I need a loop which programatically calculates this for me. Not sure how to do it.
This formula should do the trick:
P[k] = C + W * (k - 1 - (N - 1) / 2)
where k = 1,2,...,N is the number of the card.
The various cases are:
N = 1 => P[k] = C + W * (k - 1)
=> P[1] = C
N = 2 => P[k] = C + W * (k - 1 - 1/2)
=> P[1] = C - W/2, P[2] = C + W/2
N = 3 => P[k] = C + W * (k - 1 - 1)
=> P[1] = C - W, P[2] = C, P[3] = C + W
N = 4 => P[k] = C + W * (k - 1 - 3/2)
=> P[1] = C - 3W/2, P[2] = C - W/2, P[3] = C + W/2, P[4] = C + 3W/2
...
You can wrap the formula in a nifty function, as in the following test program, which produces more or less the same scheme above:
local C = 10
local W = 20
local function CardPosition( k, N )
return C + W * (k - 1 - (N - 1) / 2)
end
for N = 1, 5 do
io.write( "N = ", N, " => P[k] = ",
C, " + ", W, " * (k - 1 - ", N - 1, "/2) \n" )
io.write " => "
for k = 1, N do
io.write( "P[", k,"] = ", CardPosition(k, N), ", " )
end
io.write "\n\n"
end
You can easily spot that P[1] = C - (N-1)/2 * W in the cases you described. This is generally true, because the total width increases linearly with the number of cards.
Other cards' positions can be computed with the help of the expression: P[x] = P[x-1] + W.

How to calculate number of rectangles in rectangular grid?

I want to calculate number of rectangles in a rectangles.It can be done using formula
(x^2+x)(y^2+y)/4
but it also includes perfect squares like 1*1,2*2,3*3 etc.I dont want to include that in my calculations.How can i do that?
Ok, you have the number of rectangles with integer coordinates between the points (0, 0), (x, 0), (x, y) and (0, y), x and y being integers too. You now need to remove the perfect squares from this sum.
To compute it, let's evaluate the number of squares 1*1: there are obviously x*y of them. For squares 2*2, we have x-1 choices for the x-coordinate and y-1 for the y-coordinate of the bottom left-hand corner of such a square, due to the width of this square: this results in (x-1)*(y-1) squares. Idem, we will have (x-2)*(y-2) squares 3*3, etc.
So for a given i, we have (x - i + 1) * (y - i + 1) squares i*i, and i goes from 1 to the minimum of x and y (of course if x is 4 and y is 7, we cannot have a square with a side greater than 4).
So if m = min(x, y), we have:
Sum_Squares = Sum(i = 1, i = m, (x - i + 1) * (y - i + 1))
= Sum(j = 0, j = m - 1, (x - i) * (y - i))
= Sum(j = 0, j = m - 1, x*y - (x+y)*j + j^2)
= m*x*y - (x+y)*Sum(j = 0, j = m - 1, j) + Sum(j = 0, j = m - 1, j^2)
= m*x*y - (x+y)*Sum(j = 1, j = m - 1, j) + Sum(j = 1, j = m - 1, j^2)
= m*x*y - (x+y)*m*(m-1)/2 + (m-1)*m*(2*m-1)/6
I get that with an index change (j = i - 1) and via the well-known formulas:
Sum(i = 1, i = n, j) = n*(n + 1)/2
Sum(i = 1, i = n, j^2) = n*(n + 1)*(2*n + 1)/6
You just have to remove this Sum_Squares from (x^2+x)(y^2+y)/4 and you're done !

Resources