using System;
using UnityEngine;
namespace ProceduralToolkit
{
///
/// Collection of generic vector and raster drawing algorithms
///
public static partial class Draw
{
public const int circleSegments = 64;
public const float circleSegmentAngle = 360f/circleSegments;
public static readonly Func pointOnCircleXY;
public static readonly Func pointOnCircleXZ;
public static readonly Func pointOnCircleYZ;
static Draw()
{
pointOnCircleXY = Geometry.PointOnCircle3XY;
pointOnCircleXZ = Geometry.PointOnCircle3XZ;
pointOnCircleYZ = Geometry.PointOnCircle3YZ;
}
public static void GetSegmentsAndSegmentAngle(float fromAngle, float toAngle, out int segments, out float segmentAngle)
{
float range = toAngle - fromAngle;
if (range > circleSegmentAngle)
{
segments = Mathf.FloorToInt(range/circleSegmentAngle);
segmentAngle = range/segments;
}
else
{
segments = 1;
segmentAngle = range;
}
}
///
/// Draws a line between specified from and to points
///
public static void Line(Vector3 from, Vector3 to, Action drawLine)
{
drawLine(from, to);
}
///
/// Draws a ray starting at ray.origin to ray.origin + ray.direction
///
public static void Ray(Ray ray, Action drawLine)
{
Line(ray.origin, ray.origin + ray.direction, drawLine);
}
///
/// Draws a segment
///
public static void Segment2(Segment2 segment, Action drawLine)
{
Line((Vector3) segment.a, (Vector3) segment.b, drawLine);
}
///
/// Draws a segment
///
public static void Segment3(Segment3 segment, Action drawLine)
{
Line(segment.a, segment.b, drawLine);
}
#region WireQuad
///
/// Draws a wireframe quad with position, rotation and scale
///
public static void WireQuadXY(Vector3 position, Quaternion rotation, Vector2 scale, Action drawLine)
{
WireQuad(position, rotation, scale, Vector3.right, Vector3.up, drawLine);
}
///
/// Draws a wireframe quad with position, rotation and scale
///
public static void WireQuadXZ(Vector3 position, Quaternion rotation, Vector2 scale, Action drawLine)
{
WireQuad(position, rotation, scale, Vector3.right, Vector3.forward, drawLine);
}
///
/// Draws a wireframe quad with position, rotation and scale
///
public static void WireQuadYZ(Vector3 position, Quaternion rotation, Vector2 scale, Action drawLine)
{
WireQuad(position, rotation, scale, Vector3.up, Vector3.forward, drawLine);
}
///
/// Draws a wireframe quad with position, rotation and scale
///
public static void WireQuad(Vector3 position, Quaternion rotation, Vector2 scale, Vector3 planeRight, Vector3 planeForward,
Action drawLine)
{
Vector3 right = rotation*planeRight*scale.x;
Vector3 forward = rotation*planeForward*scale.y;
Vector3 forwardRight = position + right*0.5f + forward*0.5f;
Vector3 backRight = forwardRight - forward;
Vector3 backLeft = backRight - right;
Vector3 forwardLeft = forwardRight - right;
Line(forwardRight, backRight, drawLine);
Line(backRight, backLeft, drawLine);
Line(backLeft, forwardLeft, drawLine);
Line(forwardLeft, forwardRight, drawLine);
}
#endregion WireQuad
///
/// Draws a wireframe cube with position, rotation and scale
///
public static void WireCube(Vector3 position, Quaternion rotation, Vector3 scale, Action drawLine)
{
Vector3 right = rotation*Vector3.right*scale.x;
Vector3 up = rotation*Vector3.up*scale.y;
Vector3 forward = rotation*Vector3.forward*scale.z;
Vector3 a1 = position + right*0.5f + up*0.5f + forward*0.5f;
Vector3 b1 = a1 - up;
Vector3 c1 = b1 - right;
Vector3 d1 = a1 - right;
Vector3 a2 = a1 - forward;
Vector3 b2 = b1 - forward;
Vector3 c2 = c1 - forward;
Vector3 d2 = d1 - forward;
Line(a1, b1, drawLine);
Line(b1, c1, drawLine);
Line(c1, d1, drawLine);
Line(d1, a1, drawLine);
Line(a2, b2, drawLine);
Line(b2, c2, drawLine);
Line(c2, d2, drawLine);
Line(d2, a2, drawLine);
Line(a1, a2, drawLine);
Line(b1, b2, drawLine);
Line(c1, c2, drawLine);
Line(d1, d2, drawLine);
}
#region WireCircle
///
/// Draws a wireframe circle with position and radius
///
public static void WireCircleXY(Vector3 position, float radius, Action drawLine)
{
WireCircle(pointOnCircleXY, position, radius, drawLine);
}
///
/// Draws a wireframe circle with position, rotation and radius
///
public static void WireCircleXY(Vector3 position, Quaternion rotation, float radius, Action drawLine)
{
WireCircle(pointOnCircleXY, position, rotation, radius, drawLine);
}
///
/// Draws a wireframe circle with position and radius
///
public static void WireCircleXZ(Vector3 position, float radius, Action drawLine)
{
WireCircle(pointOnCircleXZ, position, radius, drawLine);
}
///
/// Draws a wireframe circle with position, rotation and radius
///
public static void WireCircleXZ(Vector3 position, Quaternion rotation, float radius, Action drawLine)
{
WireCircle(pointOnCircleXZ, position, rotation, radius, drawLine);
}
///
/// Draws a wireframe circle with position and radius
///
public static void WireCircleYZ(Vector3 position, float radius, Action drawLine)
{
WireCircle(pointOnCircleYZ, position, radius, drawLine);
}
///
/// Draws a wireframe circle with position, rotation and radius
///
public static void WireCircleYZ(Vector3 position, Quaternion rotation, float radius, Action drawLine)
{
WireCircle(pointOnCircleYZ, position, rotation, radius, drawLine);
}
#endregion WireCircle
#region WireCircle Universal
///
/// Draws a wireframe circle with position and radius
///
public static void WireCircle(Func pointOnCircle, Vector3 position, float radius, Action drawLine)
{
WireArc(pointOnCircle, position, radius, 0, circleSegments, circleSegmentAngle, drawLine);
}
///
/// Draws a wireframe circle with position, rotation and radius
///
public static void WireCircle(Func pointOnCircle, Vector3 position, Quaternion rotation, float radius,
Action drawLine)
{
WireArc(pointOnCircle, position, rotation, radius, 0, circleSegments, circleSegmentAngle, drawLine);
}
#endregion WireCircle Universal
#region WireArc
///
/// Draws a wireframe circular arc with position and radius
///
public static void WireArcXY(Vector3 position, float radius, float fromAngle, float toAngle, Action drawLine)
{
WireArc(pointOnCircleXY, position, radius, fromAngle, toAngle, drawLine);
}
///
/// Draws a wireframe circular arc with position, rotation and radius
///
public static void WireArcXY(Vector3 position, Quaternion rotation, float radius, float fromAngle, float toAngle,
Action drawLine)
{
WireArc(pointOnCircleXY, position, rotation, radius, fromAngle, toAngle, drawLine);
}
///
/// Draws a wireframe circular arc with position and radius
///
public static void WireArcXZ(Vector3 position, float radius, float fromAngle, float toAngle, Action drawLine)
{
WireArc(pointOnCircleXZ, position, radius, fromAngle, toAngle, drawLine);
}
///
/// Draws a wireframe circular arc with position, rotation and radius
///
public static void WireArcXZ(Vector3 position, Quaternion rotation, float radius, float fromAngle, float toAngle,
Action drawLine)
{
WireArc(pointOnCircleXZ, position, rotation, radius, fromAngle, toAngle, drawLine);
}
///
/// Draws a wireframe circular arc with position and radius
///
public static void WireArcYZ(Vector3 position, float radius, float fromAngle, float toAngle, Action drawLine)
{
WireArc(pointOnCircleYZ, position, radius, fromAngle, toAngle, drawLine);
}
///
/// Draws a wireframe circular arc with position, rotation and radius
///
public static void WireArcYZ(Vector3 position, Quaternion rotation, float radius, float fromAngle, float toAngle,
Action drawLine)
{
WireArc(pointOnCircleYZ, position, rotation, radius, fromAngle, toAngle, drawLine);
}
#endregion WireArc
#region WireArc Universal
///
/// Draws a wireframe circular arc with position and radius
///
public static void WireArc(Func pointOnCircle, Vector3 position, float radius, float fromAngle, float toAngle,
Action drawLine)
{
GetSegmentsAndSegmentAngle(fromAngle, toAngle, out int segments, out float segmentAngle);
WireArc(pointOnCircle, position, radius, fromAngle, segments, segmentAngle, drawLine);
}
///
/// Draws a wireframe circular arc with position, rotation and radius
///
public static void WireArc(Func pointOnCircle, Vector3 position, Quaternion rotation, float radius, float fromAngle,
float toAngle, Action drawLine)
{
GetSegmentsAndSegmentAngle(fromAngle, toAngle, out int segments, out float segmentAngle);
WireArc(pointOnCircle, position, rotation, radius, fromAngle, segments, segmentAngle, drawLine);
}
///
/// Draws a wireframe circular arc with position and radius
///
public static void WireArc(Func pointOnCircle, Vector3 position, float radius, float fromAngle, int segments,
float segmentAngle, Action drawLine)
{
float currentAngle = fromAngle;
for (var i = 0; i < segments; i++)
{
Vector3 a = position + pointOnCircle(radius, currentAngle);
currentAngle += segmentAngle;
Vector3 b = position + pointOnCircle(radius, currentAngle);
Line(a, b, drawLine);
}
}
///
/// Draws a wireframe circular arc with position, rotation and radius
///
public static void WireArc(Func pointOnCircle, Vector3 position, Quaternion rotation, float radius, float fromAngle,
int segments, float segmentAngle, Action drawLine)
{
float currentAngle = fromAngle;
for (var i = 0; i < segments; i++)
{
Vector3 a = position + rotation*pointOnCircle(radius, currentAngle);
currentAngle += segmentAngle;
Vector3 b = position + rotation*pointOnCircle(radius, currentAngle);
Line(a, b, drawLine);
}
}
#endregion WireArc Universal
///
/// Draws a wireframe sphere with position, rotation and radius
///
public static void WireSphere(Vector3 position, Quaternion rotation, float radius, Action drawLine)
{
WireCircleXY(position, rotation, radius, drawLine);
WireCircleXZ(position, rotation, radius, drawLine);
WireCircleYZ(position, rotation, radius, drawLine);
}
///
/// Draws a wireframe hemisphere with position, rotation and radius
///
public static void WireHemisphere(Vector3 position, Quaternion rotation, float radius, Action drawLine)
{
WireArcXY(position, rotation, radius, -90, 90, drawLine);
WireCircleXZ(position, rotation, radius, drawLine);
WireArcYZ(position, rotation, radius, 0, 180, drawLine);
}
///
/// Draws a wireframe cone with position and rotation
///
public static void WireCone(Vector3 position, Quaternion rotation, float apexRadius, float angle, float length,
Action drawLine)
{
Vector3 baseCenter = position + rotation*Vector3.up*length;
float baseRadius = Mathf.Tan(angle*Mathf.Deg2Rad)*length + apexRadius;
WireCircleXZ(baseCenter, rotation, baseRadius, drawLine);
Vector3 a2 = baseCenter + rotation*Geometry.PointOnCircle3XZ(baseRadius, 0);
Vector3 b2 = baseCenter + rotation*Geometry.PointOnCircle3XZ(baseRadius, 90);
Vector3 c2 = baseCenter + rotation*Geometry.PointOnCircle3XZ(baseRadius, 180);
Vector3 d2 = baseCenter + rotation*Geometry.PointOnCircle3XZ(baseRadius, 270);
if (apexRadius == 0)
{
Line(position, a2, drawLine);
Line(position, b2, drawLine);
Line(position, c2, drawLine);
Line(position, d2, drawLine);
}
else
{
WireCircleXZ(position, rotation, apexRadius, drawLine);
Vector3 a1 = position + rotation*Geometry.PointOnCircle3XZ(apexRadius, 0);
Vector3 b1 = position + rotation*Geometry.PointOnCircle3XZ(apexRadius, 90);
Vector3 c1 = position + rotation*Geometry.PointOnCircle3XZ(apexRadius, 180);
Vector3 d1 = position + rotation*Geometry.PointOnCircle3XZ(apexRadius, 270);
Line(a1, a2, drawLine);
Line(b1, b2, drawLine);
Line(c1, c2, drawLine);
Line(d1, d2, drawLine);
}
}
}
}