Editor/RoadGizmos.cs

Editor utility that draws gizmos for road editing. It renders curve segments, road edge outlines (with uniform or per-side widths), and a node marker with optional filled center, using the engine Gizmo API and a provided Transform.

File Access
using Sandbox;

namespace RedSnail.RoadTool2.Editor;

/// <summary>
/// Gizmo drawing shared by the road tools. Curves are in network-local space and drawn through the network's
/// transform, in whatever colour and thickness the caller set up.
/// </summary>
internal static class RoadGizmos
{
	public static void DrawCurve(in RoadCurve _Curve, in Transform _Transform, int _Steps = 24)
	{
		Vector3 previous = _Transform.PointToWorld(_Curve.P0);

		for (int i = 1; i <= _Steps; i++)
		{
			Vector3 point = _Transform.PointToWorld(_Curve.Evaluate((float)i / _Steps));

			Gizmo.Draw.Line(previous, point);
			previous = point;
		}
	}



	/// <summary>
	/// Draws the two edges of a road of the given width along the curve, capped at both ends.
	/// </summary>
	public static void DrawRoadOutline(in RoadCurve _Curve, float _Width, in Transform _Transform, int _Steps = 24)
	{
		DrawRoadOutline(_Curve, RoadWidth.Uniform(_Width), _Transform, _Steps);
	}



	/// <summary>
	/// Draws the two edges of a road along the curve, each its own distance out (the curve's parameter standing in
	/// for its distance), capped at both ends.
	/// </summary>
	public static void DrawRoadOutline(in RoadCurve _Curve, in RoadWidth _Width, in Transform _Transform, int _Steps = 24)
	{
		Vector3 previousLeft = default;
		Vector3 previousRight = default;

		for (int i = 0; i <= _Steps; i++)
		{
			float t = (float)i / _Steps;
			float distance = t * _Width.Length;
			Vector3 point = _Curve.Evaluate(t);
			Vector3 right = RoadCurve.RightOf(_Curve.Tangent(t));

			Vector3 left = _Transform.PointToWorld(point - right * _Width.LeftAt(distance));
			Vector3 rightEdge = _Transform.PointToWorld(point + right * _Width.RightAt(distance));

			if (i == 0 || i == _Steps)
				Gizmo.Draw.Line(left, rightEdge);

			if (i > 0)
			{
				Gizmo.Draw.Line(previousLeft, left);
				Gizmo.Draw.Line(previousRight, rightEdge);
			}

			previousLeft = left;
			previousRight = rightEdge;
		}
	}



	/// <summary>
	/// A node marker: a flat ring on the ground, filled when it is the one being worked on.
	/// </summary>
	public static void DrawNode(Vector3 _WorldPosition, bool _Filled)
	{
		float radius = RoadPicker.NodeRadius(_WorldPosition);

		if (_Filled)
			Gizmo.Draw.SolidSphere(_WorldPosition, radius * 0.6f);

		Gizmo.Draw.LineCircle(_WorldPosition, Vector3.Up, radius);
	}
}