Check logic for altitude of a triangle using d3 - math

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

Related

Positioning objects parallel with a mesh

I'm trying to align multiple line objects along a human body circumference depending on the orientation of the triangles from the mesh. I would like to put the lines parallel to the mesh. I correctly assign the position for the lines along the circumference, but I also need to add the rotation of the lines such that to be parallel with the body.
The body is a mesh formed by multiple triangles and every line is "linked" with a triangle.
All I have is:
3 points for the closest triangle from the mesh for every line
The normal of the triangle
The positions for the instantiated lines (2 points, start and end)
I need to calculate the angle for every X, Y, Z axes for the line such that the normal of the triangle is perpendicular with the line mesh. I don't know how to get the desired angle. I really appreciate if someone would like to help me.
input:
FVector TrianglePoints[3];
FVector Triangle_Normal; //Calculated as (B-A)^(C-A), where A,B,C are the points of the triangle
FVector linePosition; //I also have the start line and the endLine position if that helps
ouput:
//FRotator rotation(x,y,z), such that the triangle normal and the line object to be perpendicular.
An overview of the circumference line construction. Now the rotation is calculated using the Start position and End position for each line. When we cross some irregular parts of the mesh we want to rotate the lines correctly. Now the rotation is fixed, depending just on the line start and end position.
If I have understood correctly your goal, here is some related vector geometry:
A,B,C are the vertices of the triangle:
A = [xA, yA, zA],
B = [xB, yB, zB]
C = [xC, yC, zC]
K,L are the endpoints of the line-segment:
K = [xK, yK, zK]
L = [xL, yL, zL]
vectors are interpreted as row-vectors
by . I denote matrix multiplication
by x I denote cross product of 3D vectors
by t() I denote the transpose of a matrix
by | | I denote the norm (magnitude) of a vector
Goal: find the rotation matrix and rotation transformation of segment KL
around its midpoint, so that after rotation KL is parallel to the plane ABC
also, the rotation is the "minimal" angle rotation by witch we need to
rotate KL in order to make it parallel to ABC
AB = B - A
AC = C - A
KL = L - K
n = AB x AC
n = n / |n|
u = KL x n
u = u / |u|
v = n x u
cos = ( KL . t(v) ) / |KL|
sin = ( KL . t(n) ) / |KL|
U = [[ u[0], u[1], u[2] ],
[ v[0], v[1], v[2] ],
[ n[0], n[1], n[2] ],
R = [[1, 0, 0],
[0, cos, sin],
[0, -sin, cos]]
ROT = t(U).R.U
then, one can rotate the segment KL around its midpoint
M = (K + L)/2
Y = M + ROT (X - M)
Here is a python script version
A = np.array([0,0,0])
B = np.array([3,0,0])
C = np.array([2,3,0])
K = np.array([ -1,0,1])
L = np.array([ 2,2,2])
KL = L-K
U = np.empty((3,3), dtype=float)
U[2,:] = np.cross(B-A, C-A)
U[2,:] = U[2,:] / np.linalg.norm(U[2,:])
U[0,:] = np.cross(KL, U[2,:])
U[0,:] = U[0,:] / np.linalg.norm(U[0,:])
U[1,:] = np.cross(U[2,:], U[0,:])
norm_KL = np.linalg.norm(KL)
cos_ = KL.dot(U[1,:]) / norm_KL
sin_ = KL.dot(U[2,:]) / norm_KL
R = np.array([[1, 0, 0],
[0, cos_, sin_],
[0,-sin_, cos_]])
ROT = (U.T).dot(R.dot(U))
M = (K+L) / 2
K_rot = M + ROT.dot( K - M )
L_rot = M + ROT.dot( L - M )
print(L_rot)
print(K_rot)
print(L_rot-K_rot)
print((L_rot-K_rot).dot(U[2,:]))
A more inspired solution was to use a procedural mesh, generated at runtime, that have all the requirements that I need:
Continuously along multiple vertices
Easy to apply a UV map for texture tiling
Can be updated at runtime
Isn't hard to compute/work with it

Get vertex value that shapes 90 degrees with triangle centroid

I have this triangle:
I'm trying to get the vertex value highlighted in the green circle in order to draw that red line. Is there any equation that I can use to extract that value?
The centroid vertex G = (x=5.5, y=1.5)
The other vertex B = (x=0, y=1)
and the last vertex C = (x=7, y=0)
Any help would be appreciated. I know it might be a 5th grade math but I can't think of a way to calculate this point.
If you throw away the majority of the triangle and just keep the vector B->G and the vector B->C then this problem shows itself to be a "vector projection" problem.
These are solved analytically using the dot product of the 2 vectors and are well documented elsewhere.
Took me 2 days to figure this out, you basically need to get the slopes for the base vector and the altitude vector (centroid), then solve this equation: y = m * x + b for both vectors (the base + altitude). Then you'll get 2 different equations that you need to use substitution to get the x first then apply that value to the 2nd equation to get the y. For more information watch this youtube tutorial:
https://www.youtube.com/watch?v=VuEbWkF5lcM
Here's the solution in PHP (pseudo) if anyone is interested:
//slope of base
$m1 = getSlope(baseVector);
//slope of altitude (invert and divide it by 1)
$m2 = 1/-$m1;
//points
$x1 = $baseVector->x;
$y1 = $baseVector->y;
//Centroid vertex
$x2 = $center['x'];
$y2 = $center['y'];
//altitude equation: y = m * x + b
//eq1: y1 = (m1 * x1) + b1 then find b1
$b1 = -($m1 * $x1) + $y1;
//equation: y = ($m1 * x) + $b1
//eq2: y2 = (m2 * x2) + b2 then find b2
$b2 = -($m2 * $x2) + $y2;
//equation: y = ($m2 * x) + $b2;
//substitute eq1 into eq2 and find x
//merge the equations (move the Xs to the left side and numbers on the right side)
$Xs = $m1 - $m2; //left side (number of Xs)
$Bs = $b2 - $b1; //right side
$x = $Bs / $Xs; //get x number
$y = ($m2 * $x) + $b2; //get y number

how do i transform between a static and a dynamic coordinate system

i have a setup like this:
2 coordinate systems. (x,y) is the main coordinate system and (x',y') is a coordinate system that lives inside (x,y). The system (x',y') is defined by the points x1 or x2 and if i move these 2 points around then (x',y') moves accordingly. The origin of (x',y') is defined as the middle of the vector going from x1 to x2, and the y' axis is the normal vector on x1->x2 going through the origin. If i have a point x3 defined in (x',y') and i move either of x1 or x2 to make the origin shift place, how do i then move x3 accordingly such that it maintains its position in the new (x',y') ?
And how do i make a transformation which always converts a point in (x,y) to a point in (x',y') nomatter how x1 and x2 have been set?
I was thinking that if i had more points than just the one i am moving (x1 or x2) i guess i could try to estimate theta, tx, ty of the transformation
[x2'] [cos(theta) , sin(theta), tx][x2]
[y2'] = [-sin(theta), cos(theta), ty][y2]
[ 1 ]  [ 0 , 0 , 1 ][1 ]
and just apply that estimated transformation to x3 and i would be good...mmm but i think i would need 3 points in order to estimate theta, tx and ty right?
I mean i could estimate using some least squares approach...but 3 unknowns requires 3 coordinate sets right?
I tried to implement this and calculate an example. I hope you understand the syntax. Its not really giving me what i expect:
import math
import numpy as np
x1=[ 0,10]
x2=[10,20]
rx = x2[0] - x1[0]
ry = x2[1] - x1[1]
rlen = math.sqrt(rx*rx+ry*ry)
c = rx / rlen
s = ry / rlen
dx = - ( x1[0] + x2[0] )/2 # changing the sign to be negative seems to
dy = - ( x1[1] + x2[1] )/2 # rectify translation. Rotation still is wrong
M = np.array([[c, -s, 0],[s, c, 0],[dx, dy, 1]])
print( np.dot(x2 + [1],M) )
# Yields -> [ 15.92031022 -8.63603897 1. ] and should yield [5,0,1]
Since I am trying to transform the x2 coordinate, should the result then not have the value 0 in the y-component since its located in the x-axis?
Ok, I tried doing the implementation for x3 from dynamic1 to dynamic2 which the check is that x3 should end up with the same coordinate in both d1 and d2. I did that as you suggested, but I do not get the same coordinate in both d1 and d2. Did i misunderstand something?
import math
import numpy as np
x1=[ 1,1]
x2=[ 7,9]
x3=[4,3]
rx = (x2[0] - x1[0])
ry = (x2[1] - x1[1])
rlen = math.sqrt( rx*rx + ry*ry )
c = rx / rlen
s = ry / rlen
dx = ( x1[0] + x2[0] )/2
dy = ( x1[1] + x2[1] )/2
M = np.array([[c, -s, 0],[s, c, 0],[-dx*c-dy*s, dx*s-dy*c, 1]])
Minv = np.array([[c, s, 0],[-s, c, 0],[dx, dy, 1]])
x1new=[ 1,1]
x2new=[ 17,4]
rxnew = (x2new[0] - x1new[0])
rynew = (x2new[1] - x1new[1])
rlennew = math.sqrt( rxnew*rxnew + rynew*rynew )
cnew = rxnew / rlennew
snew = rynew / rlennew
dxnew = ( x1new[0] + x2new[0] )/2
dynew = ( x1new[1] + x2new[1] )/2
Mnew = np.array([[cnew, -snew, 0],[snew, cnew, 0],[-dxnew*cnew-dynew*snew, dxnew*snew-dynew*cnew, 1]])
Mnewinv = np.array([[cnew, snew, 0],[-snew, cnew, 0],[dxnew, dynew, 1]])
M_dyn1_to_dyn2 = np.dot(Minv,Mnew)
print( np.dot(x3 + [1], M) )
print( np.dot(x3 + [1], M_dyn1_to_dyn2))
#yields these 2 outputs which should be the same:
[-1.6 -1.2 1. ]
[-3.53219692 8.29298408 1. ]
Edit. Matrix correction.
To translate coordinates from static system to (x1,x2) defined one, you have to apply affine transformation.
Matrix of this transformation M consists of shift matrix S and rotation about origin R.
Matrix M is combination of S and R:
c -s 0
M = s c 0
-dx*c-dy*s dx*s-dy*c 1
Here c and s are cosine and sine of rotation angle, their values are respectively x- and y- components of unit (normalized) vector x1x2.
rx = x2.x - x1.x
ry = x2.y - x1.y
len = Sqrt(rx*rx+ry*ry)
c = rx / Len
s = ry / Len
And shift components:
dx = (x1.x + x2.x)/2
dy = (x1.y + x2.y)/2
To translate (xx,yy) coordinates from static system to rotate one, we have to find
xx' = xx*c+yy*s-dx*c-dy*s = c*(xx-dx) + s*(yy-dy)
yy' = -xx*s+yy*c+dx*s-dy*c = -s*(xx-dx) + c*(yy-dy)
Quick check:
X1 = (1,1)
X2 = (7,9)
dx = 4
dy = 5
rx = 6
ry = 8
Len = 10
c = 0.6
s = 0.8
for point (4,5):
xx-dx = 0
yy-dy = 0
xx',yy' = (0, 0) - right
for point X2 =(7,9):
xx-dx = 3
yy-dy = 4
xx' = 0.6*3 + 0.8*4 = 5 -right
yy' = -0.8*3 + 0.6*4 = 0 -right
P.S. Note that matrix to transform dyn.coordinates to static ones is inverse of M and it is simpler:
c s 0
M' = -s c 0
dx dy 1
P.P.S. You need three pairs of corresponding points to define general affine transformations. It seems here you don't need scaling and sheer, so you may determine needed transform with your x1,x2 points
I think you need double dimension array to save and set your value in that
the structure gonna be like this
=============|========|========|
index number |x |y |
=============|========|========|
first point | [0][0] | [0][1] |
second point | [1][0] | [1][1] |
third point | [2][0] | [2][1] |
=============|========|========|
I will use java in my answer
//declare the double dimension array
double matrix[][] = new double[3][2];
//setting location first point, x
matrix[0][0] = 1;
//setting location first point, y
matrix[0][1] = 1;
//fill with your formula, i only give example
//fill second point with first point and plus 1
//setting location second point, x
matrix[1][0] = matrix[0][0] + 1;
//setting location second point, y
matrix[1][1] = matrix[0][1] + 1;
//fill with your formula, i only give example
//fill third point with second point and plus 1
//setting location third point, x
matrix[2][0] = matrix[1][0] + 1;
//setting location third point, y
matrix[2][1] = matrix[1][1] + 1;

Perpendicular on a line segment from a given point

I want to calculate a point on a given line that is perpendicular from a given point.
I have a line segment AB and have a point C outside line segment. I want to calculate a point D on AB such that CD is perpendicular to AB.
I have to find point D.
It quite similar to this, but I want to consider to Z coordinate also as it does not show up correctly in 3D space.
Proof:
Point D is on a line CD perpendicular to AB, and of course D belongs to AB.
Write down the Dot product of the two vectors CD.AB = 0, and express the fact D belongs to AB as D=A+t(B-A).
We end up with 3 equations:
Dx=Ax+t(Bx-Ax)
Dy=Ay+t(By-Ay)
(Dx-Cx)(Bx-Ax)+(Dy-Cy)(By-Ay)=0
Subtitute the first two equations in the third one gives:
(Ax+t(Bx-Ax)-Cx)(Bx-Ax)+(Ay+t(By-Ay)-Cy)(By-Ay)=0
Distributing to solve for t gives:
(Ax-Cx)(Bx-Ax)+t(Bx-Ax)(Bx-Ax)+(Ay-Cy)(By-Ay)+t(By-Ay)(By-Ay)=0
which gives:
t= -[(Ax-Cx)(Bx-Ax)+(Ay-Cy)(By-Ay)]/[(Bx-Ax)^2+(By-Ay)^2]
getting rid of the negative signs:
t=[(Cx-Ax)(Bx-Ax)+(Cy-Ay)(By-Ay)]/[(Bx-Ax)^2+(By-Ay)^2]
Once you have t, you can figure out the coordinates for D from the first two equations.
Dx=Ax+t(Bx-Ax)
Dy=Ay+t(By-Ay)
function getSpPoint(A,B,C){
var x1=A.x, y1=A.y, x2=B.x, y2=B.y, x3=C.x, y3=C.y;
var px = x2-x1, py = y2-y1, dAB = px*px + py*py;
var u = ((x3 - x1) * px + (y3 - y1) * py) / dAB;
var x = x1 + u * px, y = y1 + u * py;
return {x:x, y:y}; //this is D
}
There is a simple closed form solution for this (requiring no loops or approximations) using the vector dot product.
Imagine your points as vectors where point A is at the origin (0,0) and all other points are referenced from it (you can easily transform your points to this reference frame by subtracting point A from every point).
In this reference frame point D is simply the vector projection of point C on the vector B which is expressed as:
// Per wikipedia this is more efficient than the standard (A . Bhat) * Bhat
Vector projection = Vector.DotProduct(A, B) / Vector.DotProduct(B, B) * B
The result vector can be transformed back to the original coordinate system by adding point A to it.
A point on line AB can be parametrized by:
M(x)=A+x*(B-A), for x real.
You want D=M(x) such that DC and AB are orthogonal:
dot(B-A,C-M(x))=0.
That is: dot(B-A,C-A-x*(B-A))=0, or dot(B-A,C-A)=x*dot(B-A,B-A), giving:
x=dot(B-A,C-A)/dot(B-A,B-A) which is defined unless A=B.
What you are trying to do is called vector projection
Here i have converted answered code from "cuixiping" to matlab code.
function Pr=getSpPoint(Line,Point)
% getSpPoint(): find Perpendicular on a line segment from a given point
x1=Line(1,1);
y1=Line(1,2);
x2=Line(2,1);
y2=Line(2,1);
x3=Point(1,1);
y3=Point(1,2);
px = x2-x1;
py = y2-y1;
dAB = px*px + py*py;
u = ((x3 - x1) * px + (y3 - y1) * py) / dAB;
x = x1 + u * px;
y = y1 + u * py;
Pr=[x,y];
end
I didn't see this answer offered, but Ron Warholic had a great suggestion with the Vector Projection. ACD is merely a right triangle.
Create the vector AC i.e (Cx - Ax, Cy - Ay)
Create the Vector AB i.e (Bx - Ax, By - Ay)
Dot product of AC and AB is equal to the cosine of the angle between the vectors. i.e cos(theta) = ACx*ABx + ACy*ABy.
Length of a vector is sqrt(x*x + y*y)
Length of AD = cos(theta)*length(AC)
Normalize AB i.e (ABx/length(AB), ABy/length(AB))
D = A + NAB*length(AD)
For anyone who might need this in C# I'll save you some time:
double Ax = ;
double Ay = ;
double Az = ;
double Bx = ;
double By = ;
double Bz = ;
double Cx = ;
double Cy = ;
double Cz = ;
double t = ((Cx - Ax) * (Bx - Ax) + (Cy - Ay) * (By - Ay)) / (Math.Pow(Bx - Ax, 2) + Math.Pow(By - Ay, 2));
double Dx = Ax + t*(Bx - Ax);
double Dy = Ay + t*(By - Ay);
Here is another python implementation without using a for loop. It works for any number of points and any number of line segments. Given p_array as a set of points, and x_array , y_array as continues line segments or a polyline.
This uses the equation Y = mX + n and considering that the m factor for a perpendicular line segment is -1/m.
import numpy as np
def ortoSegmentPoint(self, p_array, x_array, y_array):
"""
:param p_array: np.array([[ 718898.941 9677612.901 ], [ 718888.8227 9677718.305 ], [ 719033.0528 9677770.692 ]])
:param y_array: np.array([9677656.39934991 9677720.27550726 9677754.79])
:param x_array: np.array([718895.88881594 718938.61392781 718961.46])
:return: [POINT, LINE] indexes where point is orthogonal to line segment
"""
# PENDIENTE "m" de la recta, y = mx + n
m_array = np.divide(y_array[1:] - y_array[:-1], x_array[1:] - x_array[:-1])
# PENDIENTE INVERTIDA, 1/m
inv_m_array = np.divide(1, m_array)
# VALOR "n", y = mx + n
n_array = y_array[:-1] - x_array[:-1] * m_array
# VALOR "n_orto" PARA LA RECTA PERPENDICULAR
n_orto_array = np.array(p_array[:, 1]).reshape(len(p_array), 1) + inv_m_array * np.array(p_array[:, 0]).reshape(len(p_array), 1)
# PUNTOS DONDE SE INTERSECTAN DE FORMA PERPENDICULAR
x_intersec_array = np.divide(n_orto_array - n_array, m_array + inv_m_array)
y_intersec_array = m_array * x_intersec_array + n_array
# LISTAR COORDENADAS EN PARES
x_coord = np.array([x_array[:-1], x_array[1:]]).T
y_coord = np.array([y_array[:-1], y_array[1:]]).T
# FILAS: NUMERO DE PUNTOS, COLUMNAS: NUMERO DE TRAMOS
maskX = np.where(np.logical_and(x_intersec_array < np.max(x_coord, axis=1), x_intersec_array > np.min(x_coord, axis=1)), True, False)
maskY = np.where(np.logical_and(y_intersec_array < np.max(y_coord, axis=1), y_intersec_array > np.min(y_coord, axis=1)), True, False)
mask = maskY * maskX
return np.argwhere(mask == True)
As Ron Warholic and Nicolas Repiquet answered, this can be solved using vector projection. For completeness I'll add a python/numpy implementation of this here in case it saves anyone else some time:
import numpy as np
# Define some test data that you can solve for directly.
first_point = np.array([4, 4])
second_point = np.array([8, 4])
target_point = np.array([6, 6])
# Expected answer
expected_point = np.array([6, 4])
# Create vector for first point on line to perpendicular point.
point_vector = target_point - first_point
# Create vector for first point and second point on line.
line_vector = second_point - first_point
# Create the projection vector that will define the position of the resultant point with respect to the first point.
projection_vector = (np.dot(point_vector, line_vector) / np.dot(line_vector, line_vector)) * line_vector
# Alternative method proposed in another answer if for whatever reason you prefer to use this.
_projection_vector = (np.dot(point_vector, line_vector) / np.linalg.norm(line_vector)**2) * line_vector
# Add the projection vector to the first point
projected_point = first_point + projection_vector
# Test
(projected_point == expected_point).all()
Since you're not stating which language you're using, I'll give you a generic answer:
Just have a loop passing through all the points in your AB segment, "draw a segment" to C from them, get the distance from C to D and from A to D, and apply pithagoras theorem. If AD^2 + CD^2 = AC^2, then you've found your point.
Also, you can optimize your code by starting the loop by the shortest side (considering AD and BD sides), since you'll find that point earlier.
Here is a python implementation based on Corey Ogburn's answer from this thread.
It projects the point q onto the line segment defined by p1 and p2 resulting in the point r.
It will return null if r falls outside of line segment:
def is_point_on_line(p1, p2, q):
if (p1[0] == p2[0]) and (p1[1] == p2[1]):
p1[0] -= 0.00001
U = ((q[0] - p1[0]) * (p2[0] - p1[0])) + ((q[1] - p1[1]) * (p2[1] - p1[1]))
Udenom = math.pow(p2[0] - p1[0], 2) + math.pow(p2[1] - p1[1], 2)
U /= Udenom
r = [0, 0]
r[0] = p1[0] + (U * (p2[0] - p1[0]))
r[1] = p1[1] + (U * (p2[1] - p1[1]))
minx = min(p1[0], p2[0])
maxx = max(p1[0], p2[0])
miny = min(p1[1], p2[1])
maxy = max(p1[1], p2[1])
is_valid = (minx <= r[0] <= maxx) and (miny <= r[1] <= maxy)
if is_valid:
return r
else:
return None

Draw Lines Over a Circle

There's a line A-B and C at the center between A and B. It forms a circle as in the figure. If we assume A-B line as a diameter of the circle and then C is it's center. My problem is I have no idea how to draw another three lines (in blue) each 45 degree away from AC or AB. No, this is not a homework, it's part of my complex geometry in a rendering.
alt text http://www.freeimagehosting.net/uploads/befcd84d8c.png
There are a few ways to solve this problem, one of which is to find the angle of the line and then add 45 degrees to this a few times. Here's an example, it's in Python, but translating the math should be easy (and I've tried to write the Python in a simplistic way).
Here's the output for a few lines:
The main function is calc_points, the rest is just to give it A and B that intersect the circle, and make the plots.
from math import atan2, sin, cos, sqrt, pi
from matplotlib import pyplot
def calc_points(A, B, C):
dx = C[0]-A[0]
dy = C[1]-A[1]
line_angle = atan2(dy, dx)
radius = sqrt(dy*dy + dx*dx)
new_points = []
# now go around the circle and find the points
for i in range(3):
angle = line_angle + (i+1)*45*(pi/180) # new angle in radians
x = radius*cos(angle) + C[0]
y = radius*sin(angle) + C[1]
new_points.append([x, y])
return new_points
# test this with some reasonable values
pyplot.figure()
for i, a in enumerate((-20, 20, 190)):
radius = 5
C = [2, 2]
# find an A and B on the circle and plot them
angle = a*(pi/180)
A = [radius*cos(pi+angle)+C[0], radius*sin(pi+angle)+C[1]]
B = [radius*cos(angle)+C[0], radius*sin(angle)+C[1]]
pyplot.subplot(1,3,i+1)
pyplot.plot([A[0], C[0]], [A[1], C[1]], 'r')
pyplot.plot([B[0], C[0]], [B[1], C[1]], 'r')
# now run these through the calc_points function and the new lines
new_points = calc_points(A, B, C)
for np in new_points:
pyplot.plot([np[0], C[0]], [np[1], C[1]], 'b')
pyplot.xlim(-8, 8)
pyplot.ylim(-8, 8)
for x, X in (("A", A), ("B", B), ("C", C)):
pyplot.text(X[0], X[1], x)
pyplot.show()
If you want to find coordinates of blue lines, may be you will find helpful some information about tranformations (rotations):
http://en.wikipedia.org/wiki/Rotation_matrix
You need to rotate for example vector AC and then you can find coordinate of end point of blue line.
start with this and add a button with code:
private void btnCircleLined_Click(object sender, System.EventArgs e)
{
Graphics graph = Graphics.FromImage(DrawArea);
int x = 100, y = 100, diameter = 50;
myPen.Color = Color.Green;
myPen.Width = 10;
graph.DrawEllipse(myPen, x, y, diameter, diameter);
myPen.Color = Color.Red;
double radian = 45 * Math.PI / 180;
int xOffSet = (int)(Math.Cos(radian) * diameter / 2);
int yOffSet = (int)(Math.Sin(radian) * diameter / 2);
graph.DrawLine(myPen, x, y + yOffSet + myPen.Width + diameter / 2, x + xOffSet + myPen.Width + diameter / 2, y);
graph.DrawLine(myPen, x, y, x + xOffSet + myPen.Width + diameter / 2, y + yOffSet + myPen.Width + diameter / 2);
graph.Dispose();
this.Invalidate();
}
edit: could not see your picture so I misinterpeted your question, but this should get you started.
Translate A with C at the origin (i.e. A-C), rotate CW 45°, then translate back. Repeat three more times.
If I were doing this I'd use polar co-ordinates (apologies for including the link if you are already well aware what they are) as an easy way of figuring out the co-ordinates of the points on the circumference that you need. Then draw lines to there from the centre of the circle.

Resources