Files
leocad/common/camera.h
T
Leonardo Zide baae697960 Fix in-place submodel editing context and navigation
In-place editing could use the tab model's step and focus, lose its active
state after switching tabs, or resolve a nested instance through the wrong
parent. Entering before the final animation key also moved geometry when
drilling into a child.

Use the edited model for step controls, step edits, visibility, and focus
coordinates. Restore that editing target when returning to its tab, include
animation keys and finite hide steps in the last step, and retain the
selected instance path and transforms during nested editing.

Show the editing path only during in-place edits, with links to ancestors
and a close control to return to the tab model. Stack Find/Replace beneath
it and preserve full names in accessible text and tooltips. Add translated
source entries without changing existing translations.

Add a regression test for final-key tracking through time and key edits.
Validated with the macOS Qt 6 application build, all 8 Qt Test cases, and
51 focused checks against the compiled application for steps, tab switching,
focus status, breadcrumbs, and Find/Replace layout. Visually checked the
viewport overlay and its placement during nested editing.
2026-10-24 12:39:25 -07:00

240 lines
6.7 KiB
C++

#pragma once
#include "object.h"
#include "lc_math.h"
enum class lcViewpoint
{
Front,
Back,
Top,
Bottom,
Left,
Right,
Home,
Count
};
enum class lcCameraProjection
{
Perspective,
Orthographic,
Count
};
enum lcCameraSection : quint32
{
LC_CAMERA_SECTION_INVALID = LC_OBJECT_SECTION_INVALID,
LC_CAMERA_SECTION_POSITION = 0,
LC_CAMERA_SECTION_TARGET,
LC_CAMERA_SECTION_UPVECTOR
};
struct lcCameraHistoryState
{
lcObjectId Id;
bool Hidden;
bool Simple;
float Fovy;
float NearPlane;
float FarPlane;
lcCameraProjection Projection;
lcObjectProperty<lcVector3> Position;
lcObjectProperty<lcVector3> TargetPosition;
lcObjectProperty<lcVector3> UpVector;
QString Name;
bool operator==(const lcCameraHistoryState& Other) const
{
return Id == Other.Id && Hidden == Other.Hidden && Simple == Other.Simple && Fovy == Other.Fovy &&
NearPlane == Other.NearPlane && FarPlane == Other.FarPlane && Projection == Other.Projection &&
Position == Other.Position && TargetPosition == Other.TargetPosition && UpVector == Other.UpVector && Name == Other.Name;
}
};
class lcCamera : public lcObject
{
public:
lcCamera();
lcCamera(bool Simple);
lcCamera(bool Simple, const lcVector3& Position, const lcVector3& TargetPosition);
virtual ~lcCamera();
lcCamera(const lcCamera&) = delete;
lcCamera(lcCamera&&) = delete;
lcCamera& operator=(const lcCamera&) = delete;
lcCamera& operator=(lcCamera&&) = delete;
static QString GetCameraProjectionString(lcCameraProjection CameraProjection);
static QStringList GetCameraProjectionStrings();
static lcViewpoint GetViewpoint(const QString& ViewpointName);
QString GetName() const override
{
return mName;
}
bool SetName(const QString& Name);
void CreateName(const std::vector<std::unique_ptr<lcCamera>>& Cameras);
bool IsSimple() const
{
return mSimple;
}
lcCameraProjection GetProjection() const
{
return mProjection;
}
bool SetProjection(lcCameraProjection CameraProjection);
bool SetFOV(float Fovy);
bool SetNearPlane(float NearPlane);
bool SetFarPlane(float FarPlane);
quint32 GetAllowedTransforms() const override
{
return LC_OBJECT_TRANSFORM_MOVE_XYZ;
}
lcVector3 GetSectionPosition(quint32 Section) const override
{
switch (Section)
{
case LC_CAMERA_SECTION_POSITION:
return mPosition;
case LC_CAMERA_SECTION_TARGET:
return mTargetPosition;
case LC_CAMERA_SECTION_UPVECTOR:
return lcMul31(lcVector3(0, 25, 0), lcMatrix44AffineInverse(mWorldView));
}
return lcVector3(0.0f, 0.0f, 0.0f);
}
lcMatrix33 GetRelativeRotation() const
{
const quint32 Section = GetFocusSection();
if (Section == LC_CAMERA_SECTION_POSITION)
return lcMatrix33(mWorldView);
else
return lcMatrix33Identity();
}
lcVector3 GetRotationCenter() const
{
const quint32 Section = GetFocusSection();
if (Section != LC_CAMERA_SECTION_TARGET)
{
return mPosition;
}
else
{
return mTargetPosition;
}
}
void SaveLDraw(QTextStream& Stream) const;
bool ParseLDrawLine(QTextStream& Stream);
public:
bool IsVisible() const
{
return !mHidden;
}
bool IsHidden() const
{
return mHidden;
}
void SetHidden(bool Hidden)
{
mHidden = Hidden;
}
void SetPosition(const lcVector3& Position, lcStep Step, bool AddKey)
{
mPosition.ChangeKey(Position, Step, AddKey);
}
void SetTargetPosition(const lcVector3& TargetPosition, lcStep Step, bool AddKey)
{
mTargetPosition.ChangeKey(TargetPosition, Step, AddKey);
}
void SetUpVector(const lcVector3& UpVector, lcStep Step, bool AddKey)
{
mUpVector.ChangeKey(UpVector, Step, AddKey);
}
float GetOrthoHeight() const
{
// Compute the FOV/plane intersection radius.
// d d
// a = 2 atan(------) => ~ a = --- => d = af
// 2f f
const float f = (mPosition - mTargetPosition).Length();
return (m_fovy * f) * (LC_PI / 180.0f);
}
public:
void RayTest(lcObjectRayTest& ObjectRayTest) const override;
void BoxTest(lcObjectBoxTest& ObjectBoxTest) const override;
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;
lcStep GetLastStep() const override;
bool SetKeyFrame(lcObjectPropertyId PropertyId, lcStep Time, bool KeyFrame) override;
void RemoveKeyFrames() override;
lcCameraHistoryState GetHistoryState() const;
void SetHistoryState(const lcCameraHistoryState& State);
void InsertTime(lcStep Start, lcStep Time);
void RemoveTime(lcStep Start, lcStep Time);
static bool FileLoad(lcFile& file);
void CompareBoundingBox(lcVector3& Min, lcVector3& Max);
void UpdatePosition(lcStep Step) override;
void CopyPosition(const lcCamera* Camera);
void CopySettings(const lcCamera* Camera);
void ZoomExtents(float AspectRatio, const lcVector3& Center, const std::vector<lcVector3>& Points, lcStep Step, bool AddKey, bool AdjustFarPlane);
void ExpandFarPlane(const std::vector<lcVector3>& Points);
void ZoomRegion(float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners, lcStep Step, bool AddKey);
void Zoom(float Distance, lcStep Step, bool AddKey);
void Pan(const lcVector3& Distance, lcStep Step, bool AddKey);
void Orbit(float DistanceX, float DistanceY, const lcVector3& CenterPosition, lcStep Step, bool AddKey);
void Roll(float Distance, lcStep Step, bool AddKey);
void Center(const lcVector3& NewCenter, lcStep Step, bool AddKey);
void MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance);
void MoveRelative(const lcVector3& Distance, lcStep Step, bool AddKey);
void Rotate(lcStep Step, bool AddKey, const lcMatrix33& RotationMatrix, const lcVector3& Center, const lcMatrix33& RotationFrame);
void SetViewpoint(lcViewpoint Viewpoint);
void SetViewpoint(const lcVector3& Position);
void SetViewpoint(const lcVector3& Position, const lcVector3& Target, const lcVector3& Up);
void GetAngles(float& Latitude, float& Longitude, float& Distance) const;
void SetAngles(float Latitude, float Longitude, float Distance);
float m_fovy = 30.0f;
float m_zNear = 25.0f;
static constexpr float DefaultFarPlane = 50000.0f;
float m_zFar = DefaultFarPlane;
lcMatrix44 mWorldView;
lcObjectProperty<lcVector3> mPosition = lcObjectProperty<lcVector3>(lcVector3(0.0f, 0.0f, 0.0f));
lcObjectProperty<lcVector3> mTargetPosition = lcObjectProperty<lcVector3>(lcVector3(0.0f, 0.0f, 0.0f));
lcObjectProperty<lcVector3> mUpVector = lcObjectProperty<lcVector3>(lcVector3(0.0f, 0.0f, 0.0f));
protected:
QString mName;
bool mSimple = true;
lcCameraProjection mProjection = lcCameraProjection::Perspective;
};