Repository navigation
Objects appear in wrong position when normal vector ≠ (0,0,1) #846
|
I’m working on a 2D drawing application. While debugging, I noticed that the objects that end up in the wrong location have a normal vector different from (0,0,1). How can I correctly fix or transform the position, rotation, and/or scale (especially for block references) of these objects in my own application? I’ve attached a sample file for reference. |
Answered by
bayramakgul
Oct 29, 2025
Replies: 1 comment 2 replies
|
Solved: /// <summary>
/// Transforms a point from OCS (Object Coordinate System) to WCS (World Coordinate System)
/// </summary>
public static XYZ TransformOcsToWcs(XYZ ocsPoint, XYZ normal)
{
// If the normal vector is already (0,0,1), no transformation is required
if (IsNormalStandard(normal))
{
return ocsPoint;
}
// Normalize the normal vector
var normalizedNormal = normal.Normalize();
// Arbitrary Axis Algorithm (the method used by AutoCAD)
XYZ arbitraryX;
XYZ arbitraryY;
const double threshold = 1.0 / 64.0;
if (Math.Abs(normalizedNormal.X) < threshold && Math.Abs(normalizedNormal.Y) < threshold)
{
// The normal vector is close to the Z-axis
arbitraryX = normalizedNormal.Z < 0
? new XYZ(-1, 0, 0)
: new XYZ(1, 0, 0);
}
else
{
// General case: cross product with the WCS Y-axis
arbitraryX = new XYZ(-normalizedNormal.Y, normalizedNormal.X, 0);
arbitraryX = arbitraryX.Normalize();
}
// Y-axis = Normal × X-axis (cross product)
arbitraryY = CrossProduct(normalizedNormal, arbitraryX);
// Transform OCS coordinates to WCS
double wcsX = ocsPoint.X * arbitraryX.X + ocsPoint.Y * arbitraryY.X + ocsPoint.Z * normalizedNormal.X;
double wcsY = ocsPoint.X * arbitraryX.Y + ocsPoint.Y * arbitraryY.Y + ocsPoint.Z * normalizedNormal.Y;
double wcsZ = ocsPoint.X * arbitraryX.Z + ocsPoint.Y * arbitraryY.Z + ocsPoint.Z * normalizedNormal.Z;
return new XYZ(wcsX, wcsY, wcsZ);
}
/// <summary>
/// Checks whether the normal vector is the standard (0,0,1)
/// </summary>
public static bool IsNormalStandard(XYZ normal)
{
const double epsilon = 1e-10;
return Math.Abs(normal.X) < epsilon &&
Math.Abs(normal.Y) < epsilon &&
Math.Abs(normal.Z - 1.0) < epsilon;
}
/// <summary>
/// Calculates the cross product of two vectors
/// </summary>
private static XYZ CrossProduct(XYZ a, XYZ b)
{
return new XYZ(
a.Y * b.Z - a.Z * b.Y,
a.Z * b.X - a.X * b.Z,
a.X * b.Y - a.Y * b.X
);
}
/// <summary>
/// Applies the transformation matrix for a block reference (Insert)
/// </summary>
public static (XYZ Position, double Rotation, double ScaleX, double ScaleY)
TransformInsert(Insert insert)
{
var normal = insert.Normal;
if (IsNormalStandard(normal))
{
return (new XYZ(insert.InsertPoint.X, insert.InsertPoint.Y, 0),
insert.Rotation,
insert.XScale,
insert.YScale);
}
// Transform the position to WCS
var wcsPosition = TransformOcsToWcs(insert.InsertPoint, normal);
// Adjust the rotation
double rotation = insert.Rotation;
// Compute the rotation offset based on the normal vector relative to the Z-axis
double angleOffset = 0;
if (!IsNormalStandard(normal))
{
// Projection angle of the normal vector on the XY plane
angleOffset = Math.Atan2(normal.Y, normal.X);
// If the normal’s Z component is negative, invert the rotation
if (normal.Z < 0)
{
rotation = -rotation;
}
}
rotation += angleOffset;
// Adjust scaling according to the normal vector direction
double scaleX = insert.XScale;
double scaleY = insert.YScale;
// If normal.Z is negative, scale sign might need to be flipped
if (normal.Z < 0)
{
scaleX = -scaleX;
}
return (wcsPosition, rotation, scaleX, scaleY);
}` |
2 replies
Answer selected by
bayramakgul
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Solved:
`