XYZ question

XYZ question

MGO-Norsyn
Advocate Advocate
4,021 Views
11 Replies
Message 1 of 12

XYZ question

MGO-Norsyn
Advocate
Advocate

Hi all

 

I find the XYZ class very confusing because it can be a point or a vector.

 

Does any body knows any good guide on how to use them? Or some documentation.

 

Also, I have a specific question, how does one extract start and end points of a XYZ vector?

 

Thanks

0 Likes
Accepted solutions (1)
4,022 Views
11 Replies
Replies (11)
Message 2 of 12

augusto.goncalves
Alumni
Alumni
You're right, the XYZ class can represent a point or a vector, which are in fact quite similar.

If you have a XYZ object and run a angle method, you're in fact handling a vector information... but if you just get a coordinate, then a point.

Finally a vector don't have start or end point as they represent a direction, not a line. If you need a line, use the Curve/Line object.
Regards,



Augusto Goncalves
Twitter @augustomaia
Autodesk Developer Network
Message 3 of 12

BobbyC.Jones
Advocate
Advocate
I suggest rolling your own Point and Vector wrappers around it. It will make your code much easier to maintain.
--
Bobby C. Jones
Message 4 of 12

MGO-Norsyn
Advocate
Advocate
Thats very interesting. Could you provide a little example?
0 Likes
Message 5 of 12

BobbyC.Jones
Advocate
Advocate
Accepted solution

The XYZ class defines methods that are specific to the concept of points and vectors.  The biggest problem I had was in reviewing our code; it was difficult to know which concept it was dealing with at any given time.

 

Another benefit of providing your own point and vector wrappers is that you can limit their interface to only methods that make sense.  All of this code compiles, but none of it makes any sense.

 

 

public static void PointAndVectorExample(Line revitLine)
{
    var lineOrigin = revitLine.Origin;
    var whatIstheLengthOfaPoint = lineOrigin.GetLength();
    var howIsaPointaUnitLength = lineOrigin.IsUnitLength();

    var lineDirection = revitLine.Direction;
    var whatDoesThisRepresent = lineDirection.CrossProduct(lineOrigin);
    var thisDoesntMakeSense = lineDirection.DistanceTo(lineOrigin);
}

 

Here are some PARTIAL Point3D and Vector3D classes to give you the idea.  And some helper extensions to make using them easier to use.  You can take these and wrap the appropriate XYZ methods for each as well as define additional methods of your own.  And even implement additional interfaces, such as IEquatable.

 

 

public class Point3D
{
    public Point3D(XYZ revitXyz)
    {
        XYZ = revitXyz;
    }

    public Point3D() : this(XYZ.Zero)
    {}

    public Point3D(double x, double y, double z) : this(new XYZ(x, y, z))
    {}

    public XYZ XYZ { get; private set; }

    public double X => XYZ.X;
    public double Y => XYZ.Y;
    public double Z => XYZ.Z;

    public double DistanceTo(Point3D source)
    {
        return XYZ.DistanceTo(source.XYZ);
    }

    public Point3D Add(Vector3D source)
    {
        return new Point3D(XYZ.Add(source.XYZ));
    }

    public static Point3D operator +(Point3D point, Vector3D vector)
    {
        return point.Add(vector);
    }

    public override string ToString()
    {
        return XYZ.ToString();
    }

    public static Point3D Zero => new Point3D(XYZ.Zero);
}

 

 

 

public class Vector3D
{
    public Vector3D(XYZ revitXyz)
    {
        XYZ = revitXyz;
    }

    public Vector3D() : this(XYZ.Zero)
    {}

    public Vector3D(double x, double y, double z)  : this(new XYZ(x, y, z))
    {}

    public XYZ XYZ { get; private set; }

    public double X => XYZ.X;
    public double Y => XYZ.Y;
    public double Z => XYZ.Z;

    public Vector3D CrossProduct(Vector3D source)
    {
        return new Vector3D(XYZ.CrossProduct(source.XYZ));
    }
        
    public double GetLength()
    {
        return XYZ.GetLength();
    }

