leocad/common/piece.h

377 lines
8.2 KiB
C
Raw Normal View History

#pragma once
2011-09-07 23:06:51 +02:00
class PieceInfo;
#include "object.h"
2012-03-28 03:07:18 +02:00
#include "lc_colors.h"
#include "lc_math.h"
2011-09-07 23:06:51 +02:00
#define LC_MAX_CONTROL_POINTS 1000
enum lcPieceSection : quint32
{
LC_PIECE_SECTION_INVALID = ~0U,
LC_PIECE_SECTION_POSITION = 0,
LC_PIECE_SECTION_CONTROL_POINT_FIRST,
LC_PIECE_SECTION_CONTROL_POINT_LAST = LC_PIECE_SECTION_CONTROL_POINT_FIRST + LC_MAX_CONTROL_POINTS - 1,
};
struct lcPieceControlPoint
{
lcMatrix44 Transform;
float Scale;
};
2011-09-07 23:06:51 +02:00
2014-05-01 20:42:11 +02:00
class lcPiece : public lcObject
2011-09-07 23:06:51 +02:00
{
public:
lcPiece(PieceInfo* Info);
2017-03-09 00:49:57 +01:00
lcPiece(const lcPiece& Other);
2014-05-01 20:42:11 +02:00
~lcPiece();
2011-09-07 23:06:51 +02:00
2020-05-04 00:39:39 +02:00
lcPiece(lcPiece&&) = delete;
lcPiece& operator=(const lcPiece&) = delete;
lcPiece& operator=(lcPiece&&) = delete;
bool IsSelected() const override
{
return mSelected;
}
2011-09-07 23:06:51 +02:00
bool IsSelected(quint32 Section) const override
{
2016-02-17 00:11:52 +01:00
Q_UNUSED(Section);
return mSelected;
}
2011-09-07 23:06:51 +02:00
void SetSelected(bool Selected) override
{
mSelected = Selected;
if (!Selected)
mFocusedSection = LC_PIECE_SECTION_INVALID;
}
2011-09-07 23:06:51 +02:00
void SetSelected(quint32 Section, bool Selected) override
{
2021-11-14 02:52:29 +01:00
Q_UNUSED(Section);
mSelected = Selected;
if (!Selected)
mFocusedSection = LC_PIECE_SECTION_INVALID;
}
bool IsFocused() const override
{
return mFocusedSection != LC_PIECE_SECTION_INVALID;
}
2011-09-07 23:06:51 +02:00
bool IsFocused(quint32 Section) const override
{
return mFocusedSection == Section;
}
void SetFocused(quint32 Section, bool Focused) override
{
if (Focused)
{
mFocusedSection = Section;
mSelected = true;
}
else
mFocusedSection = LC_PIECE_SECTION_INVALID;
}
quint32 GetFocusSection() const override
{
return mFocusedSection;
}
quint32 GetAllowedTransforms() const override;
lcVector3 GetSectionPosition(quint32 Section) const override
{
if (Section == LC_PIECE_SECTION_POSITION)
{
if (mPivotPointValid)
2015-12-15 02:57:22 +01:00
return lcMul(mPivotMatrix, mModelWorld).GetTranslation();
else
return mModelWorld.GetTranslation();
}
else
{
const int ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_FIRST;
if (ControlPointIndex >= 0 && ControlPointIndex < mControlPoints.GetSize())
{
const lcMatrix44& Transform = mControlPoints[ControlPointIndex].Transform;
return lcMul(Transform, mModelWorld).GetTranslation();
}
}
return lcVector3(0.0f, 0.0f, 0.0f);
}
2014-09-05 02:24:28 +02:00
void SaveLDraw(QTextStream& Stream) const;
2014-09-08 21:42:20 +02:00
bool ParseLDrawLine(QTextStream& Stream);
2015-03-21 21:12:04 +01:00
void SetFileLine(int Line)
{
mFileLine = Line;
}
int GetFileLine() const
{
return mFileLine;
}
void RayTest(lcObjectRayTest& ObjectRayTest) const override;
void BoxTest(lcObjectBoxTest& ObjectBoxTest) const override;
void DrawInterface(lcContext* Context, const lcScene& Scene) const override;
2024-01-15 02:41:01 +01:00
bool HasKeyFrame(lcObjectPropertyId PropertyId, lcStep Time) const override;
void RemoveKeyFrames() override;
2020-12-05 20:02:10 +01:00
void AddMainModelRenderMeshes(lcScene* Scene, bool Highlight, bool Fade) const;
void AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
void SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points) const;
2016-02-19 18:53:54 +01:00
2014-08-31 02:53:12 +02:00
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
2011-09-07 23:06:51 +02:00
bool IsHidden() const
{
return mHidden;
}
void SetHidden(bool Hidden)
{
mHidden = Hidden;
}
2011-09-07 23:06:51 +02:00
const lcArray<lcPieceControlPoint>& GetControlPoints() const
{
return mControlPoints;
}
2016-05-02 07:33:58 +02:00
void SetControlPoints(const lcArray<lcPieceControlPoint>& ControlPoints)
{
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.
2020-03-30 21:17:08 +02:00
mControlPoints = ControlPoints;
UpdateMesh();
2016-05-02 07:33:58 +02:00
}
void SetControlPointScale(int ControlPointIndex, float Scale)
{
mControlPoints[ControlPointIndex].Scale = Scale;
UpdateMesh();
}
2017-07-23 05:54:33 +02:00
const QString& GetID() const
{
return mID;
}
2017-07-24 04:35:18 +02:00
void UpdateID();
2020-12-14 01:27:21 +01:00
QString GetName() const override;
2019-03-13 03:51:04 +01:00
bool IsVisible(lcStep Step) const;
bool IsVisibleInSubModel() const;
2019-05-28 01:39:51 +02:00
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const;
void Initialize(const lcMatrix44& WorldMatrix, lcStep Step);
2016-02-19 18:53:54 +01:00
const lcBoundingBox& GetBoundingBox() const;
void CompareBoundingBox(lcVector3& Min, lcVector3& Max) const;
2017-07-23 05:54:33 +02:00
void SetPieceInfo(PieceInfo* Info, const QString& ID, bool Wait);
2013-08-09 06:57:18 +02:00
bool FileLoad(lcFile& file);
2011-09-07 23:06:51 +02:00
2014-07-06 08:04:09 +02:00
void UpdatePosition(lcStep Step);
void MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance);
2015-12-16 01:28:40 +01:00
void Rotate(lcStep Step, bool AddKey, const lcMatrix33& RotationMatrix, const lcVector3& Center, const lcMatrix33& RotationFrame);
void MovePivotPoint(const lcVector3& Distance);
void RotatePivotPoint(const lcMatrix33& RotationMatrix);
2011-09-07 23:06:51 +02:00
bool CanAddControlPoint() const;
bool CanRemoveControlPoint() const;
bool InsertControlPoint(const lcVector3& WorldStart, const lcVector3& WorldEnd);
bool RemoveFocusedControlPoint();
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.
2020-03-30 21:17:08 +02:00
void VerifyControlPoints(lcArray<lcPieceControlPoint>& ControlPoints) const;
2014-05-25 20:23:09 +02:00
lcGroup* GetTopGroup();
void SetGroup(lcGroup* Group)
{
mGroup = Group;
}
lcGroup* GetGroup()
{
return mGroup;
}
2014-07-06 08:04:09 +02:00
lcStep GetStepShow() const
{
return mStepShow;
}
lcStep GetStepHide() const
{
return mStepHide;
}
void SetStepHide(lcStep Step)
{
if (Step < 2)
Step = 2;
2014-07-06 08:04:09 +02:00
mStepHide = Step;
if (mStepHide <= mStepShow)
SetStepShow(mStepHide - 1);
2014-07-06 08:04:09 +02:00
}
void SetStepShow(lcStep Step)
{
if (Step == LC_STEP_MAX)
Step = LC_STEP_MAX - 1;
if (mStepShow != Step)
{
mFileLine = -1;
mStepShow = Step;
}
if (mStepHide <= mStepShow)
mStepHide = mStepShow + 1;
2014-07-06 08:04:09 +02:00
}
2011-09-07 23:06:51 +02:00
2021-01-17 03:27:39 +01:00
quint32 GetColorCode() const
{
return mColorCode;
}
2017-12-02 21:22:04 +01:00
void SetColorCode(quint32 ColorCode)
2011-09-07 23:06:51 +02:00
{
2012-03-28 03:07:18 +02:00
mColorCode = ColorCode;
mColorIndex = lcGetColorIndex(ColorCode);
}
2021-01-17 03:27:39 +01:00
int GetColorIndex() const
{
return mColorIndex;
}
2012-03-28 03:07:18 +02:00
void SetColorIndex(int ColorIndex)
{
mColorIndex = ColorIndex;
mColorCode = lcGetColorCode(ColorIndex);
}
2011-09-07 23:06:51 +02:00
2014-08-31 02:53:12 +02:00
void SetPosition(const lcVector3& Position, lcStep Step, bool AddKey)
{
2023-12-28 19:27:00 +01:00
mPosition.ChangeKey(Position, Step, AddKey);
2014-08-31 02:53:12 +02:00
}
void SetRotation(const lcMatrix33& Rotation, lcStep Step, bool AddKey)
2014-08-31 02:53:12 +02:00
{
2023-12-28 19:27:00 +01:00
mRotation.ChangeKey(Rotation, Step, AddKey);
2014-08-31 02:53:12 +02:00
}
2015-12-14 19:01:17 +01:00
lcVector3 GetRotationCenter() const
{
2020-03-23 04:18:52 +01:00
const quint32 Section = GetFocusSection();
2016-04-03 01:11:39 +02:00
if (Section == LC_PIECE_SECTION_POSITION || Section == LC_PIECE_SECTION_INVALID)
{
if (mPivotPointValid)
2016-04-03 01:11:39 +02:00
return lcMul31(mPivotMatrix.GetTranslation(), mModelWorld);
else
return mModelWorld.GetTranslation();
}
2015-12-14 19:01:17 +01:00
else
2016-04-03 01:11:39 +02:00
{
const int ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_FIRST;
2016-04-03 01:11:39 +02:00
if (ControlPointIndex >= 0 && ControlPointIndex < mControlPoints.GetSize())
{
const lcMatrix44& Transform = mControlPoints[ControlPointIndex].Transform;
2016-04-03 01:11:39 +02:00
return lcMul31(Transform.GetTranslation(), mModelWorld);
}
2015-12-14 19:01:17 +01:00
return mModelWorld.GetTranslation();
2016-04-03 01:11:39 +02:00
}
2015-12-14 19:01:17 +01:00
}
2015-12-15 20:47:52 +01:00
lcMatrix33 GetRelativeRotation() const
2015-12-14 19:01:17 +01:00
{
2020-03-23 04:18:52 +01:00
const quint32 Section = GetFocusSection();
if (Section == LC_PIECE_SECTION_POSITION || Section == LC_PIECE_SECTION_INVALID)
{
if (mPivotPointValid)
return lcMatrix33(lcMul(mModelWorld, mPivotMatrix));
else
return lcMatrix33(mModelWorld);
}
2015-12-14 19:01:17 +01:00
else
{
const int ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_FIRST;
if (ControlPointIndex >= 0 && ControlPointIndex < mControlPoints.GetSize())
{
const lcMatrix44& Transform = mControlPoints[ControlPointIndex].Transform;
return lcMatrix33(lcMul(Transform, mModelWorld));
}
return lcMatrix33Identity();
}
2015-12-14 19:01:17 +01:00
}
void ResetPivotPoint()
{
mPivotPointValid = false;
mPivotMatrix = lcMatrix44Identity();
2015-12-14 19:01:17 +01:00
}
public:
PieceInfo* mPieceInfo;
2012-03-28 03:07:18 +02:00
lcMatrix44 mModelWorld;
2015-12-14 19:01:17 +01:00
lcMatrix44 mPivotMatrix;
2011-09-07 23:06:51 +02:00
protected:
2016-02-19 18:53:54 +01:00
void UpdateMesh();
2015-12-14 19:01:17 +01:00
bool IsPivotPointVisible() const
{
return mPivotPointValid && IsFocused();
2015-12-14 19:01:17 +01:00
}
bool AreControlPointsVisible() const
{
return IsSelected();
}
2023-12-28 19:21:52 +01:00
lcObjectProperty<lcVector3> mPosition = lcObjectProperty<lcVector3>(lcVector3(0.0f, 0.0f, 0.0f));
lcObjectProperty<lcMatrix33> mRotation = lcObjectProperty<lcMatrix33>(lcMatrix33Identity());
2014-08-31 02:53:12 +02:00
2023-12-28 19:21:52 +01:00
int mFileLine = -1;
2017-07-23 05:54:33 +02:00
QString mID;
2015-03-21 21:12:04 +01:00
2014-08-07 17:22:33 +02:00
lcGroup* mGroup;
2011-09-07 23:06:51 +02:00
2021-01-17 03:27:39 +01:00
int mColorIndex;
quint32 mColorCode;
2014-07-06 08:04:09 +02:00
lcStep mStepShow;
lcStep mStepHide;
2011-09-07 23:06:51 +02:00
bool mPivotPointValid = false;
bool mHidden = false;
bool mSelected = false;
2023-12-28 19:21:52 +01:00
quint32 mFocusedSection = LC_PIECE_SECTION_INVALID;
lcArray<lcPieceControlPoint> mControlPoints;
2023-12-28 19:21:52 +01:00
lcMesh* mMesh = nullptr;
2011-09-07 23:06:51 +02:00
};