From ca73f3e3ad51fb389b0ca615d5635db02aa02a65 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 30 Mar 2020 21:17:08 +0200 Subject: [PATCH] Synthesis of Technic Universal Joints (#456) * Split synth info initialzation by type. We are going to remove the type enumeration and use a class hierarchy instead. This preparation will then be helpful. * Make Add...Parts() overrides of a virtual AddPart() function. Since we have a class hierarchy for the different synthesized pieces, we can now turn a case distinction into a virtual function call. * Move initialization based on type to derived class constructors. Move initialization of end transformations of flexible parts into class lcSynthInfoCurved. * Make GetDefaultControlPoints() virtual with overrides. * Remove obsolete enum lcSynthType. We have replaced its purpose by derived classes by now. * Initialize shock absorbers' spring part ID early. This removes the awkward early return that is needed in the if-else cascade. * Split lcSynthInfo into derived classes for curved and straight pieces. * Only curved parts have varying sections, start, middle, and end properties. Move the properties from the base class to the derived class that needs them. * Use derived classes to mark synthesized objects of different kinds. We will extend the derived classes in the upcoming commits. * PieceInfo is only needed to synthesize some hoses and shock absorbers. * Initialize edge part IDs of flexible hoses early. This removes another case distinction in AddParts(). * Verify the number of control points loaded from a model file. * Synthesize Technic universal joints. The direction of one end can be changed so that it points to the control point. * Technic universal joints need only the position of the control point. * Synthesize legacy universal joints. --- common/lc_model.cpp | 1 + common/lc_synth.cpp | 990 ++++++++++++++++++++++++++++++-------------- common/lc_synth.h | 57 +-- common/piece.cpp | 38 +- common/piece.h | 8 +- 5 files changed, 729 insertions(+), 365 deletions(-) diff --git a/common/lc_model.cpp b/common/lc_model.cpp index 5409b46d..35d965bc 100644 --- a/common/lc_model.cpp +++ b/common/lc_model.cpp @@ -684,6 +684,7 @@ void lcModel::LoadLDraw(QIODevice& Device, Project* Project) Piece->SetPieceInfo(Info, PartId, false); Piece->Initialize(Transform, CurrentStep); Piece->SetColorCode(ColorCode); + Piece->VerifyControlPoints(ControlPoints); Piece->SetControlPoints(ControlPoints); AddPiece(Piece); Piece = nullptr; diff --git a/common/lc_synth.cpp b/common/lc_synth.cpp index 53395dfe..9caf93c7 100644 --- a/common/lc_synth.cpp +++ b/common/lc_synth.cpp @@ -7,247 +7,518 @@ #include "pieceinf.h" #include +class lcSynthInfoCurved : public lcSynthInfo +{ +public: + lcSynthInfoCurved(float Length, float DefaultScale, int NumSections, bool RigidEdges); + + void GetDefaultControlPoints(lcArray& ControlPoints) const override; + void VerifyControlPoints(lcArray& ControlPoints) const override; + +protected: + float GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const; + void CalculateSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const override; + + struct lcSynthComponent + { + lcMatrix44 Transform; + float Length; + }; + + lcSynthComponent mStart; + lcSynthComponent mMiddle; + lcSynthComponent mEnd; + float mCenterLength = 0.0f; + int mNumSections; + float mDefaultScale; + bool mRigidEdges; +}; + +class lcSynthInfoFlexibleHose : public lcSynthInfoCurved +{ +public: + lcSynthInfoFlexibleHose(float Length, int NumSections, const char* EdgePart2); + +protected: + void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const override; + + const char* mEdgePart2; +}; + +class lcSynthInfoFlexSystemHose : public lcSynthInfoCurved +{ +public: + lcSynthInfoFlexSystemHose(float Length, int NumSections); + + void GetDefaultControlPoints(lcArray& ControlPoints) const override; + +protected: + void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const override; +}; + +class lcSynthInfoRibbedHose : public lcSynthInfoCurved +{ +public: + lcSynthInfoRibbedHose(float Length, int NumSections); + +protected: + void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const override; +}; + +class lcSynthInfoFlexibleAxle : public lcSynthInfoCurved +{ +public: + lcSynthInfoFlexibleAxle(float Length, int NumSections); + +protected: + void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const override; +}; + +class lcSynthInfoBraidedString : public lcSynthInfoCurved +{ +public: + lcSynthInfoBraidedString(float Length, int NumSections); + +protected: + void CalculateSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const; + void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const override; +}; + +class lcSynthInfoStraight : public lcSynthInfo +{ +public: + explicit lcSynthInfoStraight(float Length); + + void VerifyControlPoints(lcArray& ControlPoints) const override; + +protected: + void CalculateSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const override; +}; + +class lcSynthInfoShockAbsorber : public lcSynthInfoStraight +{ +public: + explicit lcSynthInfoShockAbsorber(const char* SpringPart); + + void GetDefaultControlPoints(lcArray& ControlPoints) const override; + +protected: + void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const override; + + const char* mSpringPart; +}; + +class lcSynthInfoActuator : public lcSynthInfoStraight +{ +public: + explicit lcSynthInfoActuator(float Length); + + void GetDefaultControlPoints(lcArray& ControlPoints) const override; + +protected: + void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const override; +}; + +class lcSynthInfoUniversalJoint : public lcSynthInfo +{ +public: + lcSynthInfoUniversalJoint(float Length, float EndOffset, const char* EndPart, const char* CenterPart); + + void GetDefaultControlPoints(lcArray& ControlPoints) const override; + void VerifyControlPoints(lcArray& ControlPoints) const override; + +protected: + void CalculateSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const override; + void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const override; + + float mEndOffset; + const char* mEndPart; + const char* mCenterPart; +}; + void lcSynthInit() { lcPiecesLibrary* Library = lcGetPiecesLibrary(); - struct lcHoseInfo + static const struct { - const char* PartID; - lcSynthType Type; + char PartID[16]; float Length; int NumSections; + char EdgePart2[8]; + } + FlexibleHoses[] = + { + { "73590a.dat", 140.0f, 51, "752.dat" }, // Hose Flexible 8.5L without Tabs + { "73590b.dat", 140.0f, 51, "750.dat" }, // Hose Flexible 8.5L with Tabs }; - lcHoseInfo HoseInfo[] = + for (const auto& HoseInfo: FlexibleHoses) { - { "73590a.dat", lcSynthType::HOSE_FLEXIBLE, 140.0f, 51 }, // Hose Flexible 8.5L without Tabs - { "73590b.dat", lcSynthType::HOSE_FLEXIBLE, 140.0f, 51 }, // Hose Flexible 8.5L with Tabs - { "76263.dat", lcSynthType::FLEX_SYSTEM_HOSE, 60.0f, 29 }, // Technic Flex-System Hose 3L (60LDU) - { "76250.dat", lcSynthType::FLEX_SYSTEM_HOSE, 80.0f, 39 }, // Technic Flex-System Hose 4L (80LDU) - { "76307.dat", lcSynthType::FLEX_SYSTEM_HOSE, 100.0f, 49 }, // Technic Flex-System Hose 5L (100LDU) - { "76279.dat", lcSynthType::FLEX_SYSTEM_HOSE, 120.0f, 59 }, // Technic Flex-System Hose 6L (120LDU) - { "76289.dat", lcSynthType::FLEX_SYSTEM_HOSE, 140.0f, 69 }, // Technic Flex-System Hose 7L (140LDU) - { "76260.dat", lcSynthType::FLEX_SYSTEM_HOSE, 160.0f, 79 }, // Technic Flex-System Hose 8L (160LDU) - { "76324.dat", lcSynthType::FLEX_SYSTEM_HOSE, 180.0f, 89 }, // Technic Flex-System Hose 9L (180LDU) - { "76348.dat", lcSynthType::FLEX_SYSTEM_HOSE, 200.0f, 99 }, // Technic Flex-System Hose 10L (200LDU) - { "71505.dat", lcSynthType::FLEX_SYSTEM_HOSE, 220.0f, 109 }, // Technic Flex-System Hose 11L (220LDU) - { "71175.dat", lcSynthType::FLEX_SYSTEM_HOSE, 240.0f, 119 }, // Technic Flex-System Hose 12L (240LDU) - { "71551.dat", lcSynthType::FLEX_SYSTEM_HOSE, 260.0f, 129 }, // Technic Flex-System Hose 13L (260LDU) - { "71177.dat", lcSynthType::FLEX_SYSTEM_HOSE, 280.0f, 139 }, // Technic Flex-System Hose 14L (280LDU) - { "71194.dat", lcSynthType::FLEX_SYSTEM_HOSE, 300.0f, 149 }, // Technic Flex-System Hose 15L (300LDU) - { "71192.dat", lcSynthType::FLEX_SYSTEM_HOSE, 320.0f, 159 }, // Technic Flex-System Hose 16L (320LDU) - { "76270.dat", lcSynthType::FLEX_SYSTEM_HOSE, 340.0f, 169 }, // Technic Flex-System Hose 17L (340LDU) - { "71582.dat", lcSynthType::FLEX_SYSTEM_HOSE, 360.0f, 179 }, // Technic Flex-System Hose 18L (360LDU) - { "22463.dat", lcSynthType::FLEX_SYSTEM_HOSE, 380.0f, 189 }, // Technic Flex-System Hose 19L (380LDU) - { "76276.dat", lcSynthType::FLEX_SYSTEM_HOSE, 400.0f, 199 }, // Technic Flex-System Hose 20L (400LDU) - { "70978.dat", lcSynthType::FLEX_SYSTEM_HOSE, 420.0f, 209 }, // Technic Flex-System Hose 21L (420LDU) - { "76252.dat", lcSynthType::FLEX_SYSTEM_HOSE, 440.0f, 219 }, // Technic Flex-System Hose 22L (440LDU) - { "76254.dat", lcSynthType::FLEX_SYSTEM_HOSE, 460.0f, 229 }, // Technic Flex-System Hose 23L (460LDU) - { "76277.dat", lcSynthType::FLEX_SYSTEM_HOSE, 480.0f, 239 }, // Technic Flex-System Hose 24L (480LDU) - { "53475.dat", lcSynthType::FLEX_SYSTEM_HOSE, 520.0f, 259 }, // Technic Flex-System Hose 26L (520LDU) - { "76280.dat", lcSynthType::FLEX_SYSTEM_HOSE, 560.0f, 279 }, // Technic Flex-System Hose 28L (560LDU) - { "76389.dat", lcSynthType::FLEX_SYSTEM_HOSE, 580.0f, 289 }, // Technic Flex-System Hose 29L (580LDU) - { "76282.dat", lcSynthType::FLEX_SYSTEM_HOSE, 600.0f, 299 }, // Technic Flex-System Hose 30L (600LDU) - { "76283.dat", lcSynthType::FLEX_SYSTEM_HOSE, 620.0f, 309 }, // Technic Flex-System Hose 31L (620LDU) - { "57274.dat", lcSynthType::FLEX_SYSTEM_HOSE, 640.0f, 319 }, // Technic Flex-System Hose 32L (640LDU) - { "42688.dat", lcSynthType::FLEX_SYSTEM_HOSE, 660.0f, 329 }, // Technic Flex-System Hose 33L (660LDU) - { "22461.dat", lcSynthType::FLEX_SYSTEM_HOSE, 680.0f, 339 }, // Technic Flex-System Hose 34L (680LDU) - { "46305.dat", lcSynthType::FLEX_SYSTEM_HOSE, 800.0f, 399 }, // Technic Flex-System Hose 40L (800LDU) - { "76281.dat", lcSynthType::FLEX_SYSTEM_HOSE, 900.0f, 449 }, // Technic Flex-System Hose 45L (900LDU) - { "22296.dat", lcSynthType::FLEX_SYSTEM_HOSE, 1060.0f, 529 }, // Technic Flex-System Hose 53L (1060LDU) - { "72504.dat", lcSynthType::RIBBED_HOSE, 31.25f, 4 }, // Technic Ribbed Hose 2L - { "72706.dat", lcSynthType::RIBBED_HOSE, 50.00f, 7 }, // Technic Ribbed Hose 3L - { "71952.dat", lcSynthType::RIBBED_HOSE, 75.00f, 11 }, // Technic Ribbed Hose 4L - { "72853.dat", lcSynthType::RIBBED_HOSE, 93.75f, 14 }, // Technic Ribbed Hose 5L - { "71944.dat", lcSynthType::RIBBED_HOSE, 112.50f, 17 }, // Technic Ribbed Hose 6L - { "57719.dat", lcSynthType::RIBBED_HOSE, 131.25f, 20 }, // Technic Ribbed Hose 7L - { "71951.dat", lcSynthType::RIBBED_HOSE, 150.00f, 23 }, // Technic Ribbed Hose 8L - { "71917.dat", lcSynthType::RIBBED_HOSE, 175.00f, 27 }, // Technic Ribbed Hose 9L - { "71949.dat", lcSynthType::RIBBED_HOSE, 193.75f, 30 }, // Technic Ribbed Hose 10L - { "71986.dat", lcSynthType::RIBBED_HOSE, 212.50f, 33 }, // Technic Ribbed Hose 11L - { "71819.dat", lcSynthType::RIBBED_HOSE, 231.25f, 36 }, // Technic Ribbed Hose 12L - { "71923.dat", lcSynthType::RIBBED_HOSE, 275.00f, 43 }, // Technic Ribbed Hose 14L - { "71946.dat", lcSynthType::RIBBED_HOSE, 293.75f, 46 }, // Technic Ribbed Hose 15L - { "71947.dat", lcSynthType::RIBBED_HOSE, 312.50f, 49 }, // Technic Ribbed Hose 16L - { "22900.dat", lcSynthType::RIBBED_HOSE, 331.25f, 52 }, // Technic Ribbed Hose 17L - { "72039.dat", lcSynthType::RIBBED_HOSE, 350.00f, 55 }, // Technic Ribbed Hose 18L - { "43675.dat", lcSynthType::RIBBED_HOSE, 375.00f, 58 }, // Technic Ribbed Hose 19L - { "23397.dat", lcSynthType::RIBBED_HOSE, 468.75f, 74 }, // Technic Ribbed Hose 24L - { "33763.dat", lcSynthType::RIBBED_HOSE, 512.50f, 81 }, // Technic Ribbed Hose 26L - { "32580.dat", lcSynthType::FLEXIBLE_AXLE, 120.00f, 15 }, // Technic Axle Flexible 7 - { "32199.dat", lcSynthType::FLEXIBLE_AXLE, 200.00f, 35 }, // Technic Axle Flexible 11 - { "55709.dat", lcSynthType::FLEXIBLE_AXLE, 200.00f, 35 }, // Technic Axle Flexible 11 - { "32200.dat", lcSynthType::FLEXIBLE_AXLE, 220.00f, 40 }, // Technic Axle Flexible 12 - { "32201.dat", lcSynthType::FLEXIBLE_AXLE, 260.00f, 50 }, // Technic Axle Flexible 14 - { "32202.dat", lcSynthType::FLEXIBLE_AXLE, 300.00f, 60 }, // Technic Axle Flexible 16 - { "32235.dat", lcSynthType::FLEXIBLE_AXLE, 360.00f, 75 }, // Technic Axle Flexible 19 - { "76384.dat", lcSynthType::STRING_BRAIDED, 200.00f, 46 }, // String Braided 11L with End Studs - { "75924.dat", lcSynthType::STRING_BRAIDED, 400.00f, 96 }, // String Braided 21L with End Studs - { "572C02.dat", lcSynthType::STRING_BRAIDED, 800.00f, 196 }, // String Braided 41L with End Studs - { "73129.dat", lcSynthType::SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L - { "41838.dat", lcSynthType::SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L Soft - { "76138.dat", lcSynthType::SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L Stiff - { "76537.dat", lcSynthType::SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L Extra Stiff - { "61927C01.dat", lcSynthType::ACTUATOR, 270.00f, 1 }, // Technic Power Functions Linear Actuator (Extended) - { "61927.dat", lcSynthType::ACTUATOR, 170.00f, 1 } // Technic Power Functions Linear Actuator (Contracted) - }; - - for (unsigned int InfoIdx = 0; InfoIdx < LC_ARRAY_COUNT(HoseInfo); InfoIdx++) - { - PieceInfo* Info = Library->FindPiece(HoseInfo[InfoIdx].PartID, nullptr, false, false); + PieceInfo* Info = Library->FindPiece(HoseInfo.PartID, nullptr, false, false); if (Info) - Info->SetSynthInfo(new lcSynthInfo(HoseInfo[InfoIdx].Type, HoseInfo[InfoIdx].Length, HoseInfo[InfoIdx].NumSections, Info)); + Info->SetSynthInfo(new lcSynthInfoFlexibleHose(HoseInfo.Length, HoseInfo.NumSections, HoseInfo.EdgePart2)); + } + + static const struct + { + char PartID[16]; + float Length; + int NumSections; + } + FlexSystemHoses[] = + { + { "76263.dat", 60.0f, 29 }, // Technic Flex-System Hose 3L (60LDU) + { "76250.dat", 80.0f, 39 }, // Technic Flex-System Hose 4L (80LDU) + { "76307.dat", 100.0f, 49 }, // Technic Flex-System Hose 5L (100LDU) + { "76279.dat", 120.0f, 59 }, // Technic Flex-System Hose 6L (120LDU) + { "76289.dat", 140.0f, 69 }, // Technic Flex-System Hose 7L (140LDU) + { "76260.dat", 160.0f, 79 }, // Technic Flex-System Hose 8L (160LDU) + { "76324.dat", 180.0f, 89 }, // Technic Flex-System Hose 9L (180LDU) + { "76348.dat", 200.0f, 99 }, // Technic Flex-System Hose 10L (200LDU) + { "71505.dat", 220.0f, 109 }, // Technic Flex-System Hose 11L (220LDU) + { "71175.dat", 240.0f, 119 }, // Technic Flex-System Hose 12L (240LDU) + { "71551.dat", 260.0f, 129 }, // Technic Flex-System Hose 13L (260LDU) + { "71177.dat", 280.0f, 139 }, // Technic Flex-System Hose 14L (280LDU) + { "71194.dat", 300.0f, 149 }, // Technic Flex-System Hose 15L (300LDU) + { "71192.dat", 320.0f, 159 }, // Technic Flex-System Hose 16L (320LDU) + { "76270.dat", 340.0f, 169 }, // Technic Flex-System Hose 17L (340LDU) + { "71582.dat", 360.0f, 179 }, // Technic Flex-System Hose 18L (360LDU) + { "22463.dat", 380.0f, 189 }, // Technic Flex-System Hose 19L (380LDU) + { "76276.dat", 400.0f, 199 }, // Technic Flex-System Hose 20L (400LDU) + { "70978.dat", 420.0f, 209 }, // Technic Flex-System Hose 21L (420LDU) + { "76252.dat", 440.0f, 219 }, // Technic Flex-System Hose 22L (440LDU) + { "76254.dat", 460.0f, 229 }, // Technic Flex-System Hose 23L (460LDU) + { "76277.dat", 480.0f, 239 }, // Technic Flex-System Hose 24L (480LDU) + { "53475.dat", 520.0f, 259 }, // Technic Flex-System Hose 26L (520LDU) + { "76280.dat", 560.0f, 279 }, // Technic Flex-System Hose 28L (560LDU) + { "76389.dat", 580.0f, 289 }, // Technic Flex-System Hose 29L (580LDU) + { "76282.dat", 600.0f, 299 }, // Technic Flex-System Hose 30L (600LDU) + { "76283.dat", 620.0f, 309 }, // Technic Flex-System Hose 31L (620LDU) + { "57274.dat", 640.0f, 319 }, // Technic Flex-System Hose 32L (640LDU) + { "42688.dat", 660.0f, 329 }, // Technic Flex-System Hose 33L (660LDU) + { "22461.dat", 680.0f, 339 }, // Technic Flex-System Hose 34L (680LDU) + { "46305.dat", 800.0f, 399 }, // Technic Flex-System Hose 40L (800LDU) + { "76281.dat", 900.0f, 449 }, // Technic Flex-System Hose 45L (900LDU) + { "22296.dat", 1060.0f, 529 }, // Technic Flex-System Hose 53L (1060LDU) + }; + + for (const auto& HoseInfo: FlexSystemHoses) + { + PieceInfo* Info = Library->FindPiece(HoseInfo.PartID, nullptr, false, false); + + if (Info) + Info->SetSynthInfo(new lcSynthInfoFlexSystemHose(HoseInfo.Length, HoseInfo.NumSections)); + } + + static const struct + { + char PartID[16]; + float Length; + int NumSections; + } + RibbedHoses[] = + { + { "72504.dat", 31.25f, 4 }, // Technic Ribbed Hose 2L + { "72706.dat", 50.00f, 7 }, // Technic Ribbed Hose 3L + { "71952.dat", 75.00f, 11 }, // Technic Ribbed Hose 4L + { "72853.dat", 93.75f, 14 }, // Technic Ribbed Hose 5L + { "71944.dat", 112.50f, 17 }, // Technic Ribbed Hose 6L + { "57719.dat", 131.25f, 20 }, // Technic Ribbed Hose 7L + { "71951.dat", 150.00f, 23 }, // Technic Ribbed Hose 8L + { "71917.dat", 175.00f, 27 }, // Technic Ribbed Hose 9L + { "71949.dat", 193.75f, 30 }, // Technic Ribbed Hose 10L + { "71986.dat", 212.50f, 33 }, // Technic Ribbed Hose 11L + { "71819.dat", 231.25f, 36 }, // Technic Ribbed Hose 12L + { "71923.dat", 275.00f, 43 }, // Technic Ribbed Hose 14L + { "71946.dat", 293.75f, 46 }, // Technic Ribbed Hose 15L + { "71947.dat", 312.50f, 49 }, // Technic Ribbed Hose 16L + { "22900.dat", 331.25f, 52 }, // Technic Ribbed Hose 17L + { "72039.dat", 350.00f, 55 }, // Technic Ribbed Hose 18L + { "43675.dat", 375.00f, 58 }, // Technic Ribbed Hose 19L + { "23397.dat", 468.75f, 74 }, // Technic Ribbed Hose 24L + { "33763.dat", 512.50f, 81 }, // Technic Ribbed Hose 26L + }; + + for (const auto& HoseInfo: RibbedHoses) + { + PieceInfo* Info = Library->FindPiece(HoseInfo.PartID, nullptr, false, false); + + if (Info) + Info->SetSynthInfo(new lcSynthInfoRibbedHose(HoseInfo.Length, HoseInfo.NumSections)); + } + + static const struct + { + char PartID[16]; + float Length; + int NumSections; + } + FlexibleAxles[] = + { + { "32580.dat", 120.00f, 15 }, // Technic Axle Flexible 7 + { "32199.dat", 200.00f, 35 }, // Technic Axle Flexible 11 + { "55709.dat", 200.00f, 35 }, // Technic Axle Flexible 11 + { "32200.dat", 220.00f, 40 }, // Technic Axle Flexible 12 + { "32201.dat", 260.00f, 50 }, // Technic Axle Flexible 14 + { "32202.dat", 300.00f, 60 }, // Technic Axle Flexible 16 + { "32235.dat", 360.00f, 75 }, // Technic Axle Flexible 19 + }; + + for (const auto& AxleInfo: FlexibleAxles) + { + PieceInfo* Info = Library->FindPiece(AxleInfo.PartID, nullptr, false, false); + + if (Info) + Info->SetSynthInfo(new lcSynthInfoFlexibleAxle(AxleInfo.Length, AxleInfo.NumSections)); + } + + static const struct + { + char PartID[16]; + float Length; + int NumSections; + } + BraidedStrings[] = + { + { "76384.dat", 200.00f, 46 }, // String Braided 11L with End Studs + { "75924.dat", 400.00f, 96 }, // String Braided 21L with End Studs + { "572C02.dat", 800.00f, 196 }, // String Braided 41L with End Studs + }; + + for (const auto& StringInfo: BraidedStrings) + { + PieceInfo* Info = Library->FindPiece(StringInfo.PartID, nullptr, false, false); + + if (Info) + Info->SetSynthInfo(new lcSynthInfoBraidedString(StringInfo.Length, StringInfo.NumSections)); + } + + static const struct + { + char PartID[16]; + char SpringPart[16]; + } + ShockAbsorbers[] = + { + { "73129.dat", "70038.dat" }, // Technic Shock Absorber 6.5L + { "41838.dat", "41837.dat" }, // Technic Shock Absorber 6.5L Soft + { "76138.dat", "71953.dat" }, // Technic Shock Absorber 6.5L Stiff + { "76537.dat", "22977.dat" }, // Technic Shock Absorber 6.5L Extra Stiff + }; + + for (const auto& AbsorberInfo: ShockAbsorbers) + { + PieceInfo* Info = Library->FindPiece(AbsorberInfo.PartID, nullptr, false, false); + + if (Info) + Info->SetSynthInfo(new lcSynthInfoShockAbsorber(AbsorberInfo.SpringPart)); + } + + static const struct + { + char PartID[16]; + float Length; + } + Actuators[] = + { + { "61927C01.dat", 270.00f }, // Technic Power Functions Linear Actuator (Extended) + { "61927.dat", 170.00f } // Technic Power Functions Linear Actuator (Contracted) + }; + + for (const auto& ActuatorInfo: Actuators) + { + PieceInfo* Info = Library->FindPiece(ActuatorInfo.PartID, nullptr, false, false); + + if (Info) + Info->SetSynthInfo(new lcSynthInfoActuator(ActuatorInfo.Length)); + } + + static const struct + { + char PartID[16]; + float Length; + float EndOffset; + char EndPart[16]; + char CenterPart[16]; + } + UniversalJoints[] = + { + { "61903.dat", 60.00f, 0.0f, "62520.dat", "62519.dat" }, // Technic Universal Joint 3L + { "3712C01.dat", 60.00f, 30.0f, "3712.dat", "3326.dat" }, // Technic Universal Joint + { "575C01.dat", 60.00f, 30.0f, "575.dat", "3326a.dat" } // Technic Universal Joint Type 1 + }; + + for (const auto& JointInfo: UniversalJoints) + { + PieceInfo* Info = Library->FindPiece(JointInfo.PartID, nullptr, false, false); + + if (Info) + Info->SetSynthInfo(new lcSynthInfoUniversalJoint(JointInfo.Length, JointInfo.EndOffset, JointInfo.EndPart, JointInfo.CenterPart)); } // "758C01" // Hose Flexible 12L } -lcSynthInfo::lcSynthInfo(lcSynthType Type, float Length, int NumSections, PieceInfo* Info) - : mPieceInfo(Info), mType(Type), mLength(Length), mNumSections(NumSections) +lcSynthInfo::lcSynthInfo(float Length) + : mLength(Length) { - float EdgeSectionLength = 0.0f; - float MidSectionLength = 0.0f; - mCenterLength = 0.0f; - - switch (mType) - { - case lcSynthType::HOSE_FLEXIBLE: - EdgeSectionLength = 5.0f; - MidSectionLength = 2.56f; - mCenterLength = 4.56f; - mRigidEdges = true; - mCurve = true; - break; - - case lcSynthType::FLEX_SYSTEM_HOSE: - EdgeSectionLength = 1.0f; - MidSectionLength = 2.0f; - mRigidEdges = true; - mCurve = true; - break; - - case lcSynthType::RIBBED_HOSE: - EdgeSectionLength = 6.25f; - MidSectionLength = 6.25f; - mRigidEdges = false; - mCurve = true; - break; - - case lcSynthType::FLEXIBLE_AXLE: - EdgeSectionLength = 30.0f; - MidSectionLength = 4.0f; - mRigidEdges = true; - mCurve = true; - break; - - case lcSynthType::STRING_BRAIDED: - EdgeSectionLength = 8.0f; - MidSectionLength = 4.0f; - mRigidEdges = true; - mCurve = true; - break; - - case lcSynthType::SHOCK_ABSORBER: - case lcSynthType::ACTUATOR: - EdgeSectionLength = 0.0f; - MidSectionLength = 0.0f; - mRigidEdges = false; - mCurve = false; - break; - } - - switch (mType) - { - case lcSynthType::HOSE_FLEXIBLE: - case lcSynthType::RIBBED_HOSE: - case lcSynthType::FLEXIBLE_AXLE: - mStart.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); - mMiddle.Transform = lcMatrix44Identity(); - mEnd.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); - break; - - case lcSynthType::FLEX_SYSTEM_HOSE: - case lcSynthType::SHOCK_ABSORBER: - case lcSynthType::ACTUATOR: - case lcSynthType::STRING_BRAIDED: - mStart.Transform = lcMatrix44Identity(); - mMiddle.Transform = lcMatrix44Identity(); - mEnd.Transform = lcMatrix44Identity(); - break; - } - - mStart.Length = EdgeSectionLength; - mMiddle.Length = MidSectionLength; - mEnd.Length = EdgeSectionLength; } -void lcSynthInfo::GetDefaultControlPoints(lcArray& ControlPoints) const +lcSynthInfoCurved::lcSynthInfoCurved(float Length, float DefaultScale, int NumSections, bool RigidEdges) + : lcSynthInfo(Length), mNumSections(NumSections), mDefaultScale(DefaultScale), mRigidEdges(RigidEdges) +{ + mCurve = true; + + mStart.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); + mEnd.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); +} + +lcSynthInfoFlexibleHose::lcSynthInfoFlexibleHose(float Length, int NumSections, const char* EdgePart2) + : lcSynthInfoCurved(Length, 12.f, NumSections, true), + mEdgePart2(EdgePart2) +{ + mStart.Length = 5.0f; + mMiddle.Length = 2.56f; + mEnd.Length = 5.0f; + mCenterLength = 4.56f; +} + +lcSynthInfoFlexSystemHose::lcSynthInfoFlexSystemHose(float Length, int NumSections) + : lcSynthInfoCurved(Length, 12.f, NumSections, true) +{ + mStart.Transform = lcMatrix44Identity(); + mEnd.Transform = lcMatrix44Identity(); + mStart.Length = 1.0f; + mMiddle.Length = 2.0f; + mEnd.Length = 1.0f; +} + +lcSynthInfoRibbedHose::lcSynthInfoRibbedHose(float Length, int NumSections) + : lcSynthInfoCurved(Length, 80.0f, NumSections, false) +{ + mStart.Length = 6.25f; + mMiddle.Length = 6.25f; + mEnd.Length = 6.25f; +} + +lcSynthInfoFlexibleAxle::lcSynthInfoFlexibleAxle(float Length, int NumSections) + : lcSynthInfoCurved(Length, 12.0f, NumSections, true) +{ + mStart.Length = 30.0f; + mMiddle.Length = 4.0f; + mEnd.Length = 30.0f; +} + +lcSynthInfoBraidedString::lcSynthInfoBraidedString(float Length, int NumSections) + : lcSynthInfoCurved(Length, 12.0f, NumSections, true) +{ + mStart.Transform = lcMatrix44Identity(); + mEnd.Transform = lcMatrix44Identity(); + mStart.Length = 8.0f; + mMiddle.Length = 4.0f; + mEnd.Length = 8.0f; +} + +lcSynthInfoStraight::lcSynthInfoStraight(float Length) + : lcSynthInfo(Length) +{ + mUnidirectional = true; +} + +lcSynthInfoShockAbsorber::lcSynthInfoShockAbsorber(const char* SpringPart) + : lcSynthInfoStraight(110.00f), mSpringPart(SpringPart) +{ +} + +lcSynthInfoActuator::lcSynthInfoActuator(float Length) + : lcSynthInfoStraight(Length) +{ +} + +lcSynthInfoUniversalJoint::lcSynthInfoUniversalJoint(float Length, float EndOffset, const char* EndPart, const char* CenterPart) + : lcSynthInfo(Length), mEndOffset(EndOffset), mEndPart(EndPart), mCenterPart(CenterPart) +{ + mNondirectional = true; +} + +void lcSynthInfoCurved::GetDefaultControlPoints(lcArray& ControlPoints) const { ControlPoints.SetSize(2); - float Scale = 1.0f; - - switch (mType) - { - case lcSynthType::HOSE_FLEXIBLE: - Scale = 12.0f; - break; - - case lcSynthType::FLEX_SYSTEM_HOSE: - Scale = 12.0f; - break; - - case lcSynthType::RIBBED_HOSE: - Scale = 80.0f; - break; - - case lcSynthType::FLEXIBLE_AXLE: - Scale = 12.0f; - break; - - case lcSynthType::STRING_BRAIDED: - Scale = 12.0f; - break; - - case lcSynthType::SHOCK_ABSORBER: - case lcSynthType::ACTUATOR: - Scale = 1.0f; - break; - } - float HalfLength = mLength / 2.0f; - Scale = lcMin(Scale, HalfLength); + float Scale = lcMin(mDefaultScale, HalfLength); - switch (mType) - { - default: - ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(-HalfLength, 0.0f, 0.0f)); - ControlPoints[1].Transform = lcMatrix44Translation(lcVector3( HalfLength, 0.0f, 0.0f)); - break; - - case lcSynthType::FLEX_SYSTEM_HOSE: - ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -mLength)); - ControlPoints[1].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, 0.0f)); - break; - - case lcSynthType::SHOCK_ABSORBER: - ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -mLength)); - ControlPoints[1].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, 0.0f)); - break; - - case lcSynthType::ACTUATOR: - ControlPoints[0].Transform = lcMatrix44(lcMatrix33(lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); - ControlPoints[1].Transform = lcMatrix44(lcMatrix33(lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, mLength, 0.0f)); - break; - } + ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(-HalfLength, 0.0f, 0.0f)); + ControlPoints[1].Transform = lcMatrix44Translation(lcVector3( HalfLength, 0.0f, 0.0f)); ControlPoints[0].Scale = Scale; ControlPoints[1].Scale = Scale; } -float lcSynthInfo::GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const +void lcSynthInfoCurved::VerifyControlPoints(lcArray& ControlPoints) const +{ + if (ControlPoints.GetSize() < 2) + GetDefaultControlPoints(ControlPoints); +} + +void lcSynthInfoFlexSystemHose::GetDefaultControlPoints(lcArray& ControlPoints) const +{ + lcSynthInfoCurved::GetDefaultControlPoints(ControlPoints); + + ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -mLength)); + ControlPoints[1].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, 0.0f)); +} + +void lcSynthInfoStraight::VerifyControlPoints(lcArray& ControlPoints) const +{ + if (ControlPoints.GetSize() < 2) + GetDefaultControlPoints(ControlPoints); + else + ControlPoints.SetSize(2); +} + +void lcSynthInfoShockAbsorber::GetDefaultControlPoints(lcArray& ControlPoints) const +{ + ControlPoints.SetSize(2); + + ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -mLength)); + ControlPoints[1].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, 0.0f)); + + ControlPoints[0].Scale = 1.0f; + ControlPoints[1].Scale = 1.0f; +} + +void lcSynthInfoActuator::GetDefaultControlPoints(lcArray& ControlPoints) const +{ + ControlPoints.SetSize(2); + + ControlPoints[0].Transform = lcMatrix44(lcMatrix33(lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); + ControlPoints[1].Transform = lcMatrix44(lcMatrix33(lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, mLength, 0.0f)); + + ControlPoints[0].Scale = 1.0f; + ControlPoints[1].Scale = 1.0f; +} + +void lcSynthInfoUniversalJoint::GetDefaultControlPoints(lcArray& ControlPoints) const +{ + ControlPoints.SetSize(1); + float HalfLength = mLength / 2; + + ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, HalfLength, 0.0f)); + ControlPoints[0].Scale = 1.0f; +} + +void lcSynthInfoUniversalJoint::VerifyControlPoints(lcArray& ControlPoints) const +{ + if (ControlPoints.IsEmpty()) + GetDefaultControlPoints(ControlPoints); + else + ControlPoints.SetSize(1); +} + +float lcSynthInfoCurved::GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const { lcVector3 StartTangent(StartTransform[1].x, StartTransform[1].y, StartTransform[1].z); lcVector3 EndTangent(EndTransform[1].x, EndTransform[1].y, EndTransform[1].z); @@ -292,7 +563,7 @@ float lcSynthInfo::GetSectionTwist(const lcMatrix44& StartTransform, const lcMat return 0.0f; } -void lcSynthInfo::CalculateCurveSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const +void lcSynthInfoCurved::CalculateSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const { float SectionLength = 0.0f; @@ -308,16 +579,7 @@ void lcSynthInfo::CalculateCurveSections(const lcArray& Con { if (mRigidEdges) { - switch (mType) - { - default: - StartTransform.SetTranslation(lcMul30(lcVector3(0.0f, mStart.Length, 0.0f), StartTransform) + StartTransform.GetTranslation()); - break; - - case lcSynthType::STRING_BRAIDED: - StartTransform.SetTranslation(lcMul30(lcVector3(mStart.Length, 0.0f, 0.0f), StartTransform) + StartTransform.GetTranslation()); - break; - } + StartTransform.SetTranslation(lcMul30(lcVector3(0.0f, mStart.Length, 0.0f), StartTransform) + StartTransform.GetTranslation()); SectionLength = 0.0f; } else @@ -329,18 +591,8 @@ void lcSynthInfo::CalculateCurveSections(const lcArray& Con EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation()); SegmentControlPoints[0] = StartTransform.GetTranslation(); - switch (mType) - { - default: - SegmentControlPoints[1] = lcMul31(lcVector3(0.0f, ControlPoints[ControlPointIdx].Scale, 0.0f), StartTransform); - SegmentControlPoints[2] = lcMul31(lcVector3(0.0f, -ControlPoints[ControlPointIdx + 1].Scale, 0.0f), EndTransform); - break; - - case lcSynthType::STRING_BRAIDED: - SegmentControlPoints[1] = lcMul31(lcVector3(ControlPoints[ControlPointIdx].Scale, 0.0f, 0.0f), StartTransform); - SegmentControlPoints[2] = lcMul31(lcVector3(-ControlPoints[ControlPointIdx + 1].Scale, 0.0f, 0.0f), EndTransform); - break; - } + SegmentControlPoints[1] = lcMul31(lcVector3(0.0f, ControlPoints[ControlPointIdx].Scale, 0.0f), StartTransform); + SegmentControlPoints[2] = lcMul31(lcVector3(0.0f, -ControlPoints[ControlPointIdx + 1].Scale, 0.0f), EndTransform); SegmentControlPoints[3] = EndTransform.GetTranslation(); const int NumCurvePoints = 8192; @@ -362,11 +614,7 @@ void lcSynthInfo::CalculateCurveSections(const lcArray& Con for (int PointIdx = 0; PointIdx < CurvePoints.GetSize() - 1; PointIdx++) TotalSegmentLength += lcLength(CurvePoints[PointIdx] - CurvePoints[PointIdx + 1]); - lcVector3 StartUp; - if (mType != lcSynthType::STRING_BRAIDED) - StartUp = lcMul30(lcVector3(1.0f, 0.0f, 0.0f), StartTransform); - else - StartUp = lcMul30(lcVector3(0.0f, 1.0f, 0.0f), StartTransform); + lcVector3 StartUp = lcMul30(lcVector3(1.0f, 0.0f, 0.0f), StartTransform); float Twist = GetSectionTwist(StartTransform, EndTransform); int CurrentPointIndex = 0; @@ -398,10 +646,7 @@ void lcSynthInfo::CalculateCurveSections(const lcArray& Con Up = lcNormalize(lcCross(Side, Tangent)); StartUp = Up; - if (mType != lcSynthType::STRING_BRAIDED) - Sections.Add(lcMatrix44(lcMatrix33(Up, Tangent, Side), CurvePoints[CurrentPointIndex])); - else - Sections.Add(lcMatrix44(lcMatrix33(Tangent, Up, -Side), CurvePoints[CurrentPointIndex])); + Sections.Add(lcMatrix44(lcMatrix33(Up, Tangent, Side), CurvePoints[CurrentPointIndex])); if (SectionCallback) SectionCallback(CurvePoints[CurrentPointIndex], ControlPointIdx, t); @@ -423,11 +668,7 @@ void lcSynthInfo::CalculateCurveSections(const lcArray& Con { lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPoints.GetSize() - 1].Transform); EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation()); - lcVector3 Position; - if (mType != lcSynthType::STRING_BRAIDED) - Position = lcMul31(lcVector3(0.0f, SectionLength, 0.0f), EndTransform); - else - Position = lcMul31(lcVector3(SectionLength, 0.0f, 0.0f), EndTransform); + lcVector3 Position = lcMul31(lcVector3(0.0f, SectionLength, 0.0f), EndTransform); EndTransform.SetTranslation(Position); Sections.Add(EndTransform); @@ -444,7 +685,129 @@ void lcSynthInfo::CalculateCurveSections(const lcArray& Con } } -void lcSynthInfo::CalculateLineSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const +void lcSynthInfoBraidedString::CalculateSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const +{ + float SectionLength = 0.0f; + + for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize() - 1 && Sections.GetSize() < mNumSections + 2; ControlPointIdx++) + { + lcVector3 SegmentControlPoints[4]; + + lcMatrix44 StartTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform); + lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx + 1].Transform); + StartTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mStart.Transform), lcMatrix33(StartTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), StartTransform.GetTranslation()); + + if (ControlPointIdx == 0) + { + if (mRigidEdges) + { + StartTransform.SetTranslation(lcMul30(lcVector3(mStart.Length, 0.0f, 0.0f), StartTransform) + StartTransform.GetTranslation()); + SectionLength = 0.0f; + } + else + SectionLength = mStart.Length; + + Sections.Add(StartTransform); + } + + EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation()); + + SegmentControlPoints[0] = StartTransform.GetTranslation(); + SegmentControlPoints[1] = lcMul31(lcVector3(ControlPoints[ControlPointIdx].Scale, 0.0f, 0.0f), StartTransform); + SegmentControlPoints[2] = lcMul31(lcVector3(-ControlPoints[ControlPointIdx + 1].Scale, 0.0f, 0.0f), EndTransform); + SegmentControlPoints[3] = EndTransform.GetTranslation(); + + const int NumCurvePoints = 8192; + lcArray CurvePoints; + CurvePoints.AllocGrow(NumCurvePoints); + + for (int PointIdx = 0; PointIdx < NumCurvePoints; PointIdx++) + { + float t = (float)PointIdx / (float)(NumCurvePoints - 1); + float it = 1.0f - t; + + lcVector3 Position = it * it * it * SegmentControlPoints[0] + it * it * 3.0f * t * SegmentControlPoints[1] + it * 3.0 * t * t * SegmentControlPoints[2] + t * t * t * SegmentControlPoints[3]; + CurvePoints.Add(Position); + } + + float CurrentSegmentLength = 0.0f; + float TotalSegmentLength = 0.0f; + + for (int PointIdx = 0; PointIdx < CurvePoints.GetSize() - 1; PointIdx++) + TotalSegmentLength += lcLength(CurvePoints[PointIdx] - CurvePoints[PointIdx + 1]); + + lcVector3 StartUp = lcMul30(lcVector3(0.0f, 1.0f, 0.0f), StartTransform); + float Twist = GetSectionTwist(StartTransform, EndTransform); + int CurrentPointIndex = 0; + + while (CurrentPointIndex < CurvePoints.GetSize() - 1) + { + float Length = lcLength(CurvePoints[CurrentPointIndex + 1] - CurvePoints[CurrentPointIndex]); + CurrentSegmentLength += Length; + SectionLength -= Length; + CurrentPointIndex++; + + if (SectionLength > 0.0f) + continue; + + float t = (float)CurrentPointIndex / (float)(NumCurvePoints - 1); + float it = 1.0f - t; + + lcVector3 Tangent = lcNormalize(-3.0f * it * it * SegmentControlPoints[0] + (3.0f * it * it - 6.0f * t * it) * SegmentControlPoints[1] + (-3.0f * t * t + 6.0f * t * it) * SegmentControlPoints[2] + 3.0f * t * t * SegmentControlPoints[3]); + lcVector3 Up; + + if (Twist) + { + Up = lcMul(StartUp, lcMatrix33FromAxisAngle(Tangent, Twist * (CurrentSegmentLength / TotalSegmentLength))); + CurrentSegmentLength = 0.0f; + } + else + Up = StartUp; + + lcVector3 Side = lcNormalize(lcCross(Tangent, Up)); + Up = lcNormalize(lcCross(Side, Tangent)); + StartUp = Up; + + Sections.Add(lcMatrix44(lcMatrix33(Tangent, Up, -Side), CurvePoints[CurrentPointIndex])); + + if (SectionCallback) + SectionCallback(CurvePoints[CurrentPointIndex], ControlPointIdx, t); + + if (Sections.GetSize() == mNumSections + 2) + break; + + if (mCenterLength != 0.0f && (Sections.GetSize() == mNumSections / 2 + 1)) + SectionLength += mCenterLength; + else + SectionLength += mMiddle.Length; + + if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges) + SectionLength += mEnd.Length; + } + } + + while (Sections.GetSize() < mNumSections + 2) + { + lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPoints.GetSize() - 1].Transform); + EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation()); + lcVector3 Position = lcMul31(lcVector3(SectionLength, 0.0f, 0.0f), EndTransform); + EndTransform.SetTranslation(Position); + Sections.Add(EndTransform); + + if (SectionCallback) + SectionCallback(Position, ControlPoints.GetSize() - 1, 1.0f); + + if (mCenterLength != 0.0f && (Sections.GetSize() == mNumSections / 2 + 1)) + SectionLength += mCenterLength; + else + SectionLength += mMiddle.Length; + + if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges) + SectionLength += mEnd.Length; + } +} + +void lcSynthInfoStraight::CalculateSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const { for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize(); ControlPointIdx++) { @@ -456,7 +819,19 @@ void lcSynthInfo::CalculateLineSections(const lcArray& Cont } } -void lcSynthInfo::AddHoseFlexibleParts(lcMemFile& File, const lcArray& Sections) const +void lcSynthInfoUniversalJoint::CalculateSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const +{ + for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize(); ControlPointIdx++) + { + lcMatrix44 Transform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform); + Sections.Add(Transform); + + if (SectionCallback) + SectionCallback(Transform.GetTranslation(), ControlPointIdx, 1.0f); + } +} + +void lcSynthInfoFlexibleHose::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray& Sections) const { char Line[256]; const int NumEdgeParts = 2; @@ -467,18 +842,11 @@ void lcSynthInfo::AddHoseFlexibleParts(lcMemFile& File, const lcArraymFileName, "73590a.dat") ? EdgePartsA : EdgePartsB; - for (int PartIdx = 0; PartIdx < NumEdgeParts; PartIdx++) { const int SectionIdx = 0; @@ -524,7 +892,7 @@ void lcSynthInfo::AddHoseFlexibleParts(lcMemFile& File, const lcArray& Sections) const +void lcSynthInfoFlexSystemHose::AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const { char Line[256]; @@ -632,7 +1000,7 @@ void lcSynthInfo::AddFlexHoseParts(lcMemFile& File, lcLibraryMeshData& MeshData, AddSectionVertices(InsideSectionVertices, LC_ARRAY_COUNT(InsideSectionVertices)); } -void lcSynthInfo::AddRibbedHoseParts(lcMemFile& File, const lcArray& Sections) const +void lcSynthInfoRibbedHose::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray& Sections) const { char Line[256]; @@ -669,7 +1037,7 @@ void lcSynthInfo::AddRibbedHoseParts(lcMemFile& File, const lcArray& } } -void lcSynthInfo::AddFlexibleAxleParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const +void lcSynthInfoFlexibleAxle::AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const { char Line[256]; const int NumEdgeParts = 6; @@ -799,12 +1167,15 @@ void lcSynthInfo::AddFlexibleAxleParts(lcMemFile& File, lcLibraryMeshData& MeshD } } -void lcSynthInfo::AddStringBraidedParts(lcMemFile& File, lcLibraryMeshData& MeshData, lcArray& Sections) const +void lcSynthInfoBraidedString::AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& SectionsIn) const { + lcArray Sections; + Sections.SetSize(SectionsIn.GetSize()); + for (int SectionIdx = 0; SectionIdx < Sections.GetSize(); SectionIdx++) { - lcMatrix33 Transform(lcMul(lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f)), lcMatrix33(Sections[SectionIdx]))); - lcVector3 Offset = Sections[SectionIdx].GetTranslation(); + lcMatrix33 Transform(lcMul(lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f)), lcMatrix33(SectionsIn[SectionIdx]))); + lcVector3 Offset = SectionsIn[SectionIdx].GetTranslation(); Sections[SectionIdx] = lcMatrix44(Transform, Offset); } @@ -929,7 +1300,7 @@ void lcSynthInfo::AddStringBraidedParts(lcMemFile& File, lcLibraryMeshData& Mesh } } -void lcSynthInfo::AddShockAbsorberParts(lcMemFile& File, lcArray& Sections) const +void lcSynthInfoShockAbsorber::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray& Sections) const { char Line[256]; lcVector3 Offset; @@ -944,25 +1315,13 @@ void lcSynthInfo::AddShockAbsorberParts(lcMemFile& File, lcArray& Se float Distance = Sections[0].GetTranslation().y - Sections[1].GetTranslation().y; float Scale = (Distance - 66.0f) / 44.0f; - const char* SpringPart; - - if (!qstricmp(mPieceInfo->mFileName, "73129.dat")) - SpringPart = "70038"; - else if (!qstricmp(mPieceInfo->mFileName, "41838.dat")) - SpringPart = "41837"; - else if (!qstricmp(mPieceInfo->mFileName, "76138.dat")) - SpringPart = "71953"; - else if (!qstricmp(mPieceInfo->mFileName, "76537.dat")) - SpringPart = "22977"; - else - return; Offset = Sections[0].GetTranslation(); - sprintf(Line, "1 494 %f %f %f 1 0 0 0 %f 0 0 0 1 %s.dat\n", Offset[0], Offset[1] - 10 - 44.0f * Scale, Offset[2], Scale, SpringPart); + sprintf(Line, "1 494 %f %f %f 1 0 0 0 %f 0 0 0 1 %s\n", Offset[0], Offset[1] - 10 - 44.0f * Scale, Offset[2], Scale, mSpringPart); File.WriteBuffer(Line, strlen(Line)); } -void lcSynthInfo::AddActuatorParts(lcMemFile& File, lcArray& Sections) const +void lcSynthInfoActuator::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray& Sections) const { char Line[256]; lcVector3 Offset; @@ -978,48 +1337,49 @@ void lcSynthInfo::AddActuatorParts(lcMemFile& File, lcArray& Section File.WriteBuffer(Line, strlen(Line)); } +void lcSynthInfoUniversalJoint::AddParts(lcMemFile& File, lcLibraryMeshData&, const lcArray& Sections) const +{ + char Line[256]; + lcVector3 Offset = Sections[0].GetTranslation(); + + float Angle = atan2f(Offset.x, Offset.z); + lcMatrix44 Rotation = lcMatrix44RotationZ(Angle); + lcMatrix44 Transform = lcMatrix44LeoCADToLDraw(Rotation); + + sprintf(Line, "1 16 0 0 0 %f %f %f %f %f %f %f %f %f %s\n", Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], mCenterPart); + File.WriteBuffer(Line, strlen(Line)); + + Angle = atan2f(Offset.y, hypotf(Offset.x, Offset.z)); + Rotation = lcMul(Rotation, lcMatrix44RotationX(Angle)); + Transform = lcMul( + lcMatrix44Translation(lcVector3(0.0f, 0.0f, mEndOffset)), + lcMatrix44LeoCADToLDraw(Rotation) + ); + + sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Transform[3][0], Transform[3][1], Transform[3][2], + Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], mEndPart); + File.WriteBuffer(Line, strlen(Line)); + + Rotation = lcMatrix44FromEulerAngles(lcVector3(0.0f, LC_PI/2, LC_PI)); + Transform = lcMatrix44LeoCADToLDraw(lcMul(lcMatrix44Translation(lcVector3(0.0f, mEndOffset, 0.0f)), Rotation)); + sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Transform[3][0], Transform[3][1], Transform[3][2], + Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], -Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], mEndPart); + File.WriteBuffer(Line, strlen(Line)); +} + lcMesh* lcSynthInfo::CreateMesh(const lcArray& ControlPoints) const { lcArray Sections; - if (mCurve) - CalculateCurveSections(ControlPoints, Sections, nullptr); - else - CalculateLineSections(ControlPoints, Sections, nullptr); + CalculateSections(ControlPoints, Sections, nullptr); lcLibraryMeshData MeshData; lcMemFile File; // todo: rewrite this to pass the parts directly - switch (mType) - { - case lcSynthType::HOSE_FLEXIBLE: - AddHoseFlexibleParts(File, Sections); - break; - - case lcSynthType::FLEX_SYSTEM_HOSE: - AddFlexHoseParts(File, MeshData, Sections); - break; - - case lcSynthType::RIBBED_HOSE: - AddRibbedHoseParts(File, Sections); - break; - - case lcSynthType::FLEXIBLE_AXLE: - AddFlexibleAxleParts(File, MeshData, Sections); - break; - - case lcSynthType::STRING_BRAIDED: - AddStringBraidedParts(File, MeshData, Sections); - break; - - case lcSynthType::SHOCK_ABSORBER: - AddShockAbsorberParts(File, Sections); - break; - - case lcSynthType::ACTUATOR: - AddActuatorParts(File, Sections); - break; - } + AddParts(File, MeshData, Sections); File.WriteU8(0); @@ -1042,7 +1402,7 @@ int lcSynthInfo::InsertControlPoint(lcArray& ControlPoints, float BestDistance = FLT_MAX; lcVector3 BestPosition; - CalculateCurveSections(ControlPoints, Sections, + CalculateSections(ControlPoints, Sections, [&](const lcVector3& CurvePoint, int SegmentIndex, float t) { float Distance = lcRayPointDistance(CurvePoint, Start, End); diff --git a/common/lc_synth.h b/common/lc_synth.h index a28d3ad5..99f62ce4 100644 --- a/common/lc_synth.h +++ b/common/lc_synth.h @@ -3,29 +3,13 @@ #include "lc_math.h" #include "piece.h" -enum class lcSynthType -{ - HOSE_FLEXIBLE, - FLEX_SYSTEM_HOSE, - RIBBED_HOSE, - FLEXIBLE_AXLE, - STRING_BRAIDED, - SHOCK_ABSORBER, - ACTUATOR -}; - -struct lcSynthComponent -{ - lcMatrix44 Transform; - float Length; -}; - class lcLibraryMeshData; class lcSynthInfo { public: - lcSynthInfo(lcSynthType Type, float Length, int NumSections, PieceInfo* Info); + explicit lcSynthInfo(float Length); + virtual ~lcSynthInfo() = default; bool CanAddControlPoints() const { @@ -37,33 +21,30 @@ public: return mCurve; } - void GetDefaultControlPoints(lcArray& ControlPoints) const; + bool IsUnidirectional() const + { + return mUnidirectional; + } + + bool IsNondirectional() const + { + return mNondirectional; + } + + virtual void GetDefaultControlPoints(lcArray& ControlPoints) const = 0; + virtual void VerifyControlPoints(lcArray& ControlPoints) const = 0; int InsertControlPoint(lcArray& ControlPoints, const lcVector3& Start, const lcVector3& End) const; lcMesh* CreateMesh(const lcArray& ControlPoints) const; protected: - float GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const; using SectionCallbackFunc = std::function; - void CalculateCurveSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const; - void CalculateLineSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const; - void AddHoseFlexibleParts(lcMemFile& File, const lcArray& Sections) const; - void AddFlexHoseParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const; - void AddRibbedHoseParts(lcMemFile& File, const lcArray& Sections) const; - void AddFlexibleAxleParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const; - void AddStringBraidedParts(lcMemFile& File, lcLibraryMeshData& MeshData, lcArray& Sections) const; - void AddShockAbsorberParts(lcMemFile& File, lcArray& Sections) const; - void AddActuatorParts(lcMemFile& File, lcArray& Sections) const; + virtual void CalculateSections(const lcArray& ControlPoints, lcArray& Sections, SectionCallbackFunc SectionCallback) const = 0; + virtual void AddParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const = 0; - PieceInfo* mPieceInfo; - lcSynthType mType; - lcSynthComponent mStart; - lcSynthComponent mMiddle; - lcSynthComponent mEnd; - bool mCurve; + bool mCurve = false; + bool mUnidirectional = false; + bool mNondirectional = false; float mLength; - float mCenterLength; - int mNumSections; - bool mRigidEdges; }; void lcSynthInit(); diff --git a/common/piece.cpp b/common/piece.cpp index 5aa67dea..1899685d 100644 --- a/common/piece.cpp +++ b/common/piece.cpp @@ -797,19 +797,27 @@ void lcPiece::RotatePivotPoint(const lcMatrix33& RotationMatrix) quint32 lcPiece::GetAllowedTransforms() const { + const quint32 Move = LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z; + const quint32 Rotate = LC_OBJECT_TRANSFORM_ROTATE_X | LC_OBJECT_TRANSFORM_ROTATE_Y | LC_OBJECT_TRANSFORM_ROTATE_Z; quint32 Section = GetFocusSection(); if (Section == LC_PIECE_SECTION_POSITION || Section == LC_PIECE_SECTION_INVALID) - return LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z | LC_OBJECT_TRANSFORM_ROTATE_X | LC_OBJECT_TRANSFORM_ROTATE_Y | LC_OBJECT_TRANSFORM_ROTATE_Z; + return Move | Rotate; lcSynthInfo* SynthInfo = mPieceInfo->GetSynthInfo(); - if (!SynthInfo) - return 0; + if (SynthInfo) + { + if (SynthInfo->IsUnidirectional()) + return LC_OBJECT_TRANSFORM_MOVE_Z; - if (SynthInfo->IsCurve()) - return LC_OBJECT_TRANSFORM_MOVE_X | LC_OBJECT_TRANSFORM_MOVE_Y | LC_OBJECT_TRANSFORM_MOVE_Z | LC_OBJECT_TRANSFORM_ROTATE_X | LC_OBJECT_TRANSFORM_ROTATE_Y | LC_OBJECT_TRANSFORM_ROTATE_Z | LC_OBJECT_TRANSFORM_SCALE_X; - else - return LC_OBJECT_TRANSFORM_MOVE_Z; + if (SynthInfo->IsCurve()) + return Move | Rotate | LC_OBJECT_TRANSFORM_SCALE_X; + + if (SynthInfo->IsNondirectional()) + return Move; + } + + return 0; } bool lcPiece::CanAddControlPoint() const @@ -866,6 +874,22 @@ bool lcPiece::RemoveFocusedControlPoint() return true; } +void lcPiece::VerifyControlPoints(lcArray& ControlPoints) const +{ + lcSynthInfo* SynthInfo = mPieceInfo->GetSynthInfo(); + if (!SynthInfo) + { + ControlPoints.RemoveAll(); + } + else + { + if (ControlPoints.GetSize() > LC_MAX_CONTROL_POINTS) + ControlPoints.SetSize(LC_MAX_CONTROL_POINTS); + + SynthInfo->VerifyControlPoints(ControlPoints); + } +} + const char* lcPiece::GetName() const { return mPieceInfo->m_strDescription; diff --git a/common/piece.h b/common/piece.h index 44b993b3..da7b8db6 100644 --- a/common/piece.h +++ b/common/piece.h @@ -431,11 +431,8 @@ public: void SetControlPoints(const lcArray& ControlPoints) { - if (ControlPoints.GetSize() > 1) - { - mControlPoints = ControlPoints; - UpdateMesh(); - } + mControlPoints = ControlPoints; + UpdateMesh(); } void SetControlPointScale(int ControlPointIndex, float Scale) @@ -472,6 +469,7 @@ public: bool InsertControlPoint(const lcVector3& WorldStart, const lcVector3& WorldEnd); bool RemoveFocusedControlPoint(); + void VerifyControlPoints(lcArray& ControlPoints) const; lcGroup* GetTopGroup();