Saturday, June 20, 2009

3D ellipse drawing

Worked at improving the 3D ellipse drawing. Because the code to make that needed a lot of operations I will present below the solution found:

In order to build an Geom_Ellipse it is needed to pass as parameters three elements: a gp_Ax2 that describes a right handed coordinate system, the minor radius and the major radius. Further details are that the minor radius must be smaller than major radius, the "X direction" of gp_Ax2 defines the major axis of the ellipse, the "Y direction" defines the minor axis.

In order to implement all these receiving from the user 3 points as mouse clicks I made the following:

- start calculating the major radius from the first two points:

double majorRadius = firstPoint.Distance(secondPoint)/2;

- the radius direction is built from a vector built from the first two points:

var vecX = new OCgp_Vec(firstPoint, secondPoint);
OCgp_Dir dirX = new OCgp_Dir(vecX);


- the center of the ellipse is the mid point calculated from the first two points,
- the minor radius is calculated as the distance from the third point to the line built from the first two points:

OCgp_Lin line = new OCgp_Lin(firstPoint, dirX);
double minorRadius = line.Distance(thirdPoint);


- the problem is to calculate the direction of the minor radius. It can be built making a vector from the ellipse center to the third point, this can be powerful but difficult for the user to understand it. It would be simpler to translate the third point so that the vector from the center to it would be perpendicular on the line made from the first two points.
Calculating the perpendicular can be done easily using vector geometry knowing that the result of a vector product is a vector perpendicular on the first two vectors:

var vecX = new OCgp_Vec(firstPoint, secondPoint);
// Calculate also the axis/direction of the major radus
var vecY = new OCgp_Vec(center, thirdPoint);
// We want the direction to be perpendicular on the direction of the major radius
var vecZ = vecX.Crossed(vecY);
// The minor radius direction
vecY = vecX.Crossed(vecZ);
OCgp_Dir dirY = new OCgp_Dir(vecY);

- check if the minor radius is bigger than the major radius, in this case swap the radius values and also their directions,
- build a plan from the first 3 points, get the plane normal axis, build a gp_Ax2 right handed coordinate system from it, put its location on the center of the ellipse and set the directions of the minor and major radius:

// Build a plane from the 3 points
OCgp_Pln plane = GeomUtils.BuildPlane(firstPoint, secondPoint, thirdPoint);
OCgp_Ax1 ax1 = plane.Axis();
OCgp_Ax2 ax2 = new OCgp_Ax2();
ax2.SetAxis(ax1);
// Location is the ellipse center
ax2.SetLocation(center);
// Set the radius directions, they were swapped if the minor radius was bigger than the major radius
ax2.SetXDirection(dirX);
ax2.SetYDirection(dirY);


- finally use the gp_Ax2 value, the minor radius value and the major radius value to build the ellipse:

OCGeom_Ellipse ellipse = new OCGeom_Ellipse(ax2, majorRadius, minorRadius);

No comments: