// // (C) Copyright 2003-2019 by Autodesk, Inc. // // Permission to use, copy, modify, and distribute this software in // object code form for any purpose and without fee is hereby granted, // provided that the above copyright notice appears in all copies and // that both that copyright notice and the limited warranty and // restricted rights notice below appear in all supporting // documentation. // // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE // UNINTERRUPTED OR ERROR FREE. // // Use, duplication, or disclosure by the U.S. Government is subject to // restrictions set forth in FAR 52.227-19 (Commercial Computer // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. // namespace Revit.SDK.Samples.CreateBeamSystem.CS { using System; using System.Collections.Generic; using System.Text; using System.Drawing; using Autodesk.Revit.DB; /// /// utility class contains some methods deal with 3D arithmetic /// public class GeometryUtil { /// /// The Application Creation object is used to create new instances of utility objects. /// public static Autodesk.Revit.Creation.Application CreApp; /// /// judge whether two XYZs are equal /// /// first XYZ /// second XYZ /// is equal public static bool CompareXYZ(Autodesk.Revit.DB.XYZ pnt1, Autodesk.Revit.DB.XYZ pnt2) { return (MathUtil.CompareDouble(pnt1.X, pnt2.X) && MathUtil.CompareDouble(pnt1.Y, pnt2.Y) && MathUtil.CompareDouble(pnt1.Z, pnt2.Z)); } /// /// sorted lines end to end to make a closed loop profile /// if input lines can't make a profile, null will return /// /// lines to be sorted /// sorted lines which can make a closed loop profile public static List SortLines(List originLines) { // at least 3 lines to form the profile if (originLines.Count < 3) { return null; } List lines = new List(originLines); List result = new List(); // sorted line end to end in order result.Add(lines[0]); Autodesk.Revit.DB.XYZ intersectPnt = lines[0].GetEndPoint(1); lines[0] = null; for (int i = 0; i < lines.Count; i++) { for (int j = 1; j < lines.Count; j++) { if (null == lines[j]) { continue; } if (CompareXYZ(lines[j].GetEndPoint(0), intersectPnt)) { result.Add(lines[j]); intersectPnt = lines[j].GetEndPoint(1); lines[j] = null; break; } else if (CompareXYZ(lines[j].GetEndPoint(1), intersectPnt)) { Autodesk.Revit.DB.XYZ startPnt = lines[j].GetEndPoint(1); Autodesk.Revit.DB.XYZ endPnt = lines[j].GetEndPoint(0); lines[j] = null; Line inversedLine = Line.CreateBound(startPnt, endPnt); result.Add(inversedLine); intersectPnt = inversedLine.GetEndPoint(1); break; } } } // there is line doesn't included in the closed loop if (result.Count != lines.Count) { return null; } // the last point in the sorted loop is same to the firs point if (!CompareXYZ(intersectPnt, result[0].GetEndPoint(0))) { return null; } // make sure there is only one closed region enclosed by the closed loop for (int i = 0; i < result.Count - 2; i++) { for (int j = i + 2; j < result.Count; j++) { if (i == 0 && j == (result.Count - 1)) { continue; } Line2D line1 = ConvertTo2DLine(result[i]); Line2D line2 = ConvertTo2DLine(result[j]); int count = Line2D.FindIntersection(line1, line2); // line shouldn't intersect with lines which not adjoin to it if (count > 0) { return null; } } } return result; } /// /// judge whether the lines are in the same horizontal plane /// /// lines to be judged /// is in the same horizontal plane public static bool InSameHorizontalPlane(List lines) { // all the Z coordinate of lines' start point and end point should be equal Autodesk.Revit.DB.XYZ firstPnt = lines[0].GetEndPoint(0); for (int i = 0; i < lines.Count; i++) { if (!MathUtil.CompareDouble(lines[i].GetEndPoint(0).Z, firstPnt.Z) || !MathUtil.CompareDouble(lines[i].GetEndPoint(1).Z, firstPnt.Z)) { return false; } } return true; } /// /// use the X and Y coordinate of 3D Line to new a Line2D instance /// /// 3D Line /// 2D Line private static Line2D ConvertTo2DLine(Line line) { PointF pnt1 = new PointF((float)line.GetEndPoint(0).X, (float)line.GetEndPoint(0).Y); PointF pnt2 = new PointF((float)line.GetEndPoint(1).X, (float)line.GetEndPoint(1).Y); return new Line2D(pnt1, pnt2); } } /// /// utility class contains some methods deal with some general arithmetic /// public class MathUtil { /// /// the minimum double used to compare /// public const double Double_Epsilon = 0.00001; /// /// the minimum positive float used to compare to as zero /// public const float Float_Epsilon = 0.00001f; /// /// forbidden default constructor /// private MathUtil() { } /// /// compare whether 2 double is equal using internal precision /// /// first value /// second value /// is Equal public static bool CompareDouble(double d1, double d2) { return Math.Abs(d1 - d2) < Double_Epsilon; } /// /// dot multiply two vector /// /// first vector /// second vector /// result public static float Dot(PointF pnt1, PointF pnt2) { return pnt1.X * pnt2.X + pnt1.Y * pnt2.Y; } /// /// multiply a float with a vector /// /// float value /// vector /// result public static PointF Multiply(float f, PointF pnt) { return new PointF(f * pnt.X, f * pnt.Y); } /// /// add 2 vector /// /// first vector /// second vector /// result public static PointF Add(PointF f1, PointF f2) { return new PointF(f1.X + f2.X, f1.Y + f2.Y); } /// /// subtract 2 vector /// /// first vector /// second vector /// result public static PointF Subtract(PointF f1, PointF f2) { return new PointF(f1.X - f2.X, f1.Y - f2.Y); } /// /// find and calculate the intersection of two interval [u0, u1] and [v0, v1] /// /// first interval /// first interval /// second interval /// second interval /// 2 intersections /// number of intersection public static int FindIntersection(float u0, float u1, float v0, float v1, ref float[] w) { if (u1 < v0 || u0 > v1) { return 0; } if (u1 == v0) { w[0] = u1; return 1; } if (u0 == v1) { w[0] = u0; return 1; } if (u1 > v0) { if (u0 < v1) { if (u0 < v0) { w[0] = v0; } else { w[0] = u0; } if (u1 > v1) { w[1] = v1; } else { w[1] = u1; } return 2; } else { w[0] = u0; return 1; } } else { w[0] = u1; return 1; } } /// /// get the minimum value of 2 float /// /// first float /// second float /// minimum float public static float GetMin(float f1, float f2) { if (f1 < f2) { return f1; } return f2; } /// /// get the maximum value of 2 float /// /// first float /// second float /// maximum float public static float GetMax(float f1, float f2) { if (f1 > f2) { return f1; } return f2; } } }