diff --git a/docs/object-model-schema.json b/docs/object-model-schema.json index 14a73a6c..36fd452a 100644 --- a/docs/object-model-schema.json +++ b/docs/object-model-schema.json @@ -1,6 +1,6 @@ { "VimFormatVersion": "1.0.0", - "SchemaVersion": "5.6.0", + "SchemaVersion": "5.7.0", "Tables": { "Vim.Area": [ "byte:IsGrossInterior", @@ -33,7 +33,12 @@ "index:Vim.ViewSheet:ViewSheet" ], "Vim.BasePoint": [ + "byte:IsClipped", "byte:IsSurveyPoint", + "double:AngleToTrueNorth", + "double:EastWest", + "double:Elevation", + "double:NorthSouth", "double:Position.X", "double:Position.Y", "double:Position.Z", @@ -147,8 +152,11 @@ "index:Vim.View:OwnerView", "index:Vim.Workset:Workset", "long:Id", + "string:Creator", "string:FamilyName", + "string:LastChangedBy", "string:Name", + "string:Owner", "string:Type", "string:UniqueId" ], diff --git a/docs/schema-diff.json b/docs/schema-diff.json index 9dad5eed..95b765e4 100644 --- a/docs/schema-diff.json +++ b/docs/schema-diff.json @@ -165,5 +165,17 @@ "Added": [ "Vim.BimDocument__long:FileLength" ] + }, + "5.6.0 to 5.7.0": { + "Added": [ + "Vim.BasePoint__byte:IsClipped", + "Vim.BasePoint__double:AngleToTrueNorth", + "Vim.BasePoint__double:EastWest", + "Vim.BasePoint__double:Elevation", + "Vim.BasePoint__double:NorthSouth", + "Vim.Element__string:Creator", + "Vim.Element__string:LastChangedBy", + "Vim.Element__string:Owner" + ] } } \ No newline at end of file diff --git a/src/cpp/vim/object-model.h b/src/cpp/vim/object-model.h index db11a65b..674f8b73 100644 --- a/src/cpp/vim/object-model.h +++ b/src/cpp/vim/object-model.h @@ -998,6 +998,9 @@ namespace Vim float mLocation_Z; std::string mFamilyName; bool mIsPinned; + std::string mCreator; + std::string mLastChangedBy; + std::string mOwner; int mLevelIndex; Level* mLevel; @@ -1051,6 +1054,9 @@ namespace Vim element->mLocation_Z = GetLocation_Z(elementIndex); element->mFamilyName = GetFamilyName(elementIndex); element->mIsPinned = GetIsPinned(elementIndex); + element->mCreator = GetCreator(elementIndex); + element->mLastChangedBy = GetLastChangedBy(elementIndex); + element->mOwner = GetOwner(elementIndex); element->mLevelIndex = GetLevelIndex(elementIndex); element->mPhaseCreatedIndex = GetPhaseCreatedIndex(elementIndex); element->mPhaseDemolishedIndex = GetPhaseDemolishedIndex(elementIndex); @@ -1076,6 +1082,9 @@ namespace Vim bool existsLocation_Z = mEntityTable.column_exists("float:Location.Z"); bool existsFamilyName = mEntityTable.column_exists("string:FamilyName"); bool existsIsPinned = mEntityTable.column_exists("byte:IsPinned"); + bool existsCreator = mEntityTable.column_exists("string:Creator"); + bool existsLastChangedBy = mEntityTable.column_exists("string:LastChangedBy"); + bool existsOwner = mEntityTable.column_exists("string:Owner"); bool existsLevel = mEntityTable.column_exists("index:Vim.Level:Level"); bool existsPhaseCreated = mEntityTable.column_exists("index:Vim.Phase:PhaseCreated"); bool existsPhaseDemolished = mEntityTable.column_exists("index:Vim.Phase:PhaseDemolished"); @@ -1131,6 +1140,12 @@ namespace Vim memcpy(isPinnedData, mEntityTable.mDataColumns["byte:IsPinned"].begin(), count * sizeof(bfast::byte)); } + const std::vector& creatorData = mEntityTable.column_exists("string:Creator") ? mEntityTable.mStringColumns["string:Creator"] : std::vector(); + + const std::vector& lastChangedByData = mEntityTable.column_exists("string:LastChangedBy") ? mEntityTable.mStringColumns["string:LastChangedBy"] : std::vector(); + + const std::vector& ownerData = mEntityTable.column_exists("string:Owner") ? mEntityTable.mStringColumns["string:Owner"] : std::vector(); + const std::vector& levelData = mEntityTable.column_exists("index:Vim.Level:Level") ? mEntityTable.mIndexColumns["index:Vim.Level:Level"] : std::vector(); const std::vector& phaseCreatedData = mEntityTable.column_exists("index:Vim.Phase:PhaseCreated") ? mEntityTable.mIndexColumns["index:Vim.Phase:PhaseCreated"] : std::vector(); const std::vector& phaseDemolishedData = mEntityTable.column_exists("index:Vim.Phase:PhaseDemolished") ? mEntityTable.mIndexColumns["index:Vim.Phase:PhaseDemolished"] : std::vector(); @@ -1165,6 +1180,12 @@ namespace Vim entity.mFamilyName = std::string(reinterpret_cast(mStrings[familyNameData[i]])); if (existsIsPinned) entity.mIsPinned = isPinnedData[i]; + if (existsCreator) + entity.mCreator = std::string(reinterpret_cast(mStrings[creatorData[i]])); + if (existsLastChangedBy) + entity.mLastChangedBy = std::string(reinterpret_cast(mStrings[lastChangedByData[i]])); + if (existsOwner) + entity.mOwner = std::string(reinterpret_cast(mStrings[ownerData[i]])); entity.mLevelIndex = existsLevel ? levelData[i] : -1; entity.mPhaseCreatedIndex = existsPhaseCreated ? phaseCreatedData[i] : -1; entity.mPhaseDemolishedIndex = existsPhaseDemolished ? phaseDemolishedData[i] : -1; @@ -1453,6 +1474,93 @@ namespace Vim return result; } + std::string GetCreator(int elementIndex) + { + if (elementIndex < 0 || elementIndex >= GetCount()) + return {}; + + if (mEntityTable.column_exists("string:Creator")) { + return std::string(reinterpret_cast(mStrings[mEntityTable.mStringColumns["string:Creator"][elementIndex]])); + } + + return {}; + } + + std::vector* GetAllCreator() + { + const auto count = GetCount(); + + const std::vector& creatorData = mEntityTable.column_exists("string:Creator") ? mEntityTable.mStringColumns["string:Creator"] : std::vector(); + + std::vector* result = new std::vector(); + result->reserve(count); + + for (int i = 0; i < count; ++i) + { + result->push_back(std::string(reinterpret_cast(mStrings[creatorData[i]]))); + } + + return result; + } + + std::string GetLastChangedBy(int elementIndex) + { + if (elementIndex < 0 || elementIndex >= GetCount()) + return {}; + + if (mEntityTable.column_exists("string:LastChangedBy")) { + return std::string(reinterpret_cast(mStrings[mEntityTable.mStringColumns["string:LastChangedBy"][elementIndex]])); + } + + return {}; + } + + std::vector* GetAllLastChangedBy() + { + const auto count = GetCount(); + + const std::vector& lastChangedByData = mEntityTable.column_exists("string:LastChangedBy") ? mEntityTable.mStringColumns["string:LastChangedBy"] : std::vector(); + + std::vector* result = new std::vector(); + result->reserve(count); + + for (int i = 0; i < count; ++i) + { + result->push_back(std::string(reinterpret_cast(mStrings[lastChangedByData[i]]))); + } + + return result; + } + + std::string GetOwner(int elementIndex) + { + if (elementIndex < 0 || elementIndex >= GetCount()) + return {}; + + if (mEntityTable.column_exists("string:Owner")) { + return std::string(reinterpret_cast(mStrings[mEntityTable.mStringColumns["string:Owner"][elementIndex]])); + } + + return {}; + } + + std::vector* GetAllOwner() + { + const auto count = GetCount(); + + const std::vector& ownerData = mEntityTable.column_exists("string:Owner") ? mEntityTable.mStringColumns["string:Owner"] : std::vector(); + + std::vector* result = new std::vector(); + result->reserve(count); + + for (int i = 0; i < count; ++i) + { + result->push_back(std::string(reinterpret_cast(mStrings[ownerData[i]]))); + } + + return result; + } + int GetLevelIndex(int elementIndex) { if (!mEntityTable.column_exists("index:Vim.Level:Level")) { @@ -11074,6 +11182,11 @@ namespace Vim public: int mIndex; bool mIsSurveyPoint; + bool mIsClipped; + double mNorthSouth; + double mEastWest; + double mElevation; + double mAngleToTrueNorth; double mPosition_X; double mPosition_Y; double mPosition_Z; @@ -11105,6 +11218,11 @@ namespace Vim BasePoint* basePoint = new BasePoint(); basePoint->mIndex = basePointIndex; basePoint->mIsSurveyPoint = GetIsSurveyPoint(basePointIndex); + basePoint->mIsClipped = GetIsClipped(basePointIndex); + basePoint->mNorthSouth = GetNorthSouth(basePointIndex); + basePoint->mEastWest = GetEastWest(basePointIndex); + basePoint->mElevation = GetElevation(basePointIndex); + basePoint->mAngleToTrueNorth = GetAngleToTrueNorth(basePointIndex); basePoint->mPosition_X = GetPosition_X(basePointIndex); basePoint->mPosition_Y = GetPosition_Y(basePointIndex); basePoint->mPosition_Z = GetPosition_Z(basePointIndex); @@ -11118,6 +11236,11 @@ namespace Vim std::vector* GetAll() { bool existsIsSurveyPoint = mEntityTable.column_exists("byte:IsSurveyPoint"); + bool existsIsClipped = mEntityTable.column_exists("byte:IsClipped"); + bool existsNorthSouth = mEntityTable.column_exists("double:NorthSouth"); + bool existsEastWest = mEntityTable.column_exists("double:EastWest"); + bool existsElevation = mEntityTable.column_exists("double:Elevation"); + bool existsAngleToTrueNorth = mEntityTable.column_exists("double:AngleToTrueNorth"); bool existsPosition_X = mEntityTable.column_exists("double:Position.X"); bool existsPosition_Y = mEntityTable.column_exists("double:Position.Y"); bool existsPosition_Z = mEntityTable.column_exists("double:Position.Z"); @@ -11136,6 +11259,31 @@ namespace Vim memcpy(isSurveyPointData, mEntityTable.mDataColumns["byte:IsSurveyPoint"].begin(), count * sizeof(bfast::byte)); } + bfast::byte* isClippedData = new bfast::byte[count]; + if (mEntityTable.column_exists("byte:IsClipped")) { + memcpy(isClippedData, mEntityTable.mDataColumns["byte:IsClipped"].begin(), count * sizeof(bfast::byte)); + } + + double* northSouthData = new double[count]; + if (mEntityTable.column_exists("double:NorthSouth")) { + memcpy(northSouthData, mEntityTable.mDataColumns["double:NorthSouth"].begin(), count * sizeof(double)); + } + + double* eastWestData = new double[count]; + if (mEntityTable.column_exists("double:EastWest")) { + memcpy(eastWestData, mEntityTable.mDataColumns["double:EastWest"].begin(), count * sizeof(double)); + } + + double* elevationData = new double[count]; + if (mEntityTable.column_exists("double:Elevation")) { + memcpy(elevationData, mEntityTable.mDataColumns["double:Elevation"].begin(), count * sizeof(double)); + } + + double* angleToTrueNorthData = new double[count]; + if (mEntityTable.column_exists("double:AngleToTrueNorth")) { + memcpy(angleToTrueNorthData, mEntityTable.mDataColumns["double:AngleToTrueNorth"].begin(), count * sizeof(double)); + } + double* position_XData = new double[count]; if (mEntityTable.column_exists("double:Position.X")) { memcpy(position_XData, mEntityTable.mDataColumns["double:Position.X"].begin(), count * sizeof(double)); @@ -11174,6 +11322,16 @@ namespace Vim entity.mIndex = i; if (existsIsSurveyPoint) entity.mIsSurveyPoint = isSurveyPointData[i]; + if (existsIsClipped) + entity.mIsClipped = isClippedData[i]; + if (existsNorthSouth) + entity.mNorthSouth = northSouthData[i]; + if (existsEastWest) + entity.mEastWest = eastWestData[i]; + if (existsElevation) + entity.mElevation = elevationData[i]; + if (existsAngleToTrueNorth) + entity.mAngleToTrueNorth = angleToTrueNorthData[i]; if (existsPosition_X) entity.mPosition_X = position_XData[i]; if (existsPosition_Y) @@ -11191,6 +11349,11 @@ namespace Vim } delete[] isSurveyPointData; + delete[] isClippedData; + delete[] northSouthData; + delete[] eastWestData; + delete[] elevationData; + delete[] angleToTrueNorthData; delete[] position_XData; delete[] position_YData; delete[] position_ZData; @@ -11229,6 +11392,146 @@ namespace Vim return result; } + bool GetIsClipped(int basePointIndex) + { + if (basePointIndex < 0 || basePointIndex >= GetCount()) + return {}; + + if (mEntityTable.column_exists("byte:IsClipped")) { + return static_cast(*reinterpret_cast(const_cast(mEntityTable.mDataColumns["byte:IsClipped"].begin() + basePointIndex * sizeof(bfast::byte)))); + } + + return {}; + } + + std::vector* GetAllIsClipped() + { + const auto count = GetCount(); + + bfast::byte* isClippedData = new bfast::byte[count]; + if (mEntityTable.column_exists("byte:IsClipped")) { + memcpy(isClippedData, mEntityTable.mDataColumns["byte:IsClipped"].begin(), count * sizeof(bfast::byte)); + } + + std::vector* result = new std::vector(isClippedData, isClippedData + count); + + delete[] isClippedData; + + return result; + } + + double GetNorthSouth(int basePointIndex) + { + if (basePointIndex < 0 || basePointIndex >= GetCount()) + return {}; + + if (mEntityTable.column_exists("double:NorthSouth")) { + return *reinterpret_cast(const_cast(mEntityTable.mDataColumns["double:NorthSouth"].begin() + basePointIndex * sizeof(double))); + } + + return {}; + } + + std::vector* GetAllNorthSouth() + { + const auto count = GetCount(); + + double* northSouthData = new double[count]; + if (mEntityTable.column_exists("double:NorthSouth")) { + memcpy(northSouthData, mEntityTable.mDataColumns["double:NorthSouth"].begin(), count * sizeof(double)); + } + + std::vector* result = new std::vector(northSouthData, northSouthData + count); + + delete[] northSouthData; + + return result; + } + + double GetEastWest(int basePointIndex) + { + if (basePointIndex < 0 || basePointIndex >= GetCount()) + return {}; + + if (mEntityTable.column_exists("double:EastWest")) { + return *reinterpret_cast(const_cast(mEntityTable.mDataColumns["double:EastWest"].begin() + basePointIndex * sizeof(double))); + } + + return {}; + } + + std::vector* GetAllEastWest() + { + const auto count = GetCount(); + + double* eastWestData = new double[count]; + if (mEntityTable.column_exists("double:EastWest")) { + memcpy(eastWestData, mEntityTable.mDataColumns["double:EastWest"].begin(), count * sizeof(double)); + } + + std::vector* result = new std::vector(eastWestData, eastWestData + count); + + delete[] eastWestData; + + return result; + } + + double GetElevation(int basePointIndex) + { + if (basePointIndex < 0 || basePointIndex >= GetCount()) + return {}; + + if (mEntityTable.column_exists("double:Elevation")) { + return *reinterpret_cast(const_cast(mEntityTable.mDataColumns["double:Elevation"].begin() + basePointIndex * sizeof(double))); + } + + return {}; + } + + std::vector* GetAllElevation() + { + const auto count = GetCount(); + + double* elevationData = new double[count]; + if (mEntityTable.column_exists("double:Elevation")) { + memcpy(elevationData, mEntityTable.mDataColumns["double:Elevation"].begin(), count * sizeof(double)); + } + + std::vector* result = new std::vector(elevationData, elevationData + count); + + delete[] elevationData; + + return result; + } + + double GetAngleToTrueNorth(int basePointIndex) + { + if (basePointIndex < 0 || basePointIndex >= GetCount()) + return {}; + + if (mEntityTable.column_exists("double:AngleToTrueNorth")) { + return *reinterpret_cast(const_cast(mEntityTable.mDataColumns["double:AngleToTrueNorth"].begin() + basePointIndex * sizeof(double))); + } + + return {}; + } + + std::vector* GetAllAngleToTrueNorth() + { + const auto count = GetCount(); + + double* angleToTrueNorthData = new double[count]; + if (mEntityTable.column_exists("double:AngleToTrueNorth")) { + memcpy(angleToTrueNorthData, mEntityTable.mDataColumns["double:AngleToTrueNorth"].begin(), count * sizeof(double)); + } + + std::vector* result = new std::vector(angleToTrueNorthData, angleToTrueNorthData + count); + + delete[] angleToTrueNorthData; + + return result; + } + double GetPosition_X(int basePointIndex) { if (basePointIndex < 0 || basePointIndex >= GetCount()) diff --git a/src/cs/math3d/Vim.Math3D/DMatrix4x4.cs b/src/cs/math3d/Vim.Math3D/DMatrix4x4.cs index cc6a5368..499cf222 100644 --- a/src/cs/math3d/Vim.Math3D/DMatrix4x4.cs +++ b/src/cs/math3d/Vim.Math3D/DMatrix4x4.cs @@ -638,5 +638,173 @@ public Matrix4x4 ToMatrix4x4() (float) M31, (float) M32, (float) M33, (float) M34, (float) M41, (float) M42, (float) M43, (float) M44); } + + /// + /// Attempts to calculate the inverse of the given matrix. If successful, result will contain the inverted matrix. + /// + /// The source matrix to invert. + /// If successful, contains the inverted matrix. + /// True if the source matrix could be inverted; False otherwise. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Invert(DMatrix4x4 matrix, out DMatrix4x4 result) + { + // -1 + // If you have matrix M, inverse Matrix M can compute + // + // -1 1 + // M = --------- A + // det(M) + // + // A is adjugate (adjoint) of M, where, + // + // T + // A = C + // + // C is Cofactor matrix of M, where, + // i + j + // C = (-1) * det(M ) + // ij ij + // + // [ a b c d ] + // M = [ e f g h ] + // [ i j k l ] + // [ m n o p ] + // + // First Row + // 2 | f g h | + // C = (-1) | j k l | = + ( f ( kp - lo ) - g ( jp - ln ) + h ( jo - kn ) ) + // 11 | n o p | + // + // 3 | e g h | + // C = (-1) | i k l | = - ( e ( kp - lo ) - g ( ip - lm ) + h ( io - km ) ) + // 12 | m o p | + // + // 4 | e f h | + // C = (-1) | i j l | = + ( e ( jp - ln ) - f ( ip - lm ) + h ( in - jm ) ) + // 13 | m n p | + // + // 5 | e f g | + // C = (-1) | i j k | = - ( e ( jo - kn ) - f ( io - km ) + g ( in - jm ) ) + // 14 | m n o | + // + // Second Row + // 3 | b c d | + // C = (-1) | j k l | = - ( b ( kp - lo ) - c ( jp - ln ) + d ( jo - kn ) ) + // 21 | n o p | + // + // 4 | a c d | + // C = (-1) | i k l | = + ( a ( kp - lo ) - c ( ip - lm ) + d ( io - km ) ) + // 22 | m o p | + // + // 5 | a b d | + // C = (-1) | i j l | = - ( a ( jp - ln ) - b ( ip - lm ) + d ( in - jm ) ) + // 23 | m n p | + // + // 6 | a b c | + // C = (-1) | i j k | = + ( a ( jo - kn ) - b ( io - km ) + c ( in - jm ) ) + // 24 | m n o | + // + // Third Row + // 4 | b c d | + // C = (-1) | f g h | = + ( b ( gp - ho ) - c ( fp - hn ) + d ( fo - gn ) ) + // 31 | n o p | + // + // 5 | a c d | + // C = (-1) | e g h | = - ( a ( gp - ho ) - c ( ep - hm ) + d ( eo - gm ) ) + // 32 | m o p | + // + // 6 | a b d | + // C = (-1) | e f h | = + ( a ( fp - hn ) - b ( ep - hm ) + d ( en - fm ) ) + // 33 | m n p | + // + // 7 | a b c | + // C = (-1) | e f g | = - ( a ( fo - gn ) - b ( eo - gm ) + c ( en - fm ) ) + // 34 | m n o | + // + // Fourth Row + // 5 | b c d | + // C = (-1) | f g h | = - ( b ( gl - hk ) - c ( fl - hj ) + d ( fk - gj ) ) + // 41 | j k l | + // + // 6 | a c d | + // C = (-1) | e g h | = + ( a ( gl - hk ) - c ( el - hi ) + d ( ek - gi ) ) + // 42 | i k l | + // + // 7 | a b d | + // C = (-1) | e f h | = - ( a ( fl - hj ) - b ( el - hi ) + d ( ej - fi ) ) + // 43 | i j l | + // + // 8 | a b c | + // C = (-1) | e f g | = + ( a ( fk - gj ) - b ( ek - gi ) + c ( ej - fi ) ) + // 44 | i j k | + // + // Cost of operation + // 53 adds, 104 muls, and 1 div. + double a = matrix.M11, b = matrix.M12, c = matrix.M13, d = matrix.M14; + double e = matrix.M21, f = matrix.M22, g = matrix.M23, h = matrix.M24; + double i = matrix.M31, j = matrix.M32, k = matrix.M33, l = matrix.M34; + double m = matrix.M41, n = matrix.M42, o = matrix.M43, p = matrix.M44; + + var kp_lo = k * p - l * o; + var jp_ln = j * p - l * n; + var jo_kn = j * o - k * n; + var ip_lm = i * p - l * m; + var io_km = i * o - k * m; + var in_jm = i * n - j * m; + + var a11 = +(f * kp_lo - g * jp_ln + h * jo_kn); + var a12 = -(e * kp_lo - g * ip_lm + h * io_km); + var a13 = +(e * jp_ln - f * ip_lm + h * in_jm); + var a14 = -(e * jo_kn - f * io_km + g * in_jm); + + var det = a * a11 + b * a12 + c * a13 + d * a14; + + if (det.Abs() < float.Epsilon) + { + result = new DMatrix4x4(float.NaN, float.NaN, float.NaN, float.NaN, + float.NaN, float.NaN, float.NaN, float.NaN, + float.NaN, float.NaN, float.NaN, float.NaN, + float.NaN, float.NaN, float.NaN, float.NaN); + return false; + } + + var invDet = 1.0f / det; + + result.M11 = a11 * invDet; + result.M21 = a12 * invDet; + result.M31 = a13 * invDet; + result.M41 = a14 * invDet; + + result.M12 = -(b * kp_lo - c * jp_ln + d * jo_kn) * invDet; + result.M22 = +(a * kp_lo - c * ip_lm + d * io_km) * invDet; + result.M32 = -(a * jp_ln - b * ip_lm + d * in_jm) * invDet; + result.M42 = +(a * jo_kn - b * io_km + c * in_jm) * invDet; + + var gp_ho = g * p - h * o; + var fp_hn = f * p - h * n; + var fo_gn = f * o - g * n; + var ep_hm = e * p - h * m; + var eo_gm = e * o - g * m; + var en_fm = e * n - f * m; + + result.M13 = +(b * gp_ho - c * fp_hn + d * fo_gn) * invDet; + result.M23 = -(a * gp_ho - c * ep_hm + d * eo_gm) * invDet; + result.M33 = +(a * fp_hn - b * ep_hm + d * en_fm) * invDet; + result.M43 = -(a * fo_gn - b * eo_gm + c * en_fm) * invDet; + + var gl_hk = g * l - h * k; + var fl_hj = f * l - h * j; + var fk_gj = f * k - g * j; + var el_hi = e * l - h * i; + var ek_gi = e * k - g * i; + var ej_fi = e * j - f * i; + + result.M14 = -(b * gl_hk - c * fl_hj + d * fk_gj) * invDet; + result.M24 = +(a * gl_hk - c * el_hi + d * ek_gi) * invDet; + result.M34 = -(a * fl_hj - b * el_hi + d * ej_fi) * invDet; + result.M44 = +(a * fk_gj - b * ek_gi + c * ej_fi) * invDet; + + return true; + } } } diff --git a/src/cs/math3d/Vim.Math3D/MathOps.cs b/src/cs/math3d/Vim.Math3D/MathOps.cs index 5d6ddf65..852af0ca 100644 --- a/src/cs/math3d/Vim.Math3D/MathOps.cs +++ b/src/cs/math3d/Vim.Math3D/MathOps.cs @@ -69,8 +69,8 @@ public static partial class MathOps [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Distance(this double v1, double v2) => (v1 - v2).Abs(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(this double v) => double.IsInfinity(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(this double v) => double.IsNaN(v); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AlmostEquals(this double v1, double v2, float tolerance = Constants.Tolerance) => (v2 - v1).AlmostZero(tolerance); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AlmostZero(this double v, float tolerance = Constants.Tolerance) => v.Abs() < tolerance; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AlmostEquals(this double v1, double v2, double tolerance = Constants.Tolerance) => (v2 - v1).AlmostZero(tolerance); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AlmostZero(this double v, double tolerance = Constants.Tolerance) => v.Abs() < tolerance; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Smoothstep(this double v) => v * v * (3 - 2 * v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Add (this int v1, int v2) => v1 + v2; diff --git a/src/cs/math3d/Vim.Math3D/MathOps.tt b/src/cs/math3d/Vim.Math3D/MathOps.tt index 5bfee6dc..2f2c0a6f 100644 --- a/src/cs/math3d/Vim.Math3D/MathOps.tt +++ b/src/cs/math3d/Vim.Math3D/MathOps.tt @@ -62,8 +62,8 @@ foreach (var t in floatTypes) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static <#= t #> Distance(this <#= t #> v1, <#= t #> v2) => (v1 - v2).Abs(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInfinity(this <#= t #> v) => <#= t #>.IsInfinity(v); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNaN(this <#= t #> v) => <#= t #>.IsNaN(v); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AlmostEquals(this <#= t #> v1, <#= t #> v2, float tolerance = Constants.Tolerance) => (v2 - v1).AlmostZero(tolerance); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AlmostZero(this <#= t #> v, float tolerance = Constants.Tolerance) => v.Abs() < tolerance; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AlmostEquals(this <#= t #> v1, <#= t #> v2, <#= t #> tolerance = Constants.Tolerance) => (v2 - v1).AlmostZero(tolerance); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool AlmostZero(this <#= t #> v, <#= t #> tolerance = Constants.Tolerance) => v.Abs() < tolerance; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static <#= t #> Smoothstep(this <#= t #> v) => v * v * (3 - 2 * v); <# } #> diff --git a/src/cs/math3d/Vim.Math3D/MathOpsPartial.cs b/src/cs/math3d/Vim.Math3D/MathOpsPartial.cs index 27f28066..b3d2faac 100644 --- a/src/cs/math3d/Vim.Math3D/MathOpsPartial.cs +++ b/src/cs/math3d/Vim.Math3D/MathOpsPartial.cs @@ -568,10 +568,24 @@ public static Matrix4x4 ToMatrix(this Quaternion self) => Matrix4x4.CreateRotation(self); /// - /// Returns a matri for translation and then rotation. + /// Returns a matrix for translation and then rotation. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Matrix4x4 ToMatrix(this Transform self) => Matrix4x4.CreateTRS(self.Position, self.Orientation, Vector3.One); + + /// + /// Casts the doubles in a DVector3 to create a Vector3 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 ToVector3(this DVector3 self) + => new Vector3((float) self.X, (float) self.Y, (float) self.Z); + + /// + /// Returns a DVector3 based on the given Vector3. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static DVector3 ToDVector3(this Vector3 self) + => new DVector3(self.X, self.Y, self.Z); } } diff --git a/src/cs/math3d/Vim.Math3D/Structs.cs b/src/cs/math3d/Vim.Math3D/Structs.cs index b2b0dbe4..d1f34b6f 100644 --- a/src/cs/math3d/Vim.Math3D/Structs.cs +++ b/src/cs/math3d/Vim.Math3D/Structs.cs @@ -129,7 +129,6 @@ public readonly partial struct Vector3 [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector3(float value) : this(value, value, value) { } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 operator -(Vector3 value) => Zero - value; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(Vector3 value1, Vector3 value2) => value1.X * value2.X + value1.Y * value2.Y + value1.Z * value2.Z; - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Cross(Vector3 v1, Vector3 v2) => new Vector3(v1.Y * v2.Z - v1.Z * v2.Y, v1.Z * v2.X - v1.X * v2.Z, v1.X * v2.Y - v1.Y * v2.X); [MethodImpl(MethodImplOptions.AggressiveInlining)] public float Dot(Vector3 value) => Vector3.Dot(this, value); [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool AlmostZero(float tolerance = Constants.Tolerance) => X.Abs() < tolerance && Y.Abs() < tolerance && Z.Abs() < tolerance; [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool AnyComponentNegative() => MinComponent() < 0; diff --git a/src/cs/math3d/Vim.Math3D/StructsPartial.cs b/src/cs/math3d/Vim.Math3D/StructsPartial.cs index a30b4aef..4b20c389 100644 --- a/src/cs/math3d/Vim.Math3D/StructsPartial.cs +++ b/src/cs/math3d/Vim.Math3D/StructsPartial.cs @@ -78,6 +78,13 @@ public Vector3 Cross(Vector3 vector2) Z * vector2.X - X * vector2.Z, X * vector2.Y - Y * vector2.X); + /// + /// Computes the cross product of two vectors. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Cross(Vector3 v1, Vector3 v2) + => v1.Cross(v2); + /// /// Returns the mixed product /// diff --git a/src/cs/vim/Vim.Format.Core/EntityTable_v2.cs b/src/cs/vim/Vim.Format.Core/EntityTable_v2.cs index e5dfc9fe..24417ab1 100644 --- a/src/cs/vim/Vim.Format.Core/EntityTable_v2.cs +++ b/src/cs/vim/Vim.Format.Core/EntityTable_v2.cs @@ -64,15 +64,20 @@ private static T GetColumnOrDefault(Dictionary map, string key, T /// Returns the index column based on the given column name. /// public int[] GetIndexColumnValues(string columnName) - => GetColumnOrDefault(IndexColumns, columnName)?.GetColumnValues(); + => GetColumnOrDefault(IndexColumns, columnName)?.GetColumnValues() ?? Array.Empty(); + + /// + /// Returns the integer string indices column based on the given column name. + /// + public int[] GetStringIndices(string columnName) + => GetColumnOrDefault(StringColumns, columnName)?.GetColumnValues() ?? Array.Empty(); /// /// Returns the string column based on the given column name. /// public string[] GetStringColumnValues(string columnName) { - var stringIndices = GetColumnOrDefault(StringColumns, columnName) - ?.GetColumnValues() ?? Array.Empty(); + var stringIndices = GetStringIndices(columnName); var strings = new string[stringIndices.Length]; diff --git a/src/cs/vim/Vim.Format.Tests/ElementParameterInfoServiceTests.cs b/src/cs/vim/Vim.Format.Tests/ElementParameterInfoServiceTests.cs index 32cbcfd4..1af0a61b 100644 --- a/src/cs/vim/Vim.Format.Tests/ElementParameterInfoServiceTests.cs +++ b/src/cs/vim/Vim.Format.Tests/ElementParameterInfoServiceTests.cs @@ -103,4 +103,33 @@ public static void TestUniformatLevelSplit() Assert.AreEqual("B20", FamilyTypeUniformatInfo.GetUniformatLevel2(partial)); Assert.AreEqual("", FamilyTypeUniformatInfo.GetUniformatLevel3(partial)); } + + + public static IEnumerable<(List, int, int, int, int)> TestSortAndGetCountCases = new[] + { + (new List { }, 0, 0, 0, 0), + (new List { "a" }, 1, 1, 0, 1), + (new List { "" }, 1, 0, 0, 1), + (new List { "", "" }, 2, 0, 0, 1), + (new List { "a", "" }, 2, 1, 0, 2), + (new List { "-1" }, 1, 1, 1, 1), + (new List { "-1", "" }, 2, 1, 1, 2), + (new List { "-1", "0" }, 2, 2, 2, 2), + (new List { "0", "0" }, 2, 2, 2, 1), + (new List { "a", "b", "c", "d" }, 4, 4, 0, 4), + (new List { "a", "a", "a", "a" }, 4, 4, 0, 1), + (new List { "a", "b", "b", "a" }, 4, 4, 0, 2), + (new List { "", "a", "0", "-1" }, 4, 3, 2, 4), + }; + + [TestCaseSource(nameof(TestSortAndGetCountCases))] + public static void TestSortAndGetCounts((List, int, int, int, int) item) + { + ParameterSummary.SortAndGetCounts(item.Item1, out var countTotal, out var countFilled, out var countSuspicious, out var countDistinct); + + Assert.AreEqual(item.Item2, countTotal); + Assert.AreEqual(item.Item3, countFilled); + Assert.AreEqual(item.Item4, countSuspicious); + Assert.AreEqual(item.Item5, countDistinct); + } } diff --git a/src/cs/vim/Vim.Format/ElementParameterInfo/ParameterSummary.cs b/src/cs/vim/Vim.Format/ElementParameterInfo/ParameterSummary.cs new file mode 100644 index 00000000..6495d66a --- /dev/null +++ b/src/cs/vim/Vim.Format/ElementParameterInfo/ParameterSummary.cs @@ -0,0 +1,325 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Vim.Format.ObjectModel; +using Vim.Util; + +namespace Vim.Format.ElementParameterInfo +{ + public class ParameterSummary + { + public string SummaryKey { get; set; } + + public int Descriptor { get; set; } + + public ElementKind ElementKindEnum { get; set; } + + public string ElementKind { get; set; } + + public string CategoryNameFull { get; set; } + + public string Name { get; set; } // Derived from Descriptor + + public string NamePbiCaseSensitive { get; set; } + + public string Group { get; set; } // Derived from Descriptor + + public string Guid { get; set; } + + public bool IsShared { get; set; } + + public string Flag { get; set; } + + public int CountTotal { get; set; } + + public int CountEmpty + => CountTotal - CountFilled; + + public float PercentEmpty + => CountTotal == 0 ? 0.0f : (float)CountEmpty / CountTotal; + + public int CountFilled { get; set; } + + public float PercentFilled + => CountTotal == 0 ? 0.0f : (float)CountFilled / CountTotal; + + public int CountDubious { get; set; } + + public float PercentDubious + => CountTotal == 0 ? 0.0f : (float)CountDubious / CountTotal; + + public int CountDistinct { get; set; } + + public int CountQuality + => CountFilled - CountDubious; + + public float PercentQuality + => CountFilled == 0 ? 0.0f : (float)CountQuality / CountFilled; + + public float PercentOverall + => PercentFilled * PercentQuality; + + public enum Rating + { + Perfect = 1, + Excellent = 2, + Good = 3, + Fair = 4, + Poor = 5, + SingleValue = 6, + Empty = 7 + } + + public const float ExcellentThreshold = .90f; + public const float GoodThreshold = .75f; + public const float FairThreshold = .5f; + + // Number prefixes are used to facilitate sorting. + public const string PerfectString = "1-Perfect"; + public const string ExcellentString = "2-Excellent"; + public const string GoodString = "3-Good"; + public const string FairString = "4-Fair"; + public const string PoorString = "5-Poor"; + public const string SingleValueString = "6-Single Value"; + public const string EmptyValueString = "7-Empty"; + + public static string GetRatingString(Rating rating) + { + switch (rating) + { + case Rating.Perfect: return PerfectString; + case Rating.Excellent: return ExcellentString; + case Rating.Good: return GoodString; + case Rating.Fair: return FairString; + case Rating.Poor: return PoorString; + case Rating.SingleValue: return SingleValueString; + case Rating.Empty: return EmptyValueString; + default: return "Unknown Rating"; + }; + } + + public const string PerfectColor = "#98CC73"; + public const string ExcellentColor = "#b1dd92"; + public const string GoodColor = "#dbdd92"; + public const string FairColor = "#ffe299"; + public const string PoorColor = "#ffa9cb"; + public const string SingleValueColor = "#ff9191"; + public const string EmptyValueColor = "#ff9191"; + + public static string GetRatingColor(Rating rating) + { + switch (rating) + { + case Rating.Perfect: return PerfectColor; + case Rating.Excellent: return ExcellentColor; + case Rating.Good: return GoodColor; + case Rating.Fair: return FairColor; + case Rating.Poor: return PoorColor; + case Rating.SingleValue: return SingleValueColor; + case Rating.Empty: return EmptyValueColor; + default: return "#FFFFFF"; + } + } + + public Rating ScoreFilledValue + { + get + { + // If there is only one distinct value, this information takes precedence. + if (CountEmpty == CountTotal) return Rating.Empty; + else if (CountDistinct == 1) return Rating.SingleValue; + else if (CountEmpty == 0) return Rating.Perfect; + else if (PercentFilled >= ExcellentThreshold) return Rating.Excellent; + else if (PercentFilled >= GoodThreshold) return Rating.Good; + else if (PercentFilled >= FairThreshold) return Rating.Fair; + else return Rating.Poor; + } + } + + public string ScoreFilled + => GetRatingString(ScoreFilledValue); + + public string ScoreFilledColor + => GetRatingColor(ScoreFilledValue); + + public Rating ScoreQualityValue + { + get + { + // If there is only one distinct value, this information takes precedence. + if (CountEmpty == CountTotal) return Rating.Empty; + else if (CountDistinct == 1) return Rating.SingleValue; + else if (CountDubious == 0) return Rating.Perfect; + else if (PercentQuality >= ExcellentThreshold) return Rating.Excellent; + else if (PercentQuality >= GoodThreshold) return Rating.Good; + else if (PercentQuality >= FairThreshold) return Rating.Fair; + else return Rating.Poor; + } + } + + public string ScoreQuality + => GetRatingString(ScoreQualityValue); + + public string ScoreQualityColor + => GetRatingColor(ScoreQualityValue); + + public Rating ScoreOverallValue + { + get + { + // If there is only one distinct value, this information takes precedence. + if (CountEmpty == CountTotal) return Rating.Empty; + else if (CountDistinct == 1) return Rating.SingleValue; + else if (CountDubious == 0 && CountEmpty == 0) return Rating.Perfect; + else if (PercentOverall >= ExcellentThreshold) return Rating.Excellent; + else if (PercentOverall >= GoodThreshold) return Rating.Good; + else if (PercentOverall >= FairThreshold) return Rating.Fair; + else return Rating.Poor; + } + } + + public string ScoreOverall + => GetRatingString(ScoreOverallValue); + + public string ScoreOverallColor + => GetRatingColor(ScoreOverallValue); + + public static IEnumerable GetParameterSummary( + ParameterTable parameterTable, + ParameterDescriptorTable descriptorTable, + ElementTable elementTable, + ElementKind[] elementKindArray, + CategoryTable categoryTable) + { + return Enumerable.Range(0, parameterTable.RowCount) + .GroupBy(i => new ParameterSummaryKey(i, parameterTable, elementTable, elementKindArray, categoryTable)) + .AsParallel() + .Select(g => + { + var parameterSummaryKey = g.Key; + var descriptorIndex = parameterSummaryKey.DescriptorIndex; + var elementKind = parameterSummaryKey.ElementKind; + var categoryIndex = parameterSummaryKey.CategoryIndex; + + var displayValues = g.Select(i => Parameter.SplitValues(parameterTable.GetValue(i)).DisplayValue).ToList(); + + SortAndGetCounts(displayValues, out var countTotal, out var countFilled, out var countDubious, out var countDistinct); + + var name = descriptorTable.GetName(descriptorIndex); + + var ps = new ParameterSummary() + { + SummaryKey = parameterSummaryKey.ToString(), + Descriptor = descriptorIndex, + ElementKindEnum = elementKind, + ElementKind = elementKind.ToDisplayString(), + CategoryNameFull = categoryTable.GetNameFull(categoryIndex), + Name = name, + NamePbiCaseSensitive = name.ToPbiCaseSensitiveString(), + Group = descriptorTable.GetGroup(descriptorIndex), + Guid = descriptorTable.GetGuid(descriptorIndex), + IsShared = descriptorTable.GetIsShared(descriptorIndex), + Flag = ParameterDescriptor.GetParameterDescriptorFlagString((ParameterDescriptorFlag) descriptorTable.GetFlags(descriptorIndex)), + CountTotal = countTotal, + CountFilled = countFilled, + CountDubious = countDubious, + CountDistinct = countDistinct + }; + + return ps; + }); + } + + public static void SortAndGetCounts( + List items, + out int countTotal, + out int countFilled, + out int countDubious, + out int countDistinct) + { + countTotal = items.Count; + countFilled = 0; + countDubious = 0; + countDistinct = 0; + + if (countTotal == 0) + return; + + // Sort the collection in place (O(N log N)) + items.Sort(); + + // Count (O(N)) + for (var i = 0; i < items.Count; ++i) + { + var item = items[i]; + + var (hasValue, isDubious) = Parameter.GetValueInfo(item); + + if (hasValue) + { + countFilled += 1; + } + + if (isDubious) + { + countDubious += 1; + } + + // Compare current item with the previous one + if (i == 0) + { + countDistinct = 1; + } + else + { + if (item != items[i - 1]) + { + countDistinct += 1; + } + } + } + } + } + + public class ParameterSummaryKey : IEquatable + { + public int DescriptorIndex { get; } + + public ElementKind ElementKind { get; } + + public int CategoryIndex { get; } + + /// + /// Constructor used for grouping + /// + public ParameterSummaryKey( + int parameterIndex, + ParameterTable parameterTable, + ElementTable elementTable, + ElementKind[] elementKindArray, + CategoryTable categoryTable) + { + DescriptorIndex = parameterTable.GetParameterDescriptorIndex(parameterIndex); + var elementIndex = parameterTable.GetElementIndex(parameterIndex); + ElementKind = elementKindArray.ElementAtOrDefault(elementIndex, ElementKind.Unknown); + CategoryIndex = elementTable.GetCategoryIndex(elementIndex); + } + + public override bool Equals(object obj) + => obj is ParameterSummaryKey psk && Equals(psk); + + public bool Equals(ParameterSummaryKey other) + => DescriptorIndex == other.DescriptorIndex + && ElementKind == other.ElementKind + && CategoryIndex == other.CategoryIndex; + + public override int GetHashCode() + => HashCodeStd2.Combine(DescriptorIndex, ElementKind, CategoryIndex); + + public override string ToString() + => GetStringKey(DescriptorIndex, ElementKind, CategoryIndex); + + public static string GetStringKey(int descriptorIndex, ElementKind elementKind, int categoryIndex) + => $"{descriptorIndex}|{(int)elementKind}|{categoryIndex}"; + } +} diff --git a/src/cs/vim/Vim.Format/ElementParameterInfo/RevitLinkInfo.cs b/src/cs/vim/Vim.Format/ElementParameterInfo/RevitLinkInfo.cs new file mode 100644 index 00000000..b2354743 --- /dev/null +++ b/src/cs/vim/Vim.Format/ElementParameterInfo/RevitLinkInfo.cs @@ -0,0 +1,249 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using Vim.Format.ObjectModel; +using Vim.Math3d; +using Vim.Util; + +namespace Vim.Format.ElementParameterInfo +{ + /// + /// Deals with revit links and project base point and survey point alignment. + /// To get your head wrapped around this topic, see: https://www.youtube.com/watch?v=TjP40wpFF34 + /// + public class RevitLinkInfo + { + // Summary + public DVector3 ProjectBasePointDelta { get; set; } + public DVector3 SurveyPointDelta { get; set; } + public bool ProjectBasePointsAreAligned { get; set; } + public bool SurveyPointsAreAligned { get; set; } + public bool ProjectBasePointDataIsEqual { get; set; } + public bool SurveyPointDataIsEqual { get; set; } + public string Summary { get; set; } + public string SummaryMetric { get; set; } + + // Link + public FamilyInstance LinkFamilyInstance { get; set; } + public Element LinkFamilyInstanceElement { get; set; } + public BimDocument LinkBimDocument { get; set; } + public BasePoint LinkProjectBasePoint { get; set; } + public DVector3 LinkProjectBasePointInParentSpace { get; set; } + public BasePoint LinkSurveyPoint { get; set; } + public DVector3 LinkSurveyPointInParentSpace { get; set; } + + // Parent + public BimDocument ParentBimDocument { get; set; } + public BasePoint ParentProjectBasePoint { get; set; } + public BasePoint ParentSurveyPoint { get; set; } + + private const float AlignmentTolerance = 1E-06f; + private const double AlignmentToleranceDouble = 1E-06d; + private const int StringDoubleDecimals = 6; + private static string ToStringRounded(double d) => d.ToString($"F{StringDoubleDecimals}"); + + public static List GetRevitLinkInfoList(EntityTableSet tableSet) + { + var result = new List(); + + var bimDocumentTable = tableSet.BimDocumentTable; + var basePointTable = tableSet.BasePointTable; + var categoryTable = tableSet.CategoryTable; + var elementTable = tableSet.ElementTable; + var familyInstanceTable = tableSet.FamilyInstanceTable; + var familyTypeTable = tableSet.FamilyTypeTable; + //var parameterTable = tableSet.ParameterTable; + //var parameterLookup = tableSet.ElementIndexMaps.ParameterIndicesFromElementIndex; + + var bimDocumentLinkMap = new Dictionary<(int parentIndex, string titleNoExtension), BimDocument>(); + for (var i = 0; i < bimDocumentTable.RowCount; ++i) + { + var bd = bimDocumentTable.Get(i); + var titleNoExtension = Path.GetFileNameWithoutExtension(bd.Title); // remove the extension; it is not present in the link's family type name. + if (string.IsNullOrEmpty(titleNoExtension)) + continue; + + var parentIndex = bd.ParentIndex; + var key = (parentIndex, titleNoExtension); + bimDocumentLinkMap[key] = bd; + } + + // Create a mapping of: + // - { BimDocument Index -> ProjectBasePoint } + // - { BimDocument Index -> SurveyPoint } + var bimDocumentProjectBasePointMap = new Dictionary(); + var bimDocumentSurveyPointMap = new Dictionary(); + for (var i = 0; i < basePointTable.RowCount; ++i) + { + var elementIndex = basePointTable.GetElementIndex(i); + var bimDocumentIndex = elementTable.GetBimDocumentIndex(elementIndex); + if (bimDocumentIndex < 0) + continue; + + var basePoint = basePointTable.Get(i); + if (basePoint.IsSurveyPoint) + { + bimDocumentSurveyPointMap[bimDocumentIndex] = basePoint; + } + else + { + bimDocumentProjectBasePointMap[bimDocumentIndex] = basePoint; + } + } + + // Iterate over the family instance table and collect all family instances whose elements are in the built-in category OST_RvtLinks + for (var i = 0; i < familyInstanceTable.RowCount; ++i) + { + var linkElementIndex = familyInstanceTable.GetElementIndex(i); + var categoryIndex = elementTable.GetCategoryIndex(linkElementIndex); + var builtInCategory = categoryTable.GetBuiltInCategory(categoryIndex); + + if (builtInCategory != "OST_RvtLinks") + continue; + + // The family type of the revit link instance contains the title of the linked bim document. + var familyTypeIndex = familyInstanceTable.GetFamilyTypeIndex(i); + if (familyTypeIndex < 0) + continue; + + var parentBimDocument = elementTable.GetBimDocument(linkElementIndex); + if (parentBimDocument == null) + continue; + + var familyTypeElementIndex = familyTypeTable.GetElementIndex(familyTypeIndex); + var bimDocumentTitleNoExtension = Path.GetFileNameWithoutExtension(elementTable.GetName(familyTypeElementIndex)); + + if (!bimDocumentLinkMap.TryGetValue((parentBimDocument.Index, bimDocumentTitleNoExtension), out var linkedBimDocument) || linkedBimDocument == null) + continue; + + var linkFi = familyInstanceTable.Get(i); + var linkTransform = DMatrix4x4.CreateFromRows(linkFi.BasisX.ToDVector3(), linkFi.BasisY.ToDVector3(), linkFi.BasisZ.ToDVector3(), linkFi.Translation.ToDVector3()); + + var pbpLink = bimDocumentProjectBasePointMap.GetOrDefault(linkedBimDocument.Index); + var spLink = bimDocumentSurveyPointMap.GetOrDefault(linkedBimDocument.Index); + + var pbpParent = bimDocumentProjectBasePointMap.GetOrDefault(parentBimDocument.Index); + var spParent = bimDocumentSurveyPointMap.GetOrDefault(parentBimDocument.Index); + + var pbpAligned = false; + DVector3 pbpParentSpacePosition = default; + var spAligned = false; + DVector3 spParentSpacePosition = default; + + if (pbpLink != null && pbpParent != null) + { + pbpParentSpacePosition = pbpLink.Position.Transform(linkTransform); + pbpAligned = pbpParentSpacePosition.AlmostEquals(pbpParent.Position, AlignmentTolerance); + } + + if (spLink != null && spParent != null) + { + spParentSpacePosition = spLink.Position.Transform(linkTransform); + spAligned = spParentSpacePosition.AlmostEquals(spParent.Position, AlignmentTolerance); + } + + var info = new RevitLinkInfo + { + LinkFamilyInstance = linkFi, + LinkFamilyInstanceElement = elementTable.Get(linkElementIndex), + LinkBimDocument = linkedBimDocument, + LinkProjectBasePoint = pbpLink, + LinkProjectBasePointInParentSpace = pbpParentSpacePosition, + LinkSurveyPoint = spLink, + LinkSurveyPointInParentSpace = spParentSpacePosition, + ParentBimDocument = parentBimDocument, + ParentProjectBasePoint = pbpParent, + ParentSurveyPoint = spParent, + ProjectBasePointsAreAligned = pbpAligned, + SurveyPointsAreAligned = spAligned, + }; + + var pbpDelta = info.LinkProjectBasePointInParentSpace - info.ParentProjectBasePoint.Position; // the corrective offset to align the link project base point marker to the parent's. + info.ProjectBasePointDelta = pbpDelta; + + var spDelta = info.LinkSurveyPointInParentSpace - info.ParentSurveyPoint.Position; // the corrective offset to align the link survey point marker to the parent's. + info.SurveyPointDelta = spDelta; + + var pbpDataIsEqual = BasePointDataIsAlmostEqual(info.ParentProjectBasePoint, info.LinkProjectBasePoint, out var pbpDataSummary, out var pbpDataSummaryMetric); + info.ProjectBasePointDataIsEqual = pbpDataIsEqual; + + var spDataIsEqual = BasePointDataIsAlmostEqual(info.ParentSurveyPoint, info.LinkSurveyPoint, out var spDataSummary, out var spDataSummaryMetric); + info.SurveyPointDataIsEqual = spDataIsEqual; + + info.Summary = GetSummary(pbpAligned, pbpDelta, pbpDataIsEqual, pbpDataSummary, spAligned, spDelta, spDataIsEqual, spDataSummary, false); + info.SummaryMetric = GetSummary(pbpAligned, pbpDelta, pbpDataIsEqual, pbpDataSummaryMetric, spAligned, spDelta, spDataIsEqual, spDataSummaryMetric, true); + + result.Add(info); + } + + return result; + } + + private static string GetSummary( + bool pbpAligned, + DVector3 pbpDelta, + bool pbpDataIsEqual, + string pbpDataSummary, + bool spAligned, + DVector3 spDelta, + bool spDataIsEqual, + string spDataSummary, + bool isMetric) + { + var pbpDeltaStr = DVector3ToStringRounded(pbpDelta, isMetric); + var spDeltaStr = DVector3ToStringRounded(spDelta, isMetric); + + return +$@"{(pbpAligned ? "✅" : "❌")} Project Base Point markers {(pbpAligned ? "are" : "are not")} aligned.{(pbpAligned ? "" : $" 🔼 {pbpDeltaStr}")} +{(pbpDataIsEqual ? "✅" : "❌")} Project Base Point data {(pbpDataIsEqual ? "is" : "is not")} equal.{(pbpDataIsEqual ? "" : $"{System.Environment.NewLine}{pbpDataSummary}")} +{(spAligned ? "✅" : "❌")} Survey Point markers {(spAligned ? "are" : "are not")} aligned.{(spAligned ? "" : $" 🔼 {spDeltaStr}")} +{(spDataIsEqual ? "✅" : "❌")} Survey Point data {(spDataIsEqual ? "is" : "is not")} equal.{(spDataIsEqual ? "" : $"{System.Environment.NewLine}{spDataSummary}")}"; + } + + private static string DVector3ToStringRounded(DVector3 v, bool isMetric) + { + var unitSuffix = isMetric ? "m" : "ft"; + var x = isMetric ? Units.FeetToMeters(v.X) ?? 0d : v.X; + var y = isMetric ? Units.FeetToMeters(v.Y) ?? 0d : v.Y; + var z = isMetric ? Units.FeetToMeters(v.Z) ?? 0d : v.Z; + return $"({ToStringRounded(x)}, {ToStringRounded(y)}, {ToStringRounded(z)}) {unitSuffix}"; + } + + private static bool BasePointDataIsAlmostEqual(BasePoint bp_parent, BasePoint bp_link, out string summary, out string summaryMetric) + { + var summaryList = new List(); + var summaryListMetric = new List(); + const string tabPrefix = " - "; + + bool CompareBasePointDataValues(string property, double parentValue, double linkValue, bool canConvertFeetToMeters) + { + var almostEqual = parentValue.AlmostEquals(linkValue, AlignmentToleranceDouble); + if (!almostEqual) + { + // Imperial + summaryList.Add($"{tabPrefix}[{property}] Parent: {ToStringRounded(parentValue)} <> Link: {ToStringRounded(linkValue)}"); + + // Metric + var parentValueMetric = canConvertFeetToMeters ? Units.FeetToMeters(parentValue) ?? 0d : parentValue; + var linkValueMetric = canConvertFeetToMeters ? Units.FeetToMeters(linkValue) ?? 0d : linkValue; + var unitSuffix = canConvertFeetToMeters ? "m" : ""; + summaryListMetric.Add($"{tabPrefix}[{property}] Parent: {ToStringRounded(parentValueMetric)}{unitSuffix} <> Link: {ToStringRounded(linkValueMetric)}{unitSuffix}"); + } + + return almostEqual; + } + + var nsAlmostEqual = CompareBasePointDataValues("N/S", bp_parent.NorthSouth, bp_link.NorthSouth, true); + var ewAlmostEqual = CompareBasePointDataValues("E/W", bp_parent.EastWest, bp_link.EastWest, true); + var elevationAlmostEqual = CompareBasePointDataValues("Elevation", bp_parent.Elevation, bp_link.Elevation, true); + var angleToTrueNorthAlmostEqual = CompareBasePointDataValues("Angle to True North", bp_parent.AngleToTrueNorth, bp_link.AngleToTrueNorth, false); + + var dataIsAlmostEqual = nsAlmostEqual && ewAlmostEqual && elevationAlmostEqual && angleToTrueNorthAlmostEqual; + + summary = dataIsAlmostEqual ? "" : string.Join(System.Environment.NewLine, summaryList); + summaryMetric = dataIsAlmostEqual ? "" : string.Join(System.Environment.NewLine, summaryListMetric); + + return dataIsAlmostEqual; + } + } +} diff --git a/src/cs/vim/Vim.Format/ObjectModel/ObjectModel.cs b/src/cs/vim/Vim.Format/ObjectModel/ObjectModel.cs index 468b64a3..fa19da2a 100644 --- a/src/cs/vim/Vim.Format/ObjectModel/ObjectModel.cs +++ b/src/cs/vim/Vim.Format/ObjectModel/ObjectModel.cs @@ -14,6 +14,17 @@ public static class SchemaVersion // ReSharper disable MemberHidesStaticFromOuterClass public static class History { + // Schema additions + // Vim.Element__string:Creator + // Vim.Element__string:LastChangedBy + // Vim.Element__string:Owner + // Vim.BasePoint__byte:IsClipped + // Vim.BasePoint__double:NorthSouth + // Vim.BasePoint__double:EastWest + // Vim.BasePoint__double:Elevation + // Vim.BasePoint__double:AngleToTrueNorth + public const string v5_7_0 = "5.7.0"; + // Schema additions // Vim.BimDocument__long:FileLength public const string v5_6_0 = "5.6.0"; @@ -175,7 +186,8 @@ public static class History // ReSharper enable MemberHidesStaticFromOuterClass // [MAINTAIN] Add more object model SerializableVersions below and update the current one. - public static SerializableVersion Current => v5_6_0; + public static SerializableVersion Current => v5_7_0; + public static SerializableVersion v5_7_0 => SerializableVersion.Parse(History.v5_7_0); public static SerializableVersion v5_6_0 => SerializableVersion.Parse(History.v5_6_0); public static SerializableVersion v5_5_0 => SerializableVersion.Parse(History.v5_5_0); public static SerializableVersion v5_4_0 => SerializableVersion.Parse(History.v5_4_0); @@ -582,6 +594,39 @@ public ParameterDescriptorFlag GetParameterDescriptorFlags() public ParameterDescriptorStorageType GetParameterDescriptorStorageType() => (ParameterDescriptorStorageType) StorageType; + + public static string GetParameterDescriptorFlagString(ParameterDescriptorFlag flag) + { + switch (flag) + { + case ParameterDescriptorFlag.IsBuiltIn: + return "Built In"; + case ParameterDescriptorFlag.IsProject: + return "Project"; + case ParameterDescriptorFlag.IsGlobal: + return "Global"; + default: + return "Standard"; + } + } + + public static string GetParameterDescriptorStorageTypeString(ParameterDescriptorStorageType storageType) + { + switch (storageType) + { + case ParameterDescriptorStorageType.Integer: + return "Integer"; + case ParameterDescriptorStorageType.Double: + return "Double"; + case ParameterDescriptorStorageType.String: + return "String"; + case ParameterDescriptorStorageType.ElementId: + return "ElementId"; + case ParameterDescriptorStorageType.Unknown: + default: + return "Unknown"; + } + } } /// @@ -687,6 +732,16 @@ public static bool TryParseNativeValueAsBoolean(string nativeValue, ParameterDes public bool TryParseNativeValueAsBoolean(ParameterDescriptor desc, out bool result) => TryParseNativeValueAsBoolean(Values.NativeValue, desc, out result); + + public static (bool HasValue, bool IsDubious) GetValueInfo(string value) + { + var trimmed = (value ?? "").Trim(); + + var hasValue = !string.IsNullOrEmpty(trimmed); + var isDubious = hasValue && (trimmed == "-1" || trimmed == "0"); + + return (hasValue, isDubious); + } } /// @@ -719,6 +774,10 @@ public Vector3 Location public string FamilyName; public bool IsPinned; + public string Creator; + public string LastChangedBy; + public string Owner; + public Relation _Level; public Relation _PhaseCreated; public Relation _PhaseDemolished; @@ -1681,6 +1740,31 @@ public partial class BasePoint : EntityWithElement /// public bool IsSurveyPoint; + /// + /// The clipped state of the survey point. This is only relevant if IsSurveyPoint is true, false otherwise. + /// + public bool IsClipped; + + /// + /// The NorthSouth (N/S) value in Revit. + /// + public double NorthSouth; + + /// + /// The EastWest (E/W) value in Revit. + /// + public double EastWest; + + /// + /// The Elevation value in Revit. + /// + public double Elevation; + + /// + /// The AngleToTrueNorth value in Revit, in radians. + /// + public double AngleToTrueNorth; + /// /// The position of the BasePoint relative to the BimDocument's internal origin. /// diff --git a/src/cs/vim/Vim.Format/ObjectModel/ObjectModelGenerated.cs b/src/cs/vim/Vim.Format/ObjectModel/ObjectModelGenerated.cs index f3213ff8..8df50365 100644 --- a/src/cs/vim/Vim.Format/ObjectModel/ObjectModelGenerated.cs +++ b/src/cs/vim/Vim.Format/ObjectModel/ObjectModelGenerated.cs @@ -191,6 +191,9 @@ public override bool FieldsAreEqual(object obj) (Location_Z == other.Location_Z) && (FamilyName == other.FamilyName) && (IsPinned == other.IsPinned) && + (Creator == other.Creator) && + (LastChangedBy == other.LastChangedBy) && + (Owner == other.Owner) && (_Level?.Index == other._Level?.Index) && (_PhaseCreated?.Index == other._PhaseCreated?.Index) && (_PhaseDemolished?.Index == other._PhaseDemolished?.Index) && @@ -1501,6 +1504,11 @@ public override bool FieldsAreEqual(object obj) var fieldsAreEqual = (Index == other.Index) && (IsSurveyPoint == other.IsSurveyPoint) && + (IsClipped == other.IsClipped) && + (NorthSouth == other.NorthSouth) && + (EastWest == other.EastWest) && + (Elevation == other.Elevation) && + (AngleToTrueNorth == other.AngleToTrueNorth) && (Position_X == other.Position_X) && (Position_Y == other.Position_Y) && (Position_Z == other.Position_Z) && @@ -2129,6 +2137,12 @@ public Parameter GetParameter(int n) public String GetElementFamilyName(int index, String defaultValue = "") => ElementFamilyName?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; public IArray ElementIsPinned { get; } public Boolean GetElementIsPinned(int index, Boolean defaultValue = default) => ElementIsPinned?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; + public IArray ElementCreator { get; } + public String GetElementCreator(int index, String defaultValue = "") => ElementCreator?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; + public IArray ElementLastChangedBy { get; } + public String GetElementLastChangedBy(int index, String defaultValue = "") => ElementLastChangedBy?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; + public IArray ElementOwner { get; } + public String GetElementOwner(int index, String defaultValue = "") => ElementOwner?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; public IArray ElementLevelIndex { get; } public int GetElementLevelIndex(int index) => ElementLevelIndex?.ElementAtOrDefault(index, EntityRelation.None) ?? EntityRelation.None; public IArray ElementPhaseCreatedIndex { get; } @@ -2168,6 +2182,9 @@ public Element GetElement(int n) r.Location_Z = ElementLocation_Z.ElementAtOrDefault(n); r.FamilyName = ElementFamilyName.ElementAtOrDefault(n); r.IsPinned = ElementIsPinned.ElementAtOrDefault(n); + r.Creator = ElementCreator.ElementAtOrDefault(n); + r.LastChangedBy = ElementLastChangedBy.ElementAtOrDefault(n); + r.Owner = ElementOwner.ElementAtOrDefault(n); r._Level = new Relation(GetElementLevelIndex(n), GetLevel); r._PhaseCreated = new Relation(GetElementPhaseCreatedIndex(n), GetPhase); r._PhaseDemolished = new Relation(GetElementPhaseDemolishedIndex(n), GetPhase); @@ -3420,6 +3437,16 @@ public ElementInWarning GetElementInWarning(int n) public IArray BasePointIsSurveyPoint { get; } public Boolean GetBasePointIsSurveyPoint(int index, Boolean defaultValue = default) => BasePointIsSurveyPoint?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; + public IArray BasePointIsClipped { get; } + public Boolean GetBasePointIsClipped(int index, Boolean defaultValue = default) => BasePointIsClipped?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; + public IArray BasePointNorthSouth { get; } + public Double GetBasePointNorthSouth(int index, Double defaultValue = default) => BasePointNorthSouth?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; + public IArray BasePointEastWest { get; } + public Double GetBasePointEastWest(int index, Double defaultValue = default) => BasePointEastWest?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; + public IArray BasePointElevation { get; } + public Double GetBasePointElevation(int index, Double defaultValue = default) => BasePointElevation?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; + public IArray BasePointAngleToTrueNorth { get; } + public Double GetBasePointAngleToTrueNorth(int index, Double defaultValue = default) => BasePointAngleToTrueNorth?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; public IArray BasePointPosition_X { get; } public Double GetBasePointPosition_X(int index, Double defaultValue = default) => BasePointPosition_X?.ElementAtOrDefault(index, defaultValue) ?? defaultValue; public IArray BasePointPosition_Y { get; } @@ -3443,6 +3470,11 @@ public BasePoint GetBasePoint(int n) r.Document = Document; r.Index = n; r.IsSurveyPoint = BasePointIsSurveyPoint.ElementAtOrDefault(n); + r.IsClipped = BasePointIsClipped.ElementAtOrDefault(n); + r.NorthSouth = BasePointNorthSouth.ElementAtOrDefault(n); + r.EastWest = BasePointEastWest.ElementAtOrDefault(n); + r.Elevation = BasePointElevation.ElementAtOrDefault(n); + r.AngleToTrueNorth = BasePointAngleToTrueNorth.ElementAtOrDefault(n); r.Position_X = BasePointPosition_X.ElementAtOrDefault(n); r.Position_Y = BasePointPosition_Y.ElementAtOrDefault(n); r.Position_Z = BasePointPosition_Z.ElementAtOrDefault(n); @@ -4041,6 +4073,9 @@ public DocumentModel(Document d, bool inParallel = true) ElementLocation_Z = ElementEntityTable?.GetDataColumnValues("float:Location.Z") ?? Array.Empty().ToIArray(); ElementFamilyName = ElementEntityTable?.GetStringColumnValues("string:FamilyName") ?? Array.Empty().ToIArray(); ElementIsPinned = ElementEntityTable?.GetDataColumnValues("byte:IsPinned") ?? Array.Empty().ToIArray(); + ElementCreator = ElementEntityTable?.GetStringColumnValues("string:Creator") ?? Array.Empty().ToIArray(); + ElementLastChangedBy = ElementEntityTable?.GetStringColumnValues("string:LastChangedBy") ?? Array.Empty().ToIArray(); + ElementOwner = ElementEntityTable?.GetStringColumnValues("string:Owner") ?? Array.Empty().ToIArray(); WorksetId = WorksetEntityTable?.GetDataColumnValues("int:Id") ?? Array.Empty().ToIArray(); WorksetName = WorksetEntityTable?.GetStringColumnValues("string:Name") ?? Array.Empty().ToIArray(); WorksetKind = WorksetEntityTable?.GetStringColumnValues("string:Kind") ?? Array.Empty().ToIArray(); @@ -4207,6 +4242,11 @@ public DocumentModel(Document d, bool inParallel = true) WarningSeverity = WarningEntityTable?.GetStringColumnValues("string:Severity") ?? Array.Empty().ToIArray(); WarningDescription = WarningEntityTable?.GetStringColumnValues("string:Description") ?? Array.Empty().ToIArray(); BasePointIsSurveyPoint = BasePointEntityTable?.GetDataColumnValues("byte:IsSurveyPoint") ?? Array.Empty().ToIArray(); + BasePointIsClipped = BasePointEntityTable?.GetDataColumnValues("byte:IsClipped") ?? Array.Empty().ToIArray(); + BasePointNorthSouth = BasePointEntityTable?.GetDataColumnValues("double:NorthSouth") ?? Array.Empty().ToIArray(); + BasePointEastWest = BasePointEntityTable?.GetDataColumnValues("double:EastWest") ?? Array.Empty().ToIArray(); + BasePointElevation = BasePointEntityTable?.GetDataColumnValues("double:Elevation") ?? Array.Empty().ToIArray(); + BasePointAngleToTrueNorth = BasePointEntityTable?.GetDataColumnValues("double:AngleToTrueNorth") ?? Array.Empty().ToIArray(); BasePointPosition_X = BasePointEntityTable?.GetDataColumnValues("double:Position.X") ?? Array.Empty().ToIArray(); BasePointPosition_Y = BasePointEntityTable?.GetDataColumnValues("double:Position.Y") ?? Array.Empty().ToIArray(); BasePointPosition_Z = BasePointEntityTable?.GetDataColumnValues("double:Position.Z") ?? Array.Empty().ToIArray(); @@ -5175,6 +5215,9 @@ public ElementTable(SerializableEntityTable rawTable, string[] stringTable, Enti Column_Location_Z = GetDataColumnValues("float:Location.Z") ?? Array.Empty(); Column_FamilyName = GetStringColumnValues("string:FamilyName") ?? Array.Empty(); Column_IsPinned = GetDataColumnValues("byte:IsPinned") ?? Array.Empty(); + Column_Creator = GetStringColumnValues("string:Creator") ?? Array.Empty(); + Column_LastChangedBy = GetStringColumnValues("string:LastChangedBy") ?? Array.Empty(); + Column_Owner = GetStringColumnValues("string:Owner") ?? Array.Empty(); Column_LevelIndex = GetIndexColumnValues("index:Vim.Level:Level") ?? Array.Empty(); Column_PhaseCreatedIndex = GetIndexColumnValues("index:Vim.Phase:PhaseCreated") ?? Array.Empty(); Column_PhaseDemolishedIndex = GetIndexColumnValues("index:Vim.Phase:PhaseDemolished") ?? Array.Empty(); @@ -5206,6 +5249,12 @@ public ElementTable(SerializableEntityTable rawTable, string[] stringTable, Enti public String GetFamilyName(int index, String @default = "") => Column_FamilyName.ElementAtOrDefault(index, @default); public Boolean[] Column_IsPinned { get; } public Boolean GetIsPinned(int index, Boolean @default = default) => Column_IsPinned.ElementAtOrDefault(index, @default); + public String[] Column_Creator { get; } + public String GetCreator(int index, String @default = "") => Column_Creator.ElementAtOrDefault(index, @default); + public String[] Column_LastChangedBy { get; } + public String GetLastChangedBy(int index, String @default = "") => Column_LastChangedBy.ElementAtOrDefault(index, @default); + public String[] Column_Owner { get; } + public String GetOwner(int index, String @default = "") => Column_Owner.ElementAtOrDefault(index, @default); public int[] Column_LevelIndex { get; } public int GetLevelIndex(int index) => Column_LevelIndex.ElementAtOrDefault(index, EntityRelation.None); public Level GetLevel(int index) => _GetReferencedLevel(GetLevelIndex(index)); @@ -5265,6 +5314,9 @@ public Element Get(int index) r.Location_Z = GetLocation_Z(index); r.FamilyName = GetFamilyName(index); r.IsPinned = GetIsPinned(index); + r.Creator = GetCreator(index); + r.LastChangedBy = GetLastChangedBy(index); + r.Owner = GetOwner(index); r._Level = new Relation(GetLevelIndex(index), _GetReferencedLevel); r._PhaseCreated = new Relation(GetPhaseCreatedIndex(index), _GetReferencedPhaseCreated); r._PhaseDemolished = new Relation(GetPhaseDemolishedIndex(index), _GetReferencedPhaseDemolished); @@ -7328,6 +7380,11 @@ public BasePointTable(SerializableEntityTable rawTable, string[] stringTable, En { ParentTableSet = parentTableSet; Column_IsSurveyPoint = GetDataColumnValues("byte:IsSurveyPoint") ?? Array.Empty(); + Column_IsClipped = GetDataColumnValues("byte:IsClipped") ?? Array.Empty(); + Column_NorthSouth = GetDataColumnValues("double:NorthSouth") ?? Array.Empty(); + Column_EastWest = GetDataColumnValues("double:EastWest") ?? Array.Empty(); + Column_Elevation = GetDataColumnValues("double:Elevation") ?? Array.Empty(); + Column_AngleToTrueNorth = GetDataColumnValues("double:AngleToTrueNorth") ?? Array.Empty(); Column_Position_X = GetDataColumnValues("double:Position.X") ?? Array.Empty(); Column_Position_Y = GetDataColumnValues("double:Position.Y") ?? Array.Empty(); Column_Position_Z = GetDataColumnValues("double:Position.Z") ?? Array.Empty(); @@ -7339,6 +7396,16 @@ public BasePointTable(SerializableEntityTable rawTable, string[] stringTable, En public Boolean[] Column_IsSurveyPoint { get; } public Boolean GetIsSurveyPoint(int index, Boolean @default = default) => Column_IsSurveyPoint.ElementAtOrDefault(index, @default); + public Boolean[] Column_IsClipped { get; } + public Boolean GetIsClipped(int index, Boolean @default = default) => Column_IsClipped.ElementAtOrDefault(index, @default); + public Double[] Column_NorthSouth { get; } + public Double GetNorthSouth(int index, Double @default = default) => Column_NorthSouth.ElementAtOrDefault(index, @default); + public Double[] Column_EastWest { get; } + public Double GetEastWest(int index, Double @default = default) => Column_EastWest.ElementAtOrDefault(index, @default); + public Double[] Column_Elevation { get; } + public Double GetElevation(int index, Double @default = default) => Column_Elevation.ElementAtOrDefault(index, @default); + public Double[] Column_AngleToTrueNorth { get; } + public Double GetAngleToTrueNorth(int index, Double @default = default) => Column_AngleToTrueNorth.ElementAtOrDefault(index, @default); public Double[] Column_Position_X { get; } public Double GetPosition_X(int index, Double @default = default) => Column_Position_X.ElementAtOrDefault(index, @default); public Double[] Column_Position_Y { get; } @@ -7362,6 +7429,11 @@ public BasePoint Get(int index) var r = new BasePoint(); r.Index = index; r.IsSurveyPoint = GetIsSurveyPoint(index); + r.IsClipped = GetIsClipped(index); + r.NorthSouth = GetNorthSouth(index); + r.EastWest = GetEastWest(index); + r.Elevation = GetElevation(index); + r.AngleToTrueNorth = GetAngleToTrueNorth(index); r.Position_X = GetPosition_X(index); r.Position_Y = GetPosition_Y(index); r.Position_Z = GetPosition_Z(index); @@ -8213,6 +8285,21 @@ public static EntityTableBuilder ToElementTableBuilder(this EntitySetBuilder getIsPinned(elementIndex: number): Promise getAllIsPinned(): Promise + getCreator(elementIndex: number): Promise + getAllCreator(): Promise + getLastChangedBy(elementIndex: number): Promise + getAllLastChangedBy(): Promise + getOwner(elementIndex: number): Promise + getAllOwner(): Promise getLevelIndex(elementIndex: number): Promise getAllLevelIndex(): Promise @@ -715,6 +724,9 @@ export class Element implements IElement { location_Z?: number familyName?: string isPinned?: boolean + creator?: string + lastChangedBy?: string + owner?: string levelIndex?: number level?: ILevel @@ -753,6 +765,9 @@ export class Element implements IElement { table.getLocation_Z(index).then(v => result.location_Z = v), table.getFamilyName(index).then(v => result.familyName = v), table.getIsPinned(index).then(v => result.isPinned = v), + table.getCreator(index).then(v => result.creator = v), + table.getLastChangedBy(index).then(v => result.lastChangedBy = v), + table.getOwner(index).then(v => result.owner = v), table.getLevelIndex(index).then(v => result.levelIndex = v), table.getPhaseCreatedIndex(index).then(v => result.phaseCreatedIndex = v), table.getPhaseDemolishedIndex(index).then(v => result.phaseDemolishedIndex = v), @@ -808,6 +823,9 @@ export class ElementTable implements IElementTable { let location_Z: number[] | undefined let familyName: string[] | undefined let isPinned: boolean[] | undefined + let creator: string[] | undefined + let lastChangedBy: string[] | undefined + let owner: string[] | undefined let levelIndex: number[] | undefined let phaseCreatedIndex: number[] | undefined let phaseDemolishedIndex: number[] | undefined @@ -830,6 +848,9 @@ export class ElementTable implements IElementTable { (async () => { location_Z = (await localTable.getNumberArray("float:Location.Z")) })(), (async () => { familyName = (await localTable.getStringArray("string:FamilyName")) })(), (async () => { isPinned = (await localTable.getBooleanArray("byte:IsPinned")) })(), + (async () => { creator = (await localTable.getStringArray("string:Creator")) })(), + (async () => { lastChangedBy = (await localTable.getStringArray("string:LastChangedBy")) })(), + (async () => { owner = (await localTable.getStringArray("string:Owner")) })(), (async () => { levelIndex = (await localTable.getNumberArray("index:Vim.Level:Level")) })(), (async () => { phaseCreatedIndex = (await localTable.getNumberArray("index:Vim.Phase:PhaseCreated")) })(), (async () => { phaseDemolishedIndex = (await localTable.getNumberArray("index:Vim.Phase:PhaseDemolished")) })(), @@ -858,6 +879,9 @@ export class ElementTable implements IElementTable { location_Z: location_Z ? location_Z[i] : undefined, familyName: familyName ? familyName[i] : undefined, isPinned: isPinned ? isPinned[i] : undefined, + creator: creator ? creator[i] : undefined, + lastChangedBy: lastChangedBy ? lastChangedBy[i] : undefined, + owner: owner ? owner[i] : undefined, levelIndex: levelIndex ? levelIndex[i] : undefined, phaseCreatedIndex: phaseCreatedIndex ? phaseCreatedIndex[i] : undefined, phaseDemolishedIndex: phaseDemolishedIndex ? phaseDemolishedIndex[i] : undefined, @@ -947,6 +971,30 @@ export class ElementTable implements IElementTable { return (await this.entityTable.getBooleanArray("byte:IsPinned")) } + async getCreator(elementIndex: number): Promise { + return (await this.entityTable.getString(elementIndex, "string:Creator")) + } + + async getAllCreator(): Promise { + return (await this.entityTable.getStringArray("string:Creator")) + } + + async getLastChangedBy(elementIndex: number): Promise { + return (await this.entityTable.getString(elementIndex, "string:LastChangedBy")) + } + + async getAllLastChangedBy(): Promise { + return (await this.entityTable.getStringArray("string:LastChangedBy")) + } + + async getOwner(elementIndex: number): Promise { + return (await this.entityTable.getString(elementIndex, "string:Owner")) + } + + async getAllOwner(): Promise { + return (await this.entityTable.getStringArray("string:Owner")) + } + async getLevelIndex(elementIndex: number): Promise { return await this.entityTable.getNumber(elementIndex, "index:Vim.Level:Level") } @@ -8175,6 +8223,11 @@ export class ElementInWarningTable implements IElementInWarningTable { export interface IBasePoint { index: number isSurveyPoint?: boolean + isClipped?: boolean + northSouth?: number + eastWest?: number + elevation?: number + angleToTrueNorth?: number position_X?: number position_Y?: number position_Z?: number @@ -8193,6 +8246,16 @@ export interface IBasePointTable { getIsSurveyPoint(basePointIndex: number): Promise getAllIsSurveyPoint(): Promise + getIsClipped(basePointIndex: number): Promise + getAllIsClipped(): Promise + getNorthSouth(basePointIndex: number): Promise + getAllNorthSouth(): Promise + getEastWest(basePointIndex: number): Promise + getAllEastWest(): Promise + getElevation(basePointIndex: number): Promise + getAllElevation(): Promise + getAngleToTrueNorth(basePointIndex: number): Promise + getAllAngleToTrueNorth(): Promise getPosition_X(basePointIndex: number): Promise getAllPosition_X(): Promise getPosition_Y(basePointIndex: number): Promise @@ -8214,6 +8277,11 @@ export interface IBasePointTable { export class BasePoint implements IBasePoint { index: number isSurveyPoint?: boolean + isClipped?: boolean + northSouth?: number + eastWest?: number + elevation?: number + angleToTrueNorth?: number position_X?: number position_Y?: number position_Z?: number @@ -8230,6 +8298,11 @@ export class BasePoint implements IBasePoint { await Promise.all([ table.getIsSurveyPoint(index).then(v => result.isSurveyPoint = v), + table.getIsClipped(index).then(v => result.isClipped = v), + table.getNorthSouth(index).then(v => result.northSouth = v), + table.getEastWest(index).then(v => result.eastWest = v), + table.getElevation(index).then(v => result.elevation = v), + table.getAngleToTrueNorth(index).then(v => result.angleToTrueNorth = v), table.getPosition_X(index).then(v => result.position_X = v), table.getPosition_Y(index).then(v => result.position_Y = v), table.getPosition_Z(index).then(v => result.position_Z = v), @@ -8273,6 +8346,11 @@ export class BasePointTable implements IBasePointTable { const localTable = await this.entityTable.getLocal() let isSurveyPoint: boolean[] | undefined + let isClipped: boolean[] | undefined + let northSouth: number[] | undefined + let eastWest: number[] | undefined + let elevation: number[] | undefined + let angleToTrueNorth: number[] | undefined let position_X: number[] | undefined let position_Y: number[] | undefined let position_Z: number[] | undefined @@ -8283,6 +8361,11 @@ export class BasePointTable implements IBasePointTable { await Promise.all([ (async () => { isSurveyPoint = (await localTable.getBooleanArray("byte:IsSurveyPoint")) })(), + (async () => { isClipped = (await localTable.getBooleanArray("byte:IsClipped")) })(), + (async () => { northSouth = (await localTable.getNumberArray("double:NorthSouth")) })(), + (async () => { eastWest = (await localTable.getNumberArray("double:EastWest")) })(), + (async () => { elevation = (await localTable.getNumberArray("double:Elevation")) })(), + (async () => { angleToTrueNorth = (await localTable.getNumberArray("double:AngleToTrueNorth")) })(), (async () => { position_X = (await localTable.getNumberArray("double:Position.X")) })(), (async () => { position_Y = (await localTable.getNumberArray("double:Position.Y")) })(), (async () => { position_Z = (await localTable.getNumberArray("double:Position.Z")) })(), @@ -8299,6 +8382,11 @@ export class BasePointTable implements IBasePointTable { basePoint.push({ index: i, isSurveyPoint: isSurveyPoint ? isSurveyPoint[i] : undefined, + isClipped: isClipped ? isClipped[i] : undefined, + northSouth: northSouth ? northSouth[i] : undefined, + eastWest: eastWest ? eastWest[i] : undefined, + elevation: elevation ? elevation[i] : undefined, + angleToTrueNorth: angleToTrueNorth ? angleToTrueNorth[i] : undefined, position_X: position_X ? position_X[i] : undefined, position_Y: position_Y ? position_Y[i] : undefined, position_Z: position_Z ? position_Z[i] : undefined, @@ -8320,6 +8408,46 @@ export class BasePointTable implements IBasePointTable { return (await this.entityTable.getBooleanArray("byte:IsSurveyPoint")) } + async getIsClipped(basePointIndex: number): Promise { + return (await this.entityTable.getBoolean(basePointIndex, "byte:IsClipped")) + } + + async getAllIsClipped(): Promise { + return (await this.entityTable.getBooleanArray("byte:IsClipped")) + } + + async getNorthSouth(basePointIndex: number): Promise { + return (await this.entityTable.getNumber(basePointIndex, "double:NorthSouth")) + } + + async getAllNorthSouth(): Promise { + return (await this.entityTable.getNumberArray("double:NorthSouth")) + } + + async getEastWest(basePointIndex: number): Promise { + return (await this.entityTable.getNumber(basePointIndex, "double:EastWest")) + } + + async getAllEastWest(): Promise { + return (await this.entityTable.getNumberArray("double:EastWest")) + } + + async getElevation(basePointIndex: number): Promise { + return (await this.entityTable.getNumber(basePointIndex, "double:Elevation")) + } + + async getAllElevation(): Promise { + return (await this.entityTable.getNumberArray("double:Elevation")) + } + + async getAngleToTrueNorth(basePointIndex: number): Promise { + return (await this.entityTable.getNumber(basePointIndex, "double:AngleToTrueNorth")) + } + + async getAllAngleToTrueNorth(): Promise { + return (await this.entityTable.getNumberArray("double:AngleToTrueNorth")) + } + async getPosition_X(basePointIndex: number): Promise { return (await this.entityTable.getNumber(basePointIndex, "double:Position.X")) }