- Home /
How to make a circle with three known points
I want to make a throwable weapon that will arc towards its target.
Right now the best way I can think of is to make a circle with three points and have the object travel along the minor arc
A = player position
B = target position
C = a point that's perpendicular to the AB line and offset by the player
I can't figure out how to get the point of the center of the circle (point D)
If it changes the math / code, I need this to work in 3D so the player can aim their arc up or down too
edit: (If 3d makes everything much more complex I think I thought of a way to make 2d work for me)
Thanks for any help, I've been stuck for awhile on this
Not the prettiest picture but I hope it gets the point across
Answered: My result is in a comment
If anyone finds this later and wants my result based on @$$anonymous$$eishin 's answer
https://www.codepile.net/pile/Rpna$$anonymous$$Y7x?s=0
https://www.codepile.net/pile/E0N$$anonymous$$ak21?s=0
The second link was my result from more directly converting what was in @$$anonymous$$eishin 's link https://github.com/sergarrido/random/blob/master/circle3d/circle3d.cpp
(never used CodePile so I don't know if things last forever there)
Answer by Meishin · Aug 08, 2019 at 08:21 AM
Edit : Found here : https://github.com/sergarrido/random/tree/master/circle3d
Given your 3 points p1 (p1x, p1y, p1z), p2(p2x, p2y, p2z), p3 (p3x, p3y, p3z)
In summary, we have to solve the following 2x2 system:
(v1T·v1)k1 + (v1T·v2)k2 = 0.5·(v1T·v1)
(v1T·v2)k1 + (v2T·v2)k2 = 0.5·(v2T·v2)
where
v1 = p2-p1 = (v1x, v1y, v1z)T
v2 = p3-p1 = (v2x, v2y, v2z)T
The direct expressions for k1 and k2 can be derived obtaining:
k1 = 0.5·(v2T·v2)·[(v1T·v1) - (v1T·v2)]/[(v1T·v1)·(v2T·v2)-(v1T·v2)2]
k2 = 0.5·(v1T·v1)·[(v2T·v2) - (v1T·v2)]/[(v1T·v1)·(v2T·v2)-(v1T·v2)2]
After determining k1 and k2, the center of the circle is:
cx = p1x + k1v1x + k2v2x
cy = p1y + k1v1y + k2v2y
cz = p1z + k1v1z + k2v2z
Also in unity you could use Vector3.Dot product (untested);
Vector3 v1 = Vector3(p2-p1)
Vector3 v2 = Vector3(p3-p1)
float k1 = 0.5·Vector3.Dot(v2, v2)·[Vector3.Dot(v1, v1) - Vector3.Dot(v1, v2)]/[Vector3.Dot(v1, v1)·Vector3.Dot(v2, v2)-Vector3.Dot(v1, v2)^2]
etc..
Answer by rizzunity · Aug 08, 2019 at 08:07 AM
Hi,
Here is a bit of math. If you have 3 points, say A, B and C - then first make a line L1 that passes between A and B. Next, make another line that passes between B and C. You end up with equations:
Y_Line1 = slope_Line1(x-x1)+y1
Y_Line2 = slope_Line2(x-x2)+y2
Next, get the perpendicular lines which should pass through the mid-points of the lines AB and BC. Then the centre of the circle will just be the intersection of these 2 perpendicular lines.
Equations of the perpendicular: > Y'Line1 = [(-1/slope_line1)(x-((x1+x2)/2))+(y1+y2)/2] > Y'Line2 = [(-1/slope_line2)(x-((x2+x3)/2))+(y2+y3)/2]
These perpendiculars will intersect at the centre: > x = slope_line1*slope_line2(y1-y3)+slope_line2(x1+x2) - slope_line1(x2+x3) whole divided by [2*(slope_line2 - slope_line1)]
Once, you get the centre_x, then substitute this value in the perpendicular equations to get your centre_y
Hope this helps!
Answer by Namey5 · Aug 08, 2019 at 10:37 AM
I quickly put the following script together to demonstrate how you would go about doing this. It's commented, talking about how each part works. To see this in action, you'll need three objects; 2 cubes and a sphere. Attach this script to the sphere, and set the 2 cubes as the start and end points of your arc (keep in mind this particular one is a hybrid 2D/3D solution on the XZ axis, so you'll want to look at it top-down). Use the 'position' variable to move the sphere along the arc.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ArcTest : MonoBehaviour
{
public Transform startPoint; //Arc start object
public Transform endPoint; //Arc end object
public float arcHeight = 2f; //Max height of the arc
[Range(0f,1f)]
public float position = 0f; //How far along the arc the object should be
//This basically returns the 2D centre of the circle in the [x,y] of the Vector3 and the radius in the [z] of the Vector3
//Adapted from Erk Ekin's answer to https://math.stackexchange.com/questions/827072/finding-an-equation-of-circle-which-passes-through-three-points
Vector3? Circle3 (Vector2 p0, Vector2 p1, Vector2 p2)
{
if (p1.x == p0.x || p2.x == p1.x)
return null;
float mr = (p1.y - p0.y) / (p1.x - p0.x);
float mt = (p2.y - p1.y) / (p2.x - p1.x);
if (mr == mt)
return null;
float x = (mr * mt * (p2.y - p0.y) + mr * (p1.x + p2.x) - mt * (p0.x + p1.x)) / (2f * (mr - mt));
float y = (p0.y + p1.y) / 2f - (x - (p0.x + p1.x) / 2f) / mr;
float radius = Mathf.Sqrt (Mathf.Pow (p1.x - x, 2f) + Mathf.Pow (p1.y - y, 2f));
Vector2 centre = new Vector2 (x, y);
return new Vector3 (centre.x, centre.y, radius);
}
public void Update ()
{
//For the arc beginning and end points, I used the [x,z] axis in 3D and looked down (for testing)
Vector2 a = new Vector2 (startPoint.position.x, startPoint.position.z);
Vector2 b = new Vector2 (endPoint.position.x, endPoint.position.z);
//This finds the relative 'up' direction from the two given start and end points
Vector3 dir3 = Vector3.Cross ((endPoint.position - startPoint.position).normalized, Vector3.down).normalized;
Vector2 dir = new Vector2 (dir3.x, dir3.z);
//This is the actual height of the arc. We want the minor arc, so clamp it such that it can't be more than the radius of the circle
float height = Mathf.Min (arcHeight, Vector3.Distance (startPoint.position, endPoint.position) * 0.5f);
//This is the middle point (you can replace it with your own, I just calculate it automatically based on the two input points)
Vector2 c = (a + b) * 0.5f + dir * height;
//Find the actual centre and radius of the circle
//This is a nullable type because there's some funky maths, so we need to make sure we actually get useable values
Vector3? circle = Circle3 (a, c, b);
if (circle == null)
return;
//Extract the values from the nullable type
Vector2 centre = circle.Value;
float radius = circle.Value.z;
//Find the relative angles to the 'origin' and blend between them so that;
// position(0) = the start of the arc
// position(1) = the end of the arc
//Also make sure we're in radians
float t = Mathf.Lerp (Vector2.SignedAngle (Vector2.right, a - centre), Vector2.SignedAngle (Vector2.right, b - centre), position) * Mathf.Deg2Rad;
//Find the current point on the arc through sin/cos circle function using calculated radius and centre
Vector2 pos = centre + new Vector2 (Mathf.Cos (t), Mathf.Sin (t)) * radius;
//Move this object to the target point on the arc
transform.position = new Vector3 (pos.x, 0, pos.y);
}
}
I'll be honest, I had this page open pretty much since the question was asked. Once I finally got around to posting the answer, it refreshed and revealed the other answers.
Answer by Bunny83 · Aug 08, 2019 at 02:07 PM
For some reason I can not find the question at the moment but there was exact the same question already asked here. I've written this method and actually created this gif image:
Gif: https://www.dropbox.com/s/lst11oscgfs672h/CalculateCircleCenter.gif [preview of external content removed for GDPR compliance as it was including 3rd party cookies]