I am trying to draw lots of different great circles every couple of frames (they don’t need to be animated, just need to be 3D and appear on the screen), so I am hoping I am using optimized code to do this. I am pretty new to Unity3D, but I was able to hack together a class that uses Vectrosity lines - 50 line segments to be precise - to connect a couple objects with a great circle. I don’t think this is the best approach because the lines don’t look that smooth, but it is the best I have been able to come up with. I have posted my code below and I am hoping someone will be able to help me find a faster and better looking approach to this problem. Thanks.
using UnityEngine;
using System.Collections;
public class GreatCircleArc {
// Create an arc with numberSegments great circle vertices between a start and end point
public string shapeName { get; set; }
public Color lineColor { get; set; }
public Vector3[] linePoints;
public VectorLine line;
int numberSegments = 50;
float radius = -.01f;
float fixed_y = .001f;
int lineWidth = 2;
Vector2 point_1;
Vector2 point_2;
public void AddSphereLine ( Vector2 argPoint_1, Vector2 argPoint_2 ) {
// Get the coordinates of a great circle between two points given a center point and a specified radius.
// http://www.mathworks.com/matlabcentral/newsreader/view_thread/277881
this.point_1 = argPoint_1;
this.point_2 = argPoint_2;
Vector3[] linePoints = new Vector3[numberSegments];
line = new VectorLine( shapeName, linePoints, lineColor, null, lineWidth, LineType.Continuous );
Vector2 xz_0 = GetGreatCircle ();
float y = fixed_y - radius;
// (x, y, z) Vector from center to 1st point
Vector3 v1 = new Vector3 ( point_1.x - xz_0.x, y, point_1.y - xz_0.y );
// (x, y, z) Vector from center to 2nd point
Vector3 v2 = new Vector3 ( point_2.x - xz_0.x, y, point_2.y - xz_0.y );
// (x, y, z) Vector that lies in plane of v1 and v2 and is orthogonal to v1 and is length radius
Vector3 v3 = Cross ( Cross ( v1, v2 ), v1 );
v3 = Norm (v1) * v3 / Norm (v3);
// Let theta range through the inner angle between v1 and v2
float[] theta = linspace ( 0f, Mathf.Atan2 (Norm ( Cross ( v1, v2 ) ), Dot( v1, v2 )), numberSegments );
// New matrix, v, traces great circle path, relative to center
for ( int i = 0; i < theta.Length; ++i ) {
Vector3 x = v1 * Mathf.Cos( theta[i] ) + v3 * Mathf.Sin( theta[i] );
linePoints[i] = new Vector3( x.x + xz_0.x, x.y + y, x.z + xz_0.y );
}
}
private Vector2 GetGreatCircle() {
// Convert initial coordinates from degrees to radians
float lat_1_radians = Radians (point_1.x);
float lon_1_radians = Radians (point_1.y);
float lat_2_radians = Radians (point_2.x);
float lon_2_radians = Radians (point_2.y);
// Distance between the two points in radians
float lat_diff = lat_1_radians - lat_2_radians;
float lon_diff = lon_1_radians - lon_2_radians;
float dist_radians = 2f * Mathf.Asin (Mathf.Sqrt (
(Mathf.Sin (lat_diff / 2f) * Mathf.Sin (lat_diff / 2f)) +
Mathf.Cos (lat_1_radians) * Mathf.Cos (lat_2_radians)
* (Mathf.Sin (lon_diff / 2f) * Mathf.Sin (lon_diff / 2f))));
// Calculate the 2D (x, z) mid-point on the great circle line for creation of the sphere
float f = 1f / (numberSegments - 1) * numberSegments / 2f;
float A = Mathf.Sin ((1 - f) * dist_radians) / Mathf.Sin (dist_radians);
float B = Mathf.Sin (f * dist_radians) / Mathf.Sin (dist_radians);
float x = A * Mathf.Cos (lat_1_radians) * Mathf.Cos (lon_1_radians) + B * Mathf.Cos (lat_2_radians) * Mathf.Cos (lon_2_radians);
float y = A * Mathf.Cos (lat_1_radians) * Mathf.Sin (lon_1_radians) + B * Mathf.Cos (lat_2_radians) * Mathf.Sin (lon_2_radians);
float z = A * Mathf.Sin (lat_1_radians) + B * Mathf.Sin (lat_2_radians);
// Return x and z center points
return new Vector2( Degrees (Mathf.Atan2 (z, Mathf.Sqrt ((x * x) + (y * y)))), Degrees (Mathf.Atan2 (y, x)) );
}
private static float Radians(float angle) {
// Convert angle into radians
return Mathf.PI * angle / 180f;
}
private static float Degrees(float angle) {
// Convert angle into degrees
return angle * (180f / Mathf.PI);
}
private static Vector3 Cross( Vector3 a, Vector3 b ) {
// Cross product of two vectors
return new Vector3 ( a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x );
}
private static float Norm( Vector3 a ) {
// Frobenius norm of a vector
return Mathf.Sqrt(
Mathf.Abs(a.x) * Mathf.Abs(a.x) +
Mathf.Abs(a.y) * Mathf.Abs(a.y) +
Mathf.Abs(a.z) * Mathf.Abs(a.z)
);
}
private static float Dot(Vector3 a, Vector3 b) {
// Dot product of two vectors
return a.x * b.x + a.y * b.y + a.z * b.z;
}
private static float[] linspace(float start, float end, int n) {
// Equally spaced linear values between two points
float[] xs = new float[n];
xs[0] = start;
xs[n - 1] = end;
float delta = (end - start) / (n - 1);
for ( int i = 1; i < n - 1; ++i ) {
xs[i] = xs[i - 1] + delta;
}
return xs;
}
}