From a2e4a795f7e1ea68cf296ada6a83b03b3482fcf6 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Mon, 4 Aug 2025 18:14:28 +0300 Subject: [PATCH] Transformations now commited step by step, fixes many transformation related bugs --- include/Helpers/FixedPoint.hpp | 2 + include/Helpers/MathExtras.hpp | 6 + src/CoordSpaceHelper.cpp | 6 + src/CoordSpaceHelper.hpp | 1 + src/CoordSpaceHelperTransform.cpp | 113 +++++++++++++----- src/CoordSpaceHelperTransform.hpp | 18 ++- .../DrawingProgramSelection.cpp | 25 ++-- .../DrawingProgramSelection.hpp | 3 +- 8 files changed, 127 insertions(+), 47 deletions(-) diff --git a/include/Helpers/FixedPoint.hpp b/include/Helpers/FixedPoint.hpp index c76304b..0f0810e 100644 --- a/include/Helpers/FixedPoint.hpp +++ b/include/Helpers/FixedPoint.hpp @@ -442,6 +442,8 @@ namespace FixedPoint { } Multiplier operator*(const Multiplier& a) const { + if(a.val == UnderlyingNumber(0)) + return Multiplier(0); return (*this) / Multiplier(a.val, !a.isReciprocal); } diff --git a/include/Helpers/MathExtras.hpp b/include/Helpers/MathExtras.hpp index 8085b5e..695e407 100644 --- a/include/Helpers/MathExtras.hpp +++ b/include/Helpers/MathExtras.hpp @@ -269,3 +269,9 @@ template T transform_scalar(const Transform& transf template std::array, 4> triangle_from_rect_points(const Vector& min, const Vector& max) { return {min, {min.x(), max.y()}, max, {max.x(), min.y()}}; } + +template std::string vec_pretty(const Vector& a) { + std::stringstream ss; + ss << "[" << a.x() << ", " << a.y() << "]"; + return ss.str(); +} diff --git a/src/CoordSpaceHelper.cpp b/src/CoordSpaceHelper.cpp index db78613..125d863 100644 --- a/src/CoordSpaceHelper.cpp +++ b/src/CoordSpaceHelper.cpp @@ -72,6 +72,12 @@ void CoordSpaceHelper::scale_about_double(const WorldVec& scalePos, double scale } } +void CoordSpaceHelper::scale_about(const WorldVec& scalePos, const WorldMultiplier& scaleAmount) { + inverseScale = inverseScale / scaleAmount; + WorldVec mVec = pos - scalePos; + pos = scalePos + FixedPoint::multiplier_vec_div(mVec, scaleAmount); +} + void CoordSpaceHelper::scale_about(const WorldVec& scalePos, const WorldScalar& scaleAmount, bool flipScale) { if(!flipScale) { inverseScale /= scaleAmount; diff --git a/src/CoordSpaceHelper.hpp b/src/CoordSpaceHelper.hpp index 8ac17a2..5e5714a 100644 --- a/src/CoordSpaceHelper.hpp +++ b/src/CoordSpaceHelper.hpp @@ -85,6 +85,7 @@ class CoordSpaceHelper { void scale(const WorldScalar& scaleAmount); void rotate_about(const WorldVec& rotatePos, double angle); void scale_about(const WorldVec& scalePos, const WorldScalar& scaleAmount, bool flipScale); + void scale_about(const WorldVec& scalePos, const WorldMultiplier& scaleAmount); void scale_about_double(const WorldVec& scalePos, double scaleAmount); void set_rotation(double newRotation); diff --git a/src/CoordSpaceHelperTransform.cpp b/src/CoordSpaceHelperTransform.cpp index 28e0539..a5a486d 100644 --- a/src/CoordSpaceHelperTransform.cpp +++ b/src/CoordSpaceHelperTransform.cpp @@ -1,35 +1,106 @@ #include "CoordSpaceHelperTransform.hpp" +#include "CoordSpaceHelper.hpp" +#include "nlohmann/json.hpp" + +CoordSpaceHelperTransform::CoordSpaceHelperTransform() {} + +CoordSpaceHelperTransform::CoordSpaceHelperTransform(const WorldVec& translationPos): + transformType(TransformType::TRANSLATE), + pos(translationPos) +{} + +CoordSpaceHelperTransform::CoordSpaceHelperTransform(const WorldVec& rotatePos, double angle): + transformType(TransformType::ROTATE), + pos(rotatePos), + rotation(angle) +{} + +CoordSpaceHelperTransform::CoordSpaceHelperTransform(const WorldVec& scalePos, const WorldMultiplier& inverseScaleAmount): + transformType(TransformType::SCALE), + pos(scalePos), + inverseScale(inverseScaleAmount) +{} bool CoordSpaceHelperTransform::operator==(const CoordSpaceHelperTransform& otherCoords) const { - return rotation == otherCoords.rotation && pos == otherCoords.pos && inverseScale == otherCoords.inverseScale; + return otherCoords.transformType == transformType && rotation == otherCoords.rotation && pos == otherCoords.pos && inverseScale == otherCoords.inverseScale; } bool CoordSpaceHelperTransform::operator!=(const CoordSpaceHelperTransform& otherCoords) const { return rotation != otherCoords.rotation || pos != otherCoords.pos || inverseScale != otherCoords.inverseScale; } -WorldVec CoordSpaceHelperTransform::to_space_world(const WorldVec& coord) const { - return rotate_world_coord(FixedPoint::multiplier_vec_div((coord - pos), inverseScale), -rotation); -} +//WorldVec CoordSpaceHelperTransform::to_space_world(const WorldVec& coord) const { +// switch(transformType) { +// case TransformType::NONE: +// return coord; +// case TransformType::TRANSLATE: +// return (coord - pos); +// case TransformType::SCALE: +// return pos + FixedPoint::multiplier_vec_div(coord - pos, inverseScale); +// case TransformType::ROTATE: +// return rotate_world_coord(coord + pos, -rotation) - pos; +// } +// return coord; +//} WorldVec CoordSpaceHelperTransform::from_space_world(const WorldVec& coord) const { - return FixedPoint::multiplier_vec_mult(rotate_world_coord(coord, rotation), inverseScale) + pos; + switch(transformType) { + case TransformType::NONE: + return coord; + case TransformType::TRANSLATE: + return (coord + pos); + case TransformType::SCALE: + return FixedPoint::multiplier_vec_div(coord - pos, inverseScale) + pos; + case TransformType::ROTATE: + return pos + rotate_world_coord(coord - pos, rotation); + } + return coord; } CoordSpaceHelper CoordSpaceHelperTransform::other_coord_space_to_this_space(const CoordSpaceHelper& other) const { - CoordSpaceHelper toRet; - toRet.pos = to_space_world(other.pos); - toRet.rotation = other.rotation - rotation; - toRet.inverseScale = other.inverseScale / inverseScale; - return toRet; + switch(transformType) { + case TransformType::NONE: + return other; + case TransformType::TRANSLATE: { + auto toRet = other; + toRet.translate(-pos); + return toRet; + } + case TransformType::SCALE: { + auto toRet = other; + toRet.scale_about(pos, WorldMultiplier(1) / inverseScale); + return toRet; + } + case TransformType::ROTATE: { + auto toRet = other; + toRet.rotate_about(pos, -rotation); + return toRet; + } + } + return other; } CoordSpaceHelper CoordSpaceHelperTransform::other_coord_space_from_this_space(const CoordSpaceHelper& other) const { - CoordSpaceHelper toRet; - toRet.pos = from_space_world(other.pos); - toRet.rotation = other.rotation + rotation; - toRet.inverseScale = other.inverseScale * inverseScale; - return toRet; + switch(transformType) { + case TransformType::NONE: + return other; + case TransformType::TRANSLATE: { + auto toRet = other; + toRet.translate(pos); + return toRet; + } + case TransformType::SCALE: { + auto toRet = other; + toRet.scale_about(pos, inverseScale); + return toRet; + } + case TransformType::ROTATE: { + auto toRet = other; + toRet.rotate_about(pos, rotation); + return toRet; + } + } + return other; } void CoordSpaceHelperTransform::translate(const WorldVec& translation) { @@ -55,15 +126,3 @@ void CoordSpaceHelperTransform::set_rotation(double newRotation) { while (rotation < 0.0) rotation += 2.0 * std::numbers::pi; } - -void CoordSpaceHelperTransform::scale_about(const WorldVec& scalePos, const WorldMultiplier& scaleAmount) { - inverseScale = inverseScale / scaleAmount; - WorldVec mVec = pos - scalePos; - pos = scalePos + FixedPoint::multiplier_vec_div(mVec, scaleAmount); -} - -std::ostream& operator<<(std::ostream& os, const CoordSpaceHelperTransform& a) { - return os << "pos: [" << a.pos.x() << " " << a.pos.y() << "]\n" - << "inverseScale: " << static_cast(a.inverseScale) << "\n" - << "rotation: " << a.rotation << "\n"; -} diff --git a/src/CoordSpaceHelperTransform.hpp b/src/CoordSpaceHelperTransform.hpp index 2902d61..b200f7a 100644 --- a/src/CoordSpaceHelperTransform.hpp +++ b/src/CoordSpaceHelperTransform.hpp @@ -15,8 +15,13 @@ struct DrawData; class CoordSpaceHelperTransform { public: + CoordSpaceHelperTransform(); + CoordSpaceHelperTransform(const WorldVec& translationPos); + CoordSpaceHelperTransform(const WorldVec& rotatePos, double angle); + CoordSpaceHelperTransform(const WorldVec& scalePos, const WorldMultiplier& inverseScaleAmount); + WorldVec from_space_world(const WorldVec& coord) const; - WorldVec to_space_world(const WorldVec& coord) const; + //WorldVec to_space_world(const WorldVec& coord) const; CoordSpaceHelper other_coord_space_to_this_space(const CoordSpaceHelper& other) const; CoordSpaceHelper other_coord_space_from_this_space(const CoordSpaceHelper& other) const; @@ -24,12 +29,21 @@ class CoordSpaceHelperTransform { bool operator==(const CoordSpaceHelperTransform& otherCoords) const; bool operator!=(const CoordSpaceHelperTransform& otherCoords) const; + enum class TransformType { + NONE, + TRANSLATE, + ROTATE, + SCALE + }; + + private: void set_rotation(double newRotation); void translate(const WorldVec& translation); void rotate_about(const WorldVec& rotatePos, double angle); void scale_about(const WorldVec& scalePos, const WorldMultiplier& scaleAmount); - WorldVec pos{0, 0}; + TransformType transformType = TransformType::NONE; + WorldVec pos{0, 0}; // rotation center, scale center, or translation value WorldMultiplier inverseScale{1}; double rotation = 0.0; }; diff --git a/src/DrawingProgram/DrawingProgramSelection.cpp b/src/DrawingProgram/DrawingProgramSelection.cpp index bb13c11..242a10c 100644 --- a/src/DrawingProgram/DrawingProgramSelection.cpp +++ b/src/DrawingProgram/DrawingProgramSelection.cpp @@ -231,8 +231,8 @@ void DrawingProgramSelection::update() { selectionRectPoints[2] = selectionTransformCoords.from_space_world(initialSelectionAABB.max); selectionRectPoints[3] = selectionTransformCoords.from_space_world(initialSelectionAABB.top_right()); - scaleData.handlePoint = drawP.world.drawData.cam.c.to_space(selectionTransformCoords.from_space_world(initialSelectionAABB.max)); - rotateData.centerHandlePoint = drawP.world.drawData.cam.c.to_space(selectionTransformCoords.from_space_world(rotateData.centerPos)); + scaleData.handlePoint = drawP.world.drawData.cam.c.to_space(initialSelectionAABB.max); + rotateData.centerHandlePoint = drawP.world.drawData.cam.c.to_space(rotateData.centerPos); rotateData.handlePoint = get_rotation_point_pos_from_angle(rotateData.rotationAngle); rebuild_cam_space(); @@ -243,19 +243,16 @@ void DrawingProgramSelection::update() { if(mouse_collided_with_scale_point()) { scaleData.currentPos = scaleData.startPos = selectionTransformCoords.from_space_world(initialSelectionAABB.max); scaleData.centerPos = selectionTransformCoords.from_space_world(initialSelectionAABB.center()); - startingSelectionTransformCoords = selectionTransformCoords; transformOpHappening = TransformOperation::SCALE; } else if(mouse_collided_with_rotate_center_handle_point()) transformOpHappening = TransformOperation::ROTATE_RELOCATE_CENTER; else if(mouse_collided_with_rotate_handle_point()) { rotateData.rotationAngle = 0.0; - startingSelectionTransformCoords = selectionTransformCoords; transformOpHappening = TransformOperation::ROTATE; } else if(mouse_collided_with_selection_aabb()) { translateData.startPos = drawP.world.get_mouse_world_pos(); - startingSelectionTransformCoords = selectionTransformCoords; transformOpHappening = TransformOperation::TRANSLATE; } else @@ -263,10 +260,8 @@ void DrawingProgramSelection::update() { } break; case TransformOperation::TRANSLATE: - if(drawP.controls.leftClickHeld) { - selectionTransformCoords = startingSelectionTransformCoords; - selectionTransformCoords.translate(drawP.world.get_mouse_world_pos() - translateData.startPos); - } + if(drawP.controls.leftClickHeld) + selectionTransformCoords = CoordSpaceHelperTransform(drawP.world.get_mouse_world_pos() - translateData.startPos); else { commit_transform_selection(); return; @@ -288,8 +283,7 @@ void DrawingProgramSelection::update() { if(!isAnyNumberZero) { WorldMultiplier scaleAmount = WorldMultiplier(centerToScaleStartNorm) / WorldMultiplier(centerToScaleCurrentNorm); - selectionTransformCoords = startingSelectionTransformCoords; - selectionTransformCoords.scale_about(scaleData.centerPos, scaleAmount); + selectionTransformCoords = CoordSpaceHelperTransform(scaleData.centerPos, scaleAmount); } } else { @@ -299,7 +293,7 @@ void DrawingProgramSelection::update() { break; case TransformOperation::ROTATE_RELOCATE_CENTER: if(drawP.controls.leftClickHeld) - rotateData.centerPos = selectionTransformCoords.to_space_world(drawP.world.get_mouse_world_pos()); + rotateData.centerPos = drawP.world.get_mouse_world_pos(); else transformOpHappening = TransformOperation::NONE; break; @@ -307,8 +301,7 @@ void DrawingProgramSelection::update() { if(drawP.controls.leftClickHeld) { Vector2f rotationPointDiff = drawP.world.main.input.mouse.pos - rotateData.centerHandlePoint; rotateData.rotationAngle = std::atan2(rotationPointDiff.y(), rotationPointDiff.x()); - selectionTransformCoords = startingSelectionTransformCoords; - selectionTransformCoords.rotate_about(selectionTransformCoords.from_space_world(rotateData.centerPos), rotateData.rotationAngle); + selectionTransformCoords = CoordSpaceHelperTransform(rotateData.centerPos, rotateData.rotationAngle); } else { commit_transform_selection(); @@ -321,9 +314,9 @@ void DrawingProgramSelection::update() { deselect_all(); else if(drawP.world.main.input.key(InputManager::KEY_DRAW_DELETE).pressed) delete_all(); - else if(drawP.world.main.input.key(InputManager::KEY_COPY).pressed && startingSelectionTransformCoords == CoordSpaceHelperTransform()) + else if(drawP.world.main.input.key(InputManager::KEY_COPY).pressed && selectionTransformCoords == CoordSpaceHelperTransform()) selection_to_clipboard(); - else if(drawP.world.main.input.key(InputManager::KEY_CUT).pressed && startingSelectionTransformCoords == CoordSpaceHelperTransform()) { + else if(drawP.world.main.input.key(InputManager::KEY_CUT).pressed && selectionTransformCoords == CoordSpaceHelperTransform()) { selection_to_clipboard(); delete_all(); } diff --git a/src/DrawingProgram/DrawingProgramSelection.hpp b/src/DrawingProgram/DrawingProgramSelection.hpp index 470fef2..153fc3d 100644 --- a/src/DrawingProgram/DrawingProgramSelection.hpp +++ b/src/DrawingProgram/DrawingProgramSelection.hpp @@ -44,6 +44,7 @@ class DrawingProgramSelection { std::array selectionRectPoints; CoordSpaceHelperTransform selectionTransformCoords; + std::unordered_set selectedSet; DrawingProgramCache cache; DrawingProgram& drawP; @@ -56,8 +57,6 @@ class DrawingProgramSelection { ROTATE } transformOpHappening = TransformOperation::NONE; - CoordSpaceHelperTransform startingSelectionTransformCoords; - struct TranslationData { WorldVec startPos; } translateData;