How to obtain an arbitrary point on a circle using HPS

Using Visualize 3DF, a circle could be created using a center point, normal vector and radius. Subsequently, the 3DF API supported obtaining three points on the circle (even when the three point method of defining a circle was not used).

In HPS, InsertCircle() returns a CircleKey. The CircleKey has a ShowRadius() method. Alternatively, you can use the CircleKey to Show() or copy the contents (definition) of the CircleKey into a CircleKit which has a ShowRadius() method. In this case, the radius is integral to the definition of the circle. This is analogous to the 3DF functions Insert_Circle_By_Radius and Show_Circle_By_Radius.

Similarly, InsertCircularArc() returns a CircularArcKey. The CircularArcKey has methods to Show the three points used to define the arc. Alternatively you can use the CircleArcKey to Show() or copy the contents (definition) of the CircularArcKey into a CircularArcKit which has similar Show methods. In this case, the radius is not part of the arc’s defining parameters. This is analogous to the 3DF functions Insert_Circular_Arc and Show_Circular_Arc.

Unlike 3DF, there is no HPS API crossover where three points can be obtained for a circle defined by a center and radius. Given the center, normal and radius, you could compute one or more points on the circle.

The following code can be used in the MFC Sandbox;

class RandomCircle {
public:
	RandomCircle(HPS::Point &c, HPS::Vector& n, float r)
	{
		srand(time(NULL));
		center = c;
		normal = n;
		radius = r;
	}

	HPS::Point PointAt(float angle)
	{
		float xv = (float)cos(angle);
		float yv = (float)sin(angle);

		HPS::Vector v = findV();
		HPS::Vector w = v.Cross(normal);

		// Return center + r * (V * cos(a) + W * sin(a))
		HPS::Vector r1 = v * (radius * xv);
		HPS::Vector r2 = w * (radius * yv);

		return HPS::Point(center.x + r1.x + r2.x,
			center.y + r1.y + r2.y,
			center.z + r1.z + r2.z);
	}
	void Randomize()
	{
		// randomize the circle parameters
		center.x = GetRandomFloat();
		center.y = GetRandomFloat();
		center.z = GetRandomFloat();

		normal.x = GetRandomFloat();
		normal.y = GetRandomFloat();
		normal.z = GetRandomFloat();
		normal.Normalize();

		radius = GetRandomFloat() / radiusFraction;
	}

	HPS::Point center;
	float radius;
	HPS::Vector normal;

private:
	RandomCircle() {}

	HPS::Vector findV()
	{
		HPS::Vector vp = {0, 0, 0};
		if (normal.x != 0 || normal.y != 0) {
			vp = {0, 0, 1};
		}
		else if (normal.x != 0 || normal.z != 0) {
			vp = {0, 1, 0};
		}
		else if (normal.y != 0 || normal.z != 0) {
			vp = {1, 0, 0};
		}
		else {
			return vp; // This is not good...
		}
		HPS::Vector cp = normal.Cross(vp);
		return cp.Normalize();
	}

	float GetRandomFloat()
	{
		float x = magnitude + 1;
		while (x > magnitude)
			x = 1 + rand() / ((RAND_MAX + 1u) / magnitude);

		return x - (magnitude / 2);
	}

	const float magnitude = 250;
	const float radiusFraction = 10;
};

void CHPSView::OnUserCode2()
{
	HPS::View aView = GetCanvas().GetFrontView();
	HPS::SegmentKey modelKey = aView.GetAttachedModel().GetSegmentKey();
	HPS::SegmentKey parentKey = modelKey.Down("circles", true);
	parentKey.GetVisibilityControl().SetGeometry(true);

	// Start with a unit circle in the XY plane
	RandomCircle rc(HPS::Point(0, 0, 0), HPS::Vector(0, 0, 1), 1.0f);

	HPS::SegmentKey unitCircleKey = parentKey.Down("unit circle", true);
	unitCircleKey.InsertCircle(rc.center, rc.radius, rc.normal);
	unitCircleKey.InsertMarker(rc.PointAt(0));
	unitCircleKey.InsertLine(rc.center, (rc.center + rc.normal));
	unitCircleKey.GetMaterialMappingControl().
		SetLineColor(RGBAColor(0, 1, 0)).
		SetMarkerColor(RGBAColor(0, 0, 1)).
		SetFaceColor(RGBAColor(1, 0, 0));

	// Add additional arbitrary circles
	int count = 100;
	for (int i = 0; i < count; i++)
	{
		rc.Randomize();
		parentKey.InsertCircle(rc.center, rc.radius, rc.normal);
		parentKey.InsertMarker(rc.PointAt(0));
		parentKey.InsertLine(rc.center, (rc.center + rc.normal));
	}
	aView.FitWorld();
	aView.Update();
}

It generates a scene with a unit circle at the origin and 100 other random circles with a point on the circle and the normal. The point is calculated for a given angle around the circle (alpha = 0 in this case).