Separate coord space transform class for more correct scaling

This commit is contained in:
Yousef Khadadeh 2025-08-04 10:47:24 +03:00
parent 46370e5762
commit d261293d6b
7 changed files with 307 additions and 7 deletions

View file

@ -12,6 +12,8 @@
class World;
struct DrawData;
WorldVec rotate_world_coord(const WorldVec& a, double rotationAngle);
class CoordSpaceHelper {
public:
template <typename Archive> void save(Archive& a) const {
@ -82,8 +84,8 @@ class CoordSpaceHelper {
void translate(const WorldVec& translation);
void scale(const WorldScalar& scaleAmount);
void rotate_about(const WorldVec& rotatePos, double angle);
void scale_about_double(const WorldVec& scalePos, double scaleAmount);
void scale_about(const WorldVec& scalePos, const WorldScalar& scaleAmount, bool flipScale);
void scale_about_double(const WorldVec& scalePos, double scaleAmount);
void set_rotation(double newRotation);
template <size_t S> std::array<Vector2f, S> to_space(const std::array<WorldVec, S>& coord) const {

View file

@ -0,0 +1,63 @@
#include "CoordSpaceHelperTransform.hpp"
bool CoordSpaceHelperTransform::operator==(const CoordSpaceHelperTransform& otherCoords) const {
return 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::from_space_world(const WorldVec& coord) const {
return FixedPoint::multiplier_vec_mult(rotate_world_coord(coord, rotation), inverseScale) + pos;
}
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;
}
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;
}
void CoordSpaceHelperTransform::translate(const WorldVec& translation) {
pos += translation;
}
void CoordSpaceHelperTransform::rotate_about(const WorldVec& rotatePos, double angle) {
WorldVec a = pos - rotatePos;
FixedPoint::Number<boost::multiprecision::cpp_int, 15> s = FixedPoint::Number<boost::multiprecision::cpp_int, 15>(std::sin(angle));
FixedPoint::Number<boost::multiprecision::cpp_int, 15> c = FixedPoint::Number<boost::multiprecision::cpp_int, 15>(std::cos(angle));
set_rotation(rotation + angle);
pos = {
rotatePos.x() + a.x().multiply_different_precision(c) - a.y().multiply_different_precision(s),
rotatePos.y() + a.x().multiply_different_precision(s) + a.y().multiply_different_precision(c)
};
}
void CoordSpaceHelperTransform::set_rotation(double newRotation) {
rotation = newRotation;
// using circular fmod caused inaccuracies, so these loops might be a better solution
while(rotation >= 2.0 * std::numbers::pi)
rotation -= 2.0 * std::numbers::pi;
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);
}

View file

@ -0,0 +1,35 @@
#pragma once
#include "SharedTypes.hpp"
#include <Helpers/Serializers.hpp>
#include <array>
#include <Helpers/SCollision.hpp>
#include "CoordSpaceHelper.hpp"
#ifndef IS_SERVER
#include "include/core/SkMatrix.h"
#include "include/core/SkCanvas.h"
#endif
class World;
struct DrawData;
class CoordSpaceHelperTransform {
public:
WorldVec from_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;
bool operator==(const CoordSpaceHelperTransform& otherCoords) const;
bool operator!=(const CoordSpaceHelperTransform& otherCoords) const;
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};
WorldMultiplier inverseScale{1};
double rotation = 0.0;
};

View file

@ -283,7 +283,7 @@ void DrawingProgramSelection::update() {
scaleAmount = centerToScaleStartNorm / centerToScaleCurrentNorm;
selectionTransformCoords = startingSelectionTransformCoords;
selectionTransformCoords.scale_about(scaleData.centerPos, scaleAmount, flipScale);
selectionTransformCoords.scale_about(scaleData.centerPos, WorldMultiplier(scaleAmount, flipScale));
}
}
else {
@ -313,9 +313,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 == CoordSpaceHelper())
else if(drawP.world.main.input.key(InputManager::KEY_COPY).pressed && startingSelectionTransformCoords == CoordSpaceHelperTransform())
selection_to_clipboard();
else if(drawP.world.main.input.key(InputManager::KEY_CUT).pressed && startingSelectionTransformCoords == CoordSpaceHelper()) {
else if(drawP.world.main.input.key(InputManager::KEY_CUT).pressed && startingSelectionTransformCoords == CoordSpaceHelperTransform()) {
selection_to_clipboard();
delete_all();
}
@ -448,7 +448,7 @@ void DrawingProgramSelection::reset_selection_data() {
}
void DrawingProgramSelection::reset_transform_data() {
selectionTransformCoords = CoordSpaceHelper();
selectionTransformCoords = CoordSpaceHelperTransform();
transformOpHappening = TransformOperation::NONE;
translateData = TranslationData();
scaleData = ScaleData();

View file

@ -1,5 +1,6 @@
#pragma once
#include "DrawingProgramCache.hpp"
#include "../CoordSpaceHelperTransform.hpp"
class DrawingProgram;
@ -40,7 +41,7 @@ class DrawingProgramSelection {
std::array<WorldVec, 4> selectionRectPoints;
CoordSpaceHelper selectionTransformCoords;
CoordSpaceHelperTransform selectionTransformCoords;
std::unordered_set<CollabListType::ObjectInfoPtr> selectedSet;
DrawingProgramCache cache;
DrawingProgram& drawP;
@ -53,7 +54,7 @@ class DrawingProgramSelection {
ROTATE
} transformOpHappening = TransformOperation::NONE;
CoordSpaceHelper startingSelectionTransformCoords;
CoordSpaceHelperTransform startingSelectionTransformCoords;
struct TranslationData {
WorldVec startPos;