How to implement rounded corners in javascript?
Following is the code in C# for drawing rounded corners.
Some geometry with Paint:
0. You have a corner:
![Corner][1]
1. You know the coordinates of corner points, let it be P1, P2 and P:
![Points of corner][2]
2. Now you can get vectors from points and angle between vectors:
![Vectors and angle][3]
angle = atan(PY - P1Y, PX - P1X) - atan(PY - P2Y, PX - P2X)
3. Get the length of segment between angular point and the points of intersection with the circle.
![Segment][4]
segment = PC1 = PC2 = radius / |tan(angle / 2)|
4. Here you need to check the length of segment and the minimal length from PP1 and PP2:
![Minimal length][5]
Length of PP1:
PP1 = sqrt((PX - P1X)2 + (PY - P1Y)2)
Length of PP2:
PP2 = sqrt((PX - P2X)2 + (PY - P2Y)2)
If segment > PP1 or segment > PP2 then you need to decrease the radius:
min = Min(PP1, PP2) (for polygon is better to divide this value by 2)
segment > min ?
segment = min
radius = segment * |tan(angle / 2)|
5. Get the length of PO:
PO = sqrt(radius2 + segment2)
6. Get the C1X and C1Y by the proportion between the coordinates of the vector, length of vector and the length of the segment:
![Coordinates of PC1][6]
Proportion:
(PX - C1X) / (PX - P1X) = PC1 / PP1
So:
C1X = PX - (PX - P1X) * PC1 / PP1
The same for C1Y:
C1Y = PY - (PY - P1Y) * PC1 / PP1
7. Get the C2X and C2Y by the same way:
C2X = PX - (PX - P2X) * PC2 / PP2
C2Y = PY - (PY - P2Y) * PC2 / PP2
8. Now you can use the addition of vectors PC1 and PC2 to find the centre of circle by the same way by proportion:
![Addition of vectors][7]
(PX - OX) / (PX - CX) = PO / PC
(PY - OY) / (PY - CY) = PO / PC
Here:
CX = C1X + C2X - PX
CY = C1Y + C2Y - PY
PC = sqrt((PX - CX)2 + (PY - CY)2)
Let:
dx = PX - CX = PX * 2 - C1X - C2X
dy = PY - CY = PY * 2 - C1Y - C2Y
So:
PC = sqrt(dx2 + dy2)
OX = PX - dx * PO / PC
OY = PY - dy * PO / PC
9. Here you can draw an arc. For this you need to get start angle and end angle of arc:
![Arc][8]
Found it [here][9]:
startAngle = atan((C1Y - OY) / (C1X - OX))
endAngle = atan((C2Y - OY) / (C2X - OX))
10. At last you need to get a sweep angle and make some checks for it:
![Sweep angle][10]
sweepAngle = endAngle - startAngle
If sweepAngle < 0 then swap startAngle and endAngle, and invert sweepAngle:
sweepAngle < 0 ?
sweepAngle = - sweepAngle
startAngle = endAngle
Check if sweepAngle > 180 degrees:
sweepAngle > 180 ?
sweepAngle = 180 - sweepAngle
11. And now you can draw a rounded corner:
![The result][11]
Some geometry with c#:
private void DrawRoundedCorner(Graphics graphics, PointF angularPoint,
PointF p1, PointF p2, float radius)
{
//Vector 1
double dx1 = angularPoint.X - p1.X;
double dy1 = angularPoint.Y - p1.Y;
//Vector 2
double dx2 = angularPoint.X - p2.X;
double dy2 = angularPoint.Y - p2.Y;
//Angle between vector 1 and vector 2 divided by 2
double angle = (Math.Atan2(dy1, dx1) - Math.Atan2(dy2, dx2)) / 2;
// The length of segment between angular point and the
// points of intersection with the circle of a given radius
double tan = Math.Abs(Math.Tan(angle));
double segment = radius / tan;
//Check the segment
double length1 = GetLength(dx1, dy1);
double length2 = GetLength(dx2, dy2);
double length = Math.Min(length1, length2);
if (segment > length)
{
segment = length;
radius = (float)(length * tan);
}
// Points of intersection are calculated by the proportion between
// the coordinates of the vector, length of vector and the length of the segment.
var p1Cross = GetProportionPoint(angularPoint, segment, length1, dx1, dy1);
var p2Cross = GetProportionPoint(angularPoint, segment, length2, dx2, dy2);
// Calculation of the coordinates of the circle
// center by the addition of angular vectors.
double dx = angularPoint.X * 2 - p1Cross.X - p2Cross.X;
double dy = angularPoint.Y * 2 - p1Cross.Y - p2Cross.Y;
double L = GetLength(dx, dy);
double d = GetLength(segment, radius);
var circlePoint = GetProportionPoint(angularPoint, d, L, dx, dy);
//StartAngle and EndAngle of arc
var startAngle = Math.Atan2(p1Cross.Y - circlePoint.Y, p1Cross.X - circlePoint.X);
var endAngle = Math.Atan2(p2Cross.Y - circlePoint.Y, p2Cross.X - circlePoint.X);
//Sweep angle
var sweepAngle = endAngle - startAngle;
//Some additional checks
if (sweepAngle < 0)
{
startAngle = endAngle;
sweepAngle = -sweepAngle;
}
if (sweepAngle > Math.PI)
sweepAngle = Math.PI - sweepAngle;
//Draw result using graphics
var pen = new Pen(Color.Black);
graphics.Clear(Color.White);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.DrawLine(pen, p1, p1Cross);
graphics.DrawLine(pen, p2, p2Cross);
var left = circlePoint.X - radius;
var top = circlePoint.Y - radius;
var diameter = 2 * radius;
var degreeFactor = 180 / Math.PI;
graphics.DrawArc(pen, left, top, diameter, diameter,
(float)(startAngle * degreeFactor),
(float)(sweepAngle * degreeFactor));
}
private double GetLength(double dx, double dy)
{
return Math.Sqrt(dx * dx + dy * dy);
}
private PointF GetProportionPoint(PointF point, double segment,
double length, double dx, double dy)
{
double factor = segment / length;
return new PointF((float)(point.X - dx * factor),
(float)(point.Y - dy * factor));
}
To get points of arc you can use this:
//One point for each degree. But in some cases it will be necessary
// to use more points. Just change a degreeFactor.
int pointsCount = (int)Math.Abs(sweepAngle * degreeFactor);
int sign = Math.Sign(sweepAngle);
PointF[] points = new PointF[pointsCount];
for (int i = 0; i < pointsCount; ++i)
{
var pointX =
(float)(circlePoint.X
+ Math.Cos(startAngle + sign * (double)i / degreeFactor)
* radius);
var pointY =
(float)(circlePoint.Y
+ Math.Sin(startAngle + sign * (double)i / degreeFactor)
* radius);
points[i] = new PointF(pointX, pointY);
}
I've implemented this is javascript:
let radius = 10;
const angle =
Math.atan(p.x - p1.x, p.x - p1.x) - Math.atan(p.y - p2.y, p.x - p2.x);
let segment = radius / Math.abs(Math.tan(angle / 2));
const pp1 = Math.sqrt(Math.pow(p.x - p1.x, 2) + Math.pow(p.y - p1.y, 2));
const pp2 = Math.sqrt(Math.pow(p.x - p2.x, 2) + Math.pow(p.y - p2.y, 2));
const min = Math.min(pp1, pp2);
if (segment > min) {
segment = min;
radius = segment * Math.abs(Math.tan(angle / 2));
}
const po = Math.sqrt(Math.pow(radius, 2) + Math.pow(segment, 2));
const r = 10;
const c1x = p.x - ((p.x - p1.x) * segment) / pp1;
const c1y = p.y - ((p.y - p1.y) * segment) / pp1;
const c2x = p.x - ((p.x - p2.x) * segment) / pp2;
const c2y = p.y - ((p.y - p2.y) * segment) / pp2;
const dx = p.x * 2 - c1x - c2x;
const dy = p.y * 2 - c1y - c2y;
const pc = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
const ox = p.x - (dx * po) / pc;
const oy = p.y - (dy * po) / pc;
let startAngle = Math.atan((c1y - oy) / (c1x - ox));
let endAngle = Math.atan((c2y - oy) / (c2x - ox));
let sweepAngle = endAngle - startAngle;
if (sweepAngle < 0) {
sweepAngle = -sweepAngle;
startAngle = endAngle;
}
if (sweepAngle > 180) sweepAngle = 180 - sweepAngle;
But the issue is that the rounded corners are not getting drawn as expected!
The drawing of arc in c# is different from html canvas arc.
So how can I use the above data to draw it in html5 canvas?
To draw arcs in the html5 canvas, you can use ctx.arc(xPos, yPos, radius, startAngle, endAngle, (optional boolean, defaults to false) counterClockwise);
Documentation can be found at W3Schools.com
More general html5 canvas documentation can also be found at W3Schools.com
Related
for a game I'm building, I need to draw a rectangle on two sides of a line made from two coordinates.
I have an image illustrating this "hard to ask" question.
given coordinates (-4,3) and (3, -4)
given that the width of the rectangle will be 4 (for example)
I need to find all (x1, y1), (x2, y2), (x3, y3), (x4, y4)
** I need to write this in Javascript eventually.
your help is much appreciated.
I've tried to solve this using javascript & canvas. The problem is that the coordinates in canvas are upside down, I suppose you already know this. Also since your rect would be extremely small, I've multiplied your numbers by 10.
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
let cw = canvas.width = 300,
cx = cw / 2;
let ch = canvas.height = 300,
cy = ch / 2;
const rad = Math.PI / 180;
ctx.translate(cx,cy)
//axis
ctx.strokeStyle = "#d9d9d9";
ctx.beginPath();
ctx.moveTo(-cx,0);
ctx.lineTo(cx,0);
ctx.moveTo(0,-cy);
ctx.lineTo(0,cy);
ctx.stroke();
// your data
let p1={x:-40,y:30};
let p2={x:30,y:-40};
// the angle of the initial line
let angle = Math.atan2(p2.y-p1.y, p2.x-p1.x);
// the center of the line
let c =
{ x: p1.x + (p2.x - p1.x)/2,
y: p1.y + (p2.y - p1.y)/2
}
let w = dist(p1, p2);//the width of the rect
let h = 60;//the height of the rect
// draw the initial line
line(p1,p2);
// draw the center as a red point
marker(c);
// calculate the opoints of the rect
function rectPoints(w,h){
let p1 = {
x : c.x -w/2,
y : c.y -h/2
}
let p2 = {
x : c.x + w/2,
y : c.y -h/2
}
let p3 = {
x : c.x + w/2,
y : c.y +h/2
}
let p4 = {
x : c.x -w/2,
y : c.y +h/2
}
// this rotate all the points relative to the center c
return [
rotate(p1,c, angle),
rotate(p2,c, angle),
rotate(p3,c, angle),
rotate(p4,c, angle)
]
}
// draw the rect
ctx.strokeStyle = "blue";
drawRect(rectPoints(w,h));
// some helpful functions
function line(p1,p2){
ctx.beginPath();
ctx.moveTo(p1.x,p1.y);
ctx.lineTo(p2.x,p2.y);
ctx.stroke();
}
function dist(p1, p2) {
let dx = p2.x - p1.x;
let dy = p2.y - p1.y;
return Math.sqrt(dx * dx + dy * dy);
}
function marker(p,color){
ctx.beginPath();
ctx.fillStyle = color || "red";
ctx.arc(p.x,p.y,4,0,2*Math.PI);
ctx.fill();
}
function rotate(p,c, angle){
let cos = Math.cos(angle);
let sin = Math.sin(angle);
return {
x: c.x + (p.x - c.x) * cos - (p.y - c.y) * sin,
y: c.y + (p.x - c.x) * sin + (p.y - c.y) * cos
}
}
function drawRect(points){
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
ctx.lineTo(points[1].x,points[1].y);
ctx.lineTo(points[2].x,points[2].y);
ctx.lineTo(points[3].x,points[3].y);
ctx.lineTo(points[0].x,points[0].y);
ctx.closePath();
ctx.stroke();
}
canvas{border:1px solid #d9d9d9}
<canvas></canvas>
Points A, B form vector
M.X = B.X - A.X
M.Y = B.Y - A.Y
Perpendicular vector
P.X = -M.Y
P.Y = M.X
Length of P:
Len = Math.sqrt(P.X*P.X + P.Y*P.Y)
Normalized (unit) perpendicular:
uP.X = P.X / Len
uP.Y = P.Y / Len
Points
X1 = A.X + uP.X * HalfWidth
Y1 = A.Y + uP.Y * HalfWidth
(X4, Y4) = (A.X - uP.X * HalfWidth, A.Y - uP.Y * HalfWidth)
and similar for points 2 and 3 around B
I have a basic circle bouncing off the walls of a rectangle canvas (that I adapted from an example).
https://jsfiddle.net/n5stvv52/1/
The code to check for this kind of collision is somewhat crude, like so, but it works:
if (p.x > canvasWidth - p.rad) {
p.x = canvasWidth - p.rad
p.velX *= -1
}
if (p.x < p.rad) {
p.x = p.rad
p.velX *= -1
}
if (p.y > canvasHeight - p.rad) {
p.y = canvasHeight - p.rad
p.velY *= -1
}
if (p.y < p.rad) {
p.y = p.rad
p.velY *= -1
}
Where p is the item moving around.
However, the bounds of my canvas now need to be a circle, so I check collision with the following:
const dx = p.x - canvasRadius
const dy = p.y - canvasRadius
const collision = Math.sqrt(dx * dx + dy * dy) >= canvasRadius - p.rad
if (collision) {
console.log('Out of circle bounds!')
}
When my ball hits the edges of the circle, the if (collision) statement executes as true and I see the log. So I can get it detected, but I'm unable to know how to calculate the direction it should then go after that.
Obviously comparing x to the canvas width isn't what I need because that's the rectangle and a circle is cut at the corners.
Any idea how I can update my if statements to account for this newly detected circle?
I'm absolutely terrible with basic trigonometry it seems, so please bear with me! Thank you.
You can use the polar coordinates to normalize the vector:
var theta = Math.atan2(dy, dx)
var R = canvasRadius - p.rad
p.x = canvasRadius + R * Math.cos(theta)
p.y = canvasRadius + R * Math.sin(theta)
p.velX *= -1
p.velY *= -1
https://jsfiddle.net/d3k5pd94/1/
Update: The movement can be more natural if we add randomness to acceleration:
p.velX *= Math.random() > 0.5 ? 1 : -1
p.velY *= Math.random() > 0.5 ? 1 : -1
https://jsfiddle.net/1g9h9jvq/
So in order to do this you will indeed need some good ol' trig. The basic ingredients you'll need are:
The vector that points from the center of the circle to the collision point.
The velocity vector of the ball
Then, since things bounce with roughly an "equal and opposite angle", you'll need to find the angle difference between that velocity vector and the radius vector, which you can get by using a dot product.
Then do some trig to get a new vector that is that much off from the radius vector, in the other direction (this is your equal and opposite). Set that to be the new velocity vector, and you're good to go.
I know that's a bit dense, especially if you're rusty with your trig / vector math, so here's the code to get it going. This code could probably be simplified but it demonstrates the essential steps at least:
function canvasApp (selector) {
const canvas = document.querySelector(selector)
const context = canvas.getContext('2d')
const canvasWidth = canvas.width
const canvasHeight = canvas.height
const canvasRadius = canvasWidth / 2
const particleList = {}
const numParticles = 1
const initVelMax = 1.5
const maxVelComp = 2.5
const randAccel = 0.3
const fadeColor = 'rgba(255,255,255,0.1)'
let p
context.fillStyle = '#050505'
context.fillRect(0, 0, canvasWidth, canvasHeight)
createParticles()
draw()
function createParticles () {
const minRGB = 16
const maxRGB = 255
const alpha = 1
for (let i = 0; i < numParticles; i++) {
const vAngle = Math.random() * 2 * Math.PI
const vMag = initVelMax * (0.6 + 0.4 * Math.random())
const r = Math.floor(minRGB + Math.random() * (maxRGB - minRGB))
const g = Math.floor(minRGB + Math.random() * (maxRGB - minRGB))
const b = Math.floor(minRGB + Math.random() * (maxRGB - minRGB))
const color = `rgba(${r},${g},${b},${alpha})`
const newParticle = {
x: Math.random() * canvasWidth,
y: Math.random() * canvasHeight,
velX: vMag * Math.cos(vAngle),
velY: vMag * Math.sin(vAngle),
rad: 15,
color
}
if (i > 0) {
newParticle.next = particleList.first
}
particleList.first = newParticle
}
}
function draw () {
context.fillStyle = fadeColor
context.fillRect(0, 0, canvasWidth, canvasHeight)
p = particleList.first
// random accleration
p.velX += (1 - 2 * Math.random()) * randAccel
p.velY += (1 - 2 * Math.random()) * randAccel
// don't let velocity get too large
if (p.velX > maxVelComp) {
p.velX = maxVelComp
} else if (p.velX < -maxVelComp) {
p.velX = -maxVelComp
}
if (p.velY > maxVelComp) {
p.velY = maxVelComp
} else if (p.velY < -maxVelComp) {
p.velY = -maxVelComp
}
p.x += p.velX
p.y += p.velY
// boundary
const dx = p.x - canvasRadius
const dy = p.y - canvasRadius
const collision = Math.sqrt(dx * dx + dy * dy) >= canvasRadius - p.rad
if (collision) {
console.log('Out of circle bounds!')
// Center of circle.
const center = [Math.floor(canvasWidth/2), Math.floor(canvasHeight/2)];
// Vector that points from center to collision point (radius vector):
const radvec = [p.x, p.y].map((c, i) => c - center[i]);
// Inverse vector, this vector is one that is TANGENT to the circle at the collision point.
const invvec = [-p.y, p.x];
// Direction vector, this is the velocity vector of the ball.
const dirvec = [p.velX, p.velY];
// This is the angle in radians to the radius vector (center to collision point).
// Time to rememeber some of your trig.
const radangle = Math.atan2(radvec[1], radvec[0]);
// This is the "direction angle", eg, the DIFFERENCE in angle between the radius vector
// and the velocity vector. This is calculated using the dot product.
const dirangle = Math.acos((radvec[0]*dirvec[0] + radvec[1]*dirvec[1]) / (Math.hypot(...radvec)*Math.hypot(...dirvec)));
// This is the reflected angle, an angle that is "equal and opposite" to the velocity vec.
const refangle = radangle - dirangle;
// Turn that back into a set of coordinates (again, remember your trig):
const refvec = [Math.cos(refangle), Math.sin(refangle)].map(x => x*Math.hypot(...dirvec));
// And invert that, so that it points back to the inside of the circle:
p.velX = -refvec[0];
p.velY = -refvec[1];
// Easy peasy lemon squeezy!
}
context.fillStyle = p.color
context.beginPath()
context.arc(p.x, p.y, p.rad, 0, 2 * Math.PI, false)
context.closePath()
context.fill()
p = p.next
window.requestAnimationFrame(draw)
}
}
canvasApp('#canvas')
<canvas id="canvas" width="500" height="500" style="border: 1px solid red; border-radius: 50%;"></canvas>
DISCLAIMER: Since your initial position is random, this doens't work very well with the ball starts already outside of the circle. So make sure the initial point is within the bounds.
You don't need trigonometry at all. All you need is the surface normal, which is the vector from the point of impact to the center. Normalize it (divide both coordinates by the length), and you get the new velocity using
v' = v - 2 * (v • n) * n
Where v • n is the dot product:
v • n = v.x * n.x + v.y * n.y
Translated to your code example, that's
// boundary
const dx = p.x - canvasRadius
const dy = p.y - canvasRadius
const nl = Math.sqrt(dx * dx + dy * dy)
const collision = nl >= canvasRadius - p.rad
if (collision) {
// the normal at the point of collision is -dx, -dy normalized
var nx = -dx / nl
var ny = -dy / nl
// calculate new velocity: v' = v - 2 * dot(d, v) * n
const dot = p.velX * nx + p.velY * ny
p.velX = p.velX - 2 * dot * nx
p.velY = p.velY - 2 * dot * ny
}
function canvasApp(selector) {
const canvas = document.querySelector(selector)
const context = canvas.getContext('2d')
const canvasWidth = canvas.width
const canvasHeight = canvas.height
const canvasRadius = canvasWidth / 2
const particleList = {}
const numParticles = 1
const initVelMax = 1.5
const maxVelComp = 2.5
const randAccel = 0.3
const fadeColor = 'rgba(255,255,255,0.1)'
let p
context.fillStyle = '#050505'
context.fillRect(0, 0, canvasWidth, canvasHeight)
createParticles()
draw()
function createParticles() {
const minRGB = 16
const maxRGB = 255
const alpha = 1
for (let i = 0; i < numParticles; i++) {
const vAngle = Math.random() * 2 * Math.PI
const vMag = initVelMax * (0.6 + 0.4 * Math.random())
const r = Math.floor(minRGB + Math.random() * (maxRGB - minRGB))
const g = Math.floor(minRGB + Math.random() * (maxRGB - minRGB))
const b = Math.floor(minRGB + Math.random() * (maxRGB - minRGB))
const color = `rgba(${r},${g},${b},${alpha})`
const newParticle = {
// start inside circle
x: canvasWidth / 4 + Math.random() * canvasWidth / 2,
y: canvasHeight / 4 + Math.random() * canvasHeight / 2,
velX: vMag * Math.cos(vAngle),
velY: vMag * Math.sin(vAngle),
rad: 15,
color
}
if (i > 0) {
newParticle.next = particleList.first
}
particleList.first = newParticle
}
}
function draw() {
context.fillStyle = fadeColor
context.fillRect(0, 0, canvasWidth, canvasHeight)
// draw circle bounds
context.fillStyle = "black"
context.beginPath()
context.arc(canvasRadius, canvasRadius, canvasRadius, 0, 2 * Math.PI, false)
context.closePath()
context.stroke()
p = particleList.first
// random accleration
p.velX += (1 - 2 * Math.random()) * randAccel
p.velY += (1 - 2 * Math.random()) * randAccel
// don't let velocity get too large
if (p.velX > maxVelComp) {
p.velX = maxVelComp
} else if (p.velX < -maxVelComp) {
p.velX = -maxVelComp
}
if (p.velY > maxVelComp) {
p.velY = maxVelComp
} else if (p.velY < -maxVelComp) {
p.velY = -maxVelComp
}
p.x += p.velX
p.y += p.velY
// boundary
const dx = p.x - canvasRadius
const dy = p.y - canvasRadius
const nl = Math.sqrt(dx * dx + dy * dy)
const collision = nl >= canvasRadius - p.rad
if (collision) {
// the normal at the point of collision is -dx, -dy normalized
var nx = -dx / nl
var ny = -dy / nl
// calculate new velocity: v' = v - 2 * dot(d, v) * n
const dot = p.velX * nx + p.velY * ny
p.velX = p.velX - 2 * dot * nx
p.velY = p.velY - 2 * dot * ny
}
context.fillStyle = p.color
context.beginPath()
context.arc(p.x, p.y, p.rad, 0, 2 * Math.PI, false)
context.closePath()
context.fill()
p = p.next
window.requestAnimationFrame(draw)
}
}
canvasApp('#canvas')
<canvas id="canvas" width="176" height="176"></canvas>
I have been trying to learn creating basic 3d sphere using html5 canvas and I am new to 3d programming. When I googled, I found this incredibly useful article.You can find working example there.
function drawEllipse(ox, oy, oz, or, alpha, beta, gamma, hidden) {
for (var theta=0; theta <=2 * Math.PI; theta += 0.02) {
var px = ox + or * Math.cos(theta);
var py = oy;
var pz = oz + or * Math.sin(theta);
var a = transform(px, py, pz, alpha, beta, gamma);
if (!hidden || a[2] >= 0) {
drawDot(radius * a[0], radius * a[1]);
}
}
}
function drawDot(x, y) {
ctx.fillRect(x, y, 1, 1);
}
/* 3d rotation matrix */
function transform(x, y, z, rz, rx, ry) {
return [
((x * Math.sin(rz) - y * Math.cos(rz)) * Math.sin(rx) + z * Math.cos(rx)) * Math.sin(ry) + (x * Math.cos(rz) - y * Math.sin(rz)) * Math.cos(ry),
(x * Math.sin(rz) - y * Math.cos(rz)) * Math.cos(rx) - z * Math.sin(rx),
((x * Math.sin(rz) - y * Math.cos(rz)) * Math.sin(rx) + z * Math.cos(rx)) * Math.cos(ry) - (x * Math.cos(rz) - y * Math.sin(rz)) * Math.sin(ry)
]
}
/*latitude circles*/
for (var latitude = 0; latitude < Math.PI / 2; latitude += Math.PI / 18) {
drawEllipse(0, Math.sin(latitude), 0,Math.cos(latitude),0, alpha, gamma,true);
drawEllipse(0, -Math.sin(latitude), 0,Math.cos(latitude),0, alpha, gamma,true);
}
/*longitude circles*/
for (var longitude=0 ; longitude < Math.PI; longitude += Math.PI / 18) {
drawEllipse(0, 0, 0,1,longitude, Math.PI / 2 + alpha, gamma,true);
} // alpha and gamma are the x and y axis rotation angles
But the only problem is the direction of rotation when dragging the mouse on the sphere. Yaw and Pitch direction is not correct. Rotating left to right(yaw) working fine. But rotating top to bottom(pitch) is different. Can anyone please find a solution ?
I have a orbit of length 200. But it is centered around a sun of radius 0 (length 0). Now I want to expand the sun to have a radius of 1 and "push" out the outer orbits as well.
The XYZ coordinates look like this:
[-6.76, 5.75, -1.06],
[-6.95, 5.54, -0.91],
[-7.13, 5.33, -0.75],
[-7.31, 5.11, -0.58]
... followed by 196 more coordinates
I tried tried a lot of things to make the circle bigger * radius and / someNumbers. To at least try to do it myself.
But i lost it when i made an if like this:
If(the x coordination > 0)
the x coordination += 1;
}
Else{
the x coordination += 1;
}
And also for Y and Z but when they came close to the 1 and -1 position of that axis they skipped to the other side.
Creating a line (with the width of 1 on both sides) of emptiness along the axis.
Result of MBo's awnser(view from above):
// arrayIndex is a number to remember at which point it is in the orbit array
satellites.forEach(function (element) {
if (element.arrayIndex>= element.satellite.coordinates.length) {
element.arrayIndex= 0;
}
var posX = element.satellite.coordinates[element.arrayIndex][0];
var posY = element.satellite.coordinates[element.arrayIndex][1];
var posZ = element.satellite.coordinates[element.arrayIndex][2];
R = Math.sqrt(posX^2 + posY^2 + posZ^2);
cf = (R + earthRadius) / R;
xnew = posX * cf;
ynew = posY * cf;
znew = posZ * cf;
// var posX = earthRadius * (element.satellite.coordinates[element.test][0] / (200 * earthRadius) * earthRadius);
// var posY = earthRadius * (element.satellite.coordinates[element.test][1] / (200 * earthRadius) * earthRadius);
// var posZ = earthRadius * (element.satellite.coordinates[element.test][2] / (200 * earthRadius) * earthRadius);
// divide by 100 to scale it down some more
element.position.x = xnew / 100;
element.position.y = ynew / 100;
element.position.z = znew / 100;
element.arrayIndex= element.arrayIndex+ 1;
});
You have orbit radius
/////////R = Sqrt(x^2 + y^2 + z^2)
Edit to avoid confusion:
R = Sqrt(x * x + y * y + z * z)
You need to modify coordinates to make orbit radius R+r. To preserve orbit form, for every point find it's R, and multiply all components by coefficient (R+r)/R
R = Sqrt(x^2 + y^2 + z^2)
cf = (R + r) / R
xnew = x * cf
ynew = y * cf
znew = z * cf
I want to draw an equilateral triangle in the middle of canvas. I tried this:
ctx.moveTo(canvas.width/2, canvas.height/2-50);
ctx.lineTo(canvas.width/2-50, canvas.height/2+50);
ctx.lineTo(canvas.width/2+50, canvas.height/2+50);
ctx.fill();
But the triangle looks a bit too tall.
How can I draw an equilateral triangle in the middle of canvas?
Someone told me you have to find the ratio of the height of an equilateral triangle to the side of an equilateral triangle.
h:s
What are the two numbers?
The equation for the three corner points is
x = r*cos(angle) + x_center
y = r*sin(angle) + y_center
where for angle = 0, (1./3)*(2*pi), and (2./3)*(2*pi); and where r is the radius of the circle in which the triangle is inscribed.
You have to do it with the height of the triangle
var h = side * (Math.sqrt(3)/2);
or
var h = side * Math.cos(Math.PI/6);
So the ratio h:s is equal to:
sqrt( 3 ) / 2 : 1 = cos( π / 6 ) : 1 ≈ 0.866025
See : http://jsfiddle.net/rWSKh/2/
A simple version where X and Y are the points you want to top of the triangle to be:
var height = 100 * (Math.sqrt(3)/2);
context.beginPath();
context.moveTo(X, Y);
context.lineTo(X+50, Y+height);
context.lineTo(X-50, Y+height);
context.lineTo(X, Y);
context.fill();
context.closePath();
This makes an equilateral triange with all sides = 100. Replace 100 with how long you want your side lengths to be.
After you find the midpoint of the canvas, if you want that to be your triangle's midpoint as well you can set X = midpoint's X and Y = midpoint's Y - 50 (for a 100 length triangle).
The side lengths will not be equal given those coordinates.
The horizontal line constructed on the bottom has a length of 100, but the other sides are actually the hypotenuse of a 50x100 triangle ( approx. 112).
I can get you started with drawing an equilateral triangle but I don't have the time to get it centered.
jsFiddle
var ax=0;
var ay=0;
var bx=0;
var by=150;
var dx=bx-ax
var dy=by-ay;
var dangle = Math.atan2(dy, dx) - Math.PI / 3;
var sideDist = Math.sqrt(dx * dx + dy * dy);
var cx = Math.cos(dangle) * sideDist + ax;
var cy = Math.sin(dangle) * sideDist + ay;
var canvas = document.getElementById('equ');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(ax,ay);
ctx.lineTo(bx,by);
ctx.lineTo(cx,cy);
ctx.fill();
my code for drawing triangle also depending on direction (for lines). code is for Raphael lib.
drawTriangle(x2 - x1, y2 - y1, x2, y2);
function drawTriangle(dx, dy, midX, midY) {
var diff = 0;
var cos = 0.866;
var sin = 0.500;
var length = Math.sqrt(dx * dx + dy * dy) * 0.8;
dx = 8 * (dx / length);
dy = 8 * (dy / length);
var pX1 = (midX + diff) - (dx * cos + dy * -sin);
var pY1 = midY - (dx * sin + dy * cos);
var pX2 = (midX + diff) - (dx * cos + dy * sin);
var pY2 = midY - (dx * -sin + dy * cos);
return [
"M", midX + diff, midY,
"L", pX1, pY1,
"L", pX2, pY2,
"L", midX + diff, midY
].join(",");
}