    public override string ToString()
    {
        return XYZ.ToString();
    }

    public static Vector3D BasisX => new Vector3D(XYZ.BasisX);
    public static Vector3D BasisY => new Vector3D(XYZ.BasisY);
    public static Vector3D BasisZ => new Vector3D(XYZ.BasisZ);
}

 

 

 

public static class XYZExtensions
{
    public static Point3D ToPoint3D(this XYZ revitXyz)
    {
        return new Point3D(revitXyz);
    }

    public static Vector3D ToVector3D(this XYZ revitXyz)
    {
        return new Vector3D(revitXyz);
    }
}

 

 

public static class LineExtensions
{
    public static Vector3D Direction(this Line revitLine)
    {
        return new Vector3D(revitLine.Direction);
    }

    public static Point3D Origin(this Line revitLine)
    {
        return new Point3D(revitLine.Origin);
    }
}

 

 

 

--
Bobby C. Jones
Message 6 of 12

MGO-Norsyn
Advocate
Advocate
Thank you. There's some stuff I'll have to learn. 🙂
0 Likes
Message 7 of 12

BobbyC.Jones
Advocate
Advocate

Ha!  Don't we all have much to learn; I certainly do!  You're very welcome and I hope this helped get you started.  And don't hesitate to ask if you have any more questions.

--
Bobby C. Jones
0 Likes
Message 8 of 12

jeremytammik
Autodesk
Autodesk

Edited and summarised for posterity:

 

http://thebuildingcoder.typepad.com/blog/2017/08/birthday-post-on-the-xyz-class.html

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 9 of 12

BobbyC.Jones
Advocate
Advocate

Hi Jeremy,

Very cool!  In looking over that code I noticed a call to an extension method that I did not supply.  For completeness sake:

 

 

public static class DoubleExtensions
{
private const double Tolerance = 1.0e-10;
public static bool IsAlmostEqualTo(this double double1, double double2) {
var isAlmostEqual = Math.Abs(double1 - double2) <= Tolerance;

return isAlmostEqual; }
}

 

--
Bobby C. Jones
0 Likes
Message 10 of 12

jeremytammik
Autodesk
Autodesk

Thank you!

 

Added to the post.

 

Cheers,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 11 of 12

MGO-Norsyn
Advocate
Advocate

Thank you very much for help on this topic. I've finally come around to implement the ConnectorXYZComparer in my codez and, while developing a new utility which at one point seeks to find distinct pipe connectors based on location in space by comparing Connector.Origin which is a XYZ, I have discovered that some connectors can have a much larger tolerance than the 1.0e-9 which is used in the BuildingCoder samples and utils.

 

In my test set, which is around 800 connectors, I got 32 false negatives. The largest delta is at 0.0004... ft. See the attached text file for my test results. So the HashString method from the ConnectorXYZComparer, which writes the coordinates to 9th decimal place returns slightly different hashstrings for connectors at the same location, but with large deltas. Also the Equals method operating with 1.0e-9 tolerance is returning false negatives.

 

So anybody using the Comparer provided by Jeremy is going to have some false negatives and wrong results when working with XYZs from MEP connectors.

 

To fix this I had to up the tolerance on the Equals method to 0.00328 ft -> roughly 1 mm, which is okay, because I will never have two distinct groups of connectors at distances lower than 1 mm, and I could probably have set it even higher safely.

 

Second part is that the hash string has to have only two decimals or else I was getting with four decimals:

(13.6971,19.1862,11.0728)
(13.6971,19.1866,11.0728)

And with three decimals:

(13.697,19.186,11.073)
(13.697,19.187,11.073)

I *HOPE* that two decimals is enough to cover the wildest imaginable tolerance for Revit piping Connectors...

0 Likes
Message 12 of 12

jeremytammik
Autodesk
Autodesk

Dear Mgo,

 

Thank you for your update, research and results.

 

I agree that 1 mm is a sensible threshold to use.

 

In fact, I often an integer-based coordinate system by rounding every single coordinate value to the closest millimetre when processing Revit models:

 

 

Best regards,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes