Files
leocad/common/piece.h
T
Leonardo Zide 851eecee50 Store only changed objects in edit undo history
Full before-and-after model snapshots accumulate large amounts of memory during editing, even when an operation changes only one object. Compact completed edits to retain only added, removed, or modified object states, with ordering metadata kept only for structural changes.

Restore objects by stable IDs, including group relationships, and detach views before removing cameras. Compose merged edits from their deltas and compare animation keys as well as current property values so keyframe-only edits remain undoable.
2026-10-21 10:48:24 -07:00

324 lines
8.3 KiB
C++

#pragma once
class lcPieceData;
#include "object.h"
#include "lc_colors.h"
#include "lc_math.h"
#include "lc_assettypes.h"
#define LC_MAX_CONTROL_POINTS 1000
enum lcPieceSection : quint32
{
LC_PIECE_SECTION_INVALID = LC_OBJECT_SECTION_INVALID,
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,
LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST = 1
};
struct lcPieceControlPoint
{
lcMatrix44 Transform;
float Scale;
bool operator==(const lcPieceControlPoint& Other) const
{
return Transform == Other.Transform && Scale == Other.Scale;
}
};
struct lcPieceHistoryState
{
lcObjectId Id;
bool Hidden;
int FileLine;
QString PieceId;
uint32_t GroupId;
int ColorIndex;
quint32 ColorCode;
lcStep StepShow;
lcStep StepHide;
lcMatrix44 PivotMatrix;
bool PivotPointValid;
std::vector<lcPieceControlPoint> ControlPoints;
lcObjectProperty<lcVector3> Position;
lcObjectProperty<lcMatrix33> Rotation;
bool operator==(const lcPieceHistoryState& Other) const
{
return Id == Other.Id && Hidden == Other.Hidden && FileLine == Other.FileLine && PieceId == Other.PieceId &&
GroupId == Other.GroupId && ColorIndex == Other.ColorIndex && ColorCode == Other.ColorCode &&
StepShow == Other.StepShow && StepHide == Other.StepHide && PivotMatrix == Other.PivotMatrix &&
PivotPointValid == Other.PivotPointValid && ControlPoints == Other.ControlPoints &&
Position == Other.Position && Rotation == Other.Rotation;
}
};
class lcPiece : public lcObject
{
public:
lcPiece();
lcPiece(lcPieceData* PieceData);
lcPiece(lcPieceDataRef PieceDataRef);
lcPiece(const lcPiece& Other);
virtual ~lcPiece();
lcPiece(lcPiece&&) = delete;
lcPiece& operator=(const lcPiece&) = delete;
lcPiece& operator=(lcPiece&&) = delete;
quint32 GetAllowedTransforms() const override;
lcVector3 GetSectionPosition(quint32 Section) const override;
void SaveLDraw(QTextStream& Stream) const;
bool ParseLDrawLine(QTextStream& Stream);
void SetFileLine(int Line)
{
mFileLine = Line;
}
int GetFileLine() const
{
return mFileLine;
}
void RayTest(lcObjectRayTest& ObjectRayTest) const override;
void BoxTest(lcObjectBoxTest& ObjectBoxTest) const override;
bool MinIntersectDist(const lcVector3& Start, const lcVector3& End, float& MinDistance, lcPieceRayTest& PieceRayTest) const;
bool IntersectsPlanes(const lcMatrix44& WorldMatrix, const lcVector4 Planes[6]) const;
void DrawInterface(lcContext* Context, const lcScene& Scene) const override;
QVariant GetPropertyValue(lcObjectPropertyId PropertyId) const override;
bool SetPropertyValue(lcObjectPropertyId PropertyId, lcStep Step, bool AddKey, QVariant Value) override;
bool HasKeyFrame(lcObjectPropertyId PropertyId, lcStep Time) const override;
bool SetKeyFrame(lcObjectPropertyId PropertyId, lcStep Time, bool KeyFrame) override;
void RemoveKeyFrames() override;
lcPieceHistoryState GetHistoryState() const;
void SetHistoryState(const lcPieceHistoryState& State, Project* Project, lcGroup* Group);
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, lcGeometryBoundsMode Mode) const;
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
bool IsHidden() const
{
return mHidden;
}
void SetHidden(bool Hidden)
{
mHidden = Hidden;
}
const std::vector<lcPieceControlPoint>& GetControlPoints() const
{
return mControlPoints;
}
void SetControlPoints(const std::vector<lcPieceControlPoint>& ControlPoints)
{
mControlPoints = ControlPoints;
UpdateMesh();
}
void SetControlPointScale(int ControlPointIndex, float Scale)
{
mControlPoints[ControlPointIndex].Scale = Scale;
UpdateMesh();
}
bool IsTrainTrackConnected(int ConnectionIndex) const
{
return mTrainTrackConnections[ConnectionIndex];
}
void SetTrainTrackConnections(std::vector<bool>&& Connections)
{
mTrainTrackConnections = std::move(Connections);
}
const QString& GetID() const
{
return mID;
}
void UpdateID();
QString GetName() const override;
bool IsVisible(lcStep Step) const;
bool IsVisibleInSubModel() const;
bool AreTrainTrackConnectionsVisible() const
{
return IsFocused();
}
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const;
void Initialize(const lcMatrix44& WorldMatrix, lcStep Step);
const lcBoundingBox& GetBoundingBox() const;
void CompareBoundingBox(lcVector3& Min, lcVector3& Max) const;
void SetPieceData(lcPieceDataRef PieceDataRef, const QString& ID, bool Wait, bool UpdateSynthInfo);
bool SetPieceId(lcPieceData* PieceData);
bool FileLoad(lcFile& file, Project* Project);
void UpdatePosition(lcStep Step) override;
void MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance);
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);
bool CanAddControlPoint() const;
bool CanRemoveControlPoint() const;
bool InsertControlPoint(const lcVector3& WorldStart, const lcVector3& WorldEnd);
bool RemoveFocusedControlPoint();
void VerifyControlPoints(std::vector<lcPieceControlPoint>& ControlPoints) const;
bool IsGeneratedMeshPending() const { return mSynthPending; }
// An older mesh may remain visible while its replacement is pending.
bool HasGeneratedMesh() const { return mMesh != nullptr && !mSynthPending; }
void SetGeneratedMesh(lcMesh* Mesh);
void RefreshGeneratedMesh();
lcGroup* GetTopGroup();
void SetGroup(lcGroup* Group)
{
mGroup = Group;
}
lcGroup* GetGroup() const
{
return mGroup;
}
lcStep GetStepShow() const
{
return mStepShow;
}
lcStep GetStepHide() const
{
return mStepHide;
}
void SetStepHide(lcStep Step)
{
if (Step < 2)
Step = 2;
mStepHide = Step;
if (mStepHide <= mStepShow)
SetStepShow(mStepHide - 1);
}
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;
}
quint32 GetColorCode() const
{
return mColorCode;
}
void SetColorCode(quint32 ColorCode)
{
mColorCode = ColorCode;
mColorIndex = lcGetColorIndex(ColorCode);
}
int GetColorIndex() const
{
return mColorIndex;
}
bool SetColorIndex(int ColorIndex)
{
if (mColorIndex == ColorIndex)
return false;
mColorIndex = ColorIndex;
mColorCode = lcGetColorCode(ColorIndex);
return true;
}
void SetPosition(const lcVector3& Position, lcStep Step, bool AddKey)
{
mPosition.ChangeKey(Position, Step, AddKey);
}
void SetRotation(const lcMatrix33& Rotation, lcStep Step, bool AddKey)
{
mRotation.ChangeKey(Rotation, Step, AddKey);
}
lcVector3 GetRotationCenter() const;
lcMatrix33 GetRelativeRotation() const;
void ResetPivotPoint()
{
mPivotPointValid = false;
mPivotMatrix = lcMatrix44Identity();
}
public:
lcPieceDataRef mPieceData;
lcMatrix44 mModelWorld;
lcMatrix44 mPivotMatrix = lcMatrix44Identity();
protected:
void UpdateMesh();
lcMesh* GetDisplayMesh() const;
bool IsPivotPointVisible() const
{
return mPivotPointValid && IsFocused();
}
bool AreControlPointsVisible() const
{
return IsSelected();
}
void DrawSynthInterface(lcContext* Context, const lcMatrix44& WorldMatrix) const;
lcObjectProperty<lcVector3> mPosition = lcObjectProperty<lcVector3>(lcVector3(0.0f, 0.0f, 0.0f));
lcObjectProperty<lcMatrix33> mRotation = lcObjectProperty<lcMatrix33>(lcMatrix33Identity());
int mFileLine = -1;
QString mID;
lcGroup* mGroup = nullptr;
int mColorIndex;
quint32 mColorCode;
lcStep mStepShow = 1;
lcStep mStepHide = LC_STEP_MAX;
bool mPivotPointValid = false;
std::vector<lcPieceControlPoint> mControlPoints;
std::vector<bool> mTrainTrackConnections;
lcMesh* mMesh = nullptr;
bool mSynthPending = false;
};