Skip to content

Commit

Permalink
Merge pull request #97 from prizrak9/independent-cross
Browse files Browse the repository at this point in the history
Independent cross
  • Loading branch information
pryvyd9 authored May 9, 2021
2 parents 749d1c3 + cecef1d commit 4a0bd11
Show file tree
Hide file tree
Showing 17 changed files with 932 additions and 809 deletions.
6 changes: 5 additions & 1 deletion CHANGE_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@
Now Release copies (CopyIfNewer) necessary files to output so the folder can be easily run from output or transferred to another pc and run there.
Added Publish configuration that cleans output before build and copies only necessary files without any debug symbols;
# 0.13.3
- property/event overhaul;
- property/event overhaul;
# 0.14
- introduced independent cross movement and rotation;
- isolated main math in separate static classes;
- fixed sine building when 2 points are at the same location;
182 changes: 10 additions & 172 deletions StereoPlus2/DomainTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "DomainUtils.hpp"
#include <glm/gtx/vector_angle.hpp>
#include <regex>
#include "Math.hpp"

class GroupObject : public SceneObject {
public:
Expand Down Expand Up @@ -224,30 +225,7 @@ class SineCurve : public LeafObject {
}

void updateCacheAsPolyLine(int from, int to) {
auto size = to - from;
std::vector<glm::vec3> vs;

for (size_t i = 0; i < size; i++)
vs.push_back(vertices[i + from]);

for (auto v : vs)
verticesCache.push_back(v);
}

glm::quat getRotation(glm::vec3 ac, glm::vec3 ab) {
auto zPlaneLocal = glm::cross(ac, ab);
zPlaneLocal = glm::normalize(zPlaneLocal);

auto zPlaneGlobal = glm::vec3(0, 0, 1);

auto r1 = glm::rotation(zPlaneGlobal, zPlaneLocal);

auto acRotatedBack = glm::rotate(glm::inverse(r1), ac);
acRotatedBack = glm::normalize(acRotatedBack);

auto r2 = glm::rotation(glm::vec3(1, 0, 0), acRotatedBack);
auto r = r1 * r2;
return r;
verticesCache.insert(verticesCache.end(), vertices.begin() + from, vertices.begin() + to);
}

/// <summary>
Expand Down Expand Up @@ -278,74 +256,16 @@ void UpdateCache() {
return;
}

size_t i = 0;

for (; i < vertices.size(); i += 2)
for (size_t i = 0; i < vertices.size(); i += 2)
{
if (i + 2 >= vertices.size())
{
updateCacheAsPolyLine(i + 1, vertices.size());
break;
}

auto ac = vertices[i + 2] - vertices[i];
auto ab = vertices[i + 1] - vertices[i];
auto bc = vertices[i + 2] - vertices[i + 1];

auto acUnit = glm::normalize(ac);
auto abadScalarProjection = glm::dot(ab, acUnit);
auto db = ab - acUnit * abadScalarProjection;
auto abdbScalarProjection = glm::dot(ab, glm::normalize(db));

if (isnan(abadScalarProjection) || isnan(abdbScalarProjection)) {
updateCacheAsPolyLine(i, i + 2);
break;
}

auto r = getRotation(ac, ab);

if (isnan(r.x) || isnan(r.y) || isnan(r.z) || isnan(r.w)) {
updateCacheAsPolyLine(i, i + 2);
break;
}

auto rotatedY = glm::rotate(r, glm::vec3(0, 1, 0));
auto sameDirection = glm::dot(glm::normalize(db), rotatedY) > 0;

auto acLength = glm::length(ac);
auto abLength = glm::length(ab);
auto bdLength = abdbScalarProjection;
auto adLength = abadScalarProjection;
auto dcLength = acLength - adLength;

static const auto hpi = 3.1415926 / 2.;

auto bcLength = glm::length(bc);

int abNumber = abLength / 5 + 1;
int bcNumber = bcLength / 5 + 1;

std::vector<glm::vec3> points;

for (size_t j = 0; j < abNumber; j++) {
auto x = -hpi + hpi * j / (float)abNumber;
auto nx = j / (float)abNumber * adLength;
auto ny = cos(x) * bdLength;
points.push_back(glm::vec3(nx, ny, 0));
}
for (size_t j = 0; j <= bcNumber; j++) {
auto x = hpi * j / (float)bcNumber;
auto nx = j / (float)bcNumber * dcLength + adLength;
auto ny = cos(x) * bdLength;
points.push_back(glm::vec3(nx, ny, 0));
}

if (!sameDirection)
for (size_t j = 0; j < points.size(); j++)
points[j].y = -points[j].y;

for (auto p : points)
verticesCache.push_back(glm::rotate(r, p) + vertices[i]);
auto points = Build::Sine(&vertices[i]);
verticesCache.insert(verticesCache.end(), points.begin(), points.end());
}

CascadeTransform(verticesCache);
Expand Down Expand Up @@ -826,93 +746,11 @@ class Camera : public LeafObject
return positionModifier + GetLocalPosition();
}

glm::vec3 getLeft(const glm::vec3& posMillimeters) {
auto pos = ConvertMillimetersToViewCoordinates(posMillimeters, ViewSize.Get(), viewSizeZ);
auto cameraPos = GetPos();
float denominator = cameraPos.z - pos.z;
return glm::vec3(
(pos.x * cameraPos.z - pos.z * (cameraPos.x - eyeToCenterDistance)) / denominator,
(cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator,
0
);
}
glm::vec3 getRight(const glm::vec3& posMillimeters) {
auto pos = ConvertMillimetersToViewCoordinates(posMillimeters, ViewSize.Get(), viewSizeZ);
auto cameraPos = GetPos();
float denominator = cameraPos.z - pos.z;
return glm::vec3(
(pos.x * cameraPos.z - pos.z * (cameraPos.x + eyeToCenterDistance)) / denominator,
(cameraPos.z * -pos.y + cameraPos.y * pos.z) / denominator,
0
);
}


Event<> onPropertiesChanged;

virtual void HandleBeforeUpdate() override {
onPropertiesChanged.Invoke();
}

// Millimeters to pixels
static glm::vec3 ConvertMillimetersToPixels(const glm::vec3& vMillimeters) {
static float inchToMillimeter = 0.0393701;
// vMillimiters[millimiter]
// inchToMillemeter[inch/millimeter]
// PPI[pixel/inch]
// vMillimiters*PPI*inchToMillemeter[millimeter*(pixel/inch)*(inch/millimeter) = millimeter*(pixel/millimeter) = pixel]
auto vPixels = Settings::PPI().Get() * inchToMillimeter * vMillimeters;
return vPixels;
}

// Millimeters to [-1;1]
// World center-centered
// (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates
static glm::vec3 ConvertMillimetersToViewCoordinates(const glm::vec3& vMillimeters, const glm::vec2& viewSizePixels, const float& viewSizeZMillimeters) {
static float inchToMillimeter = 0.0393701;
auto vsph = viewSizePixels / 2.f;
auto vszmh = viewSizeZMillimeters / 2.f;

auto vView = glm::vec3(
vMillimeters.x * Settings::PPI().Get() * inchToMillimeter / vsph.x,
vMillimeters.y * Settings::PPI().Get() * inchToMillimeter / vsph.y,
vMillimeters.z / vszmh
);
return vView;
}

// Millimeters to [-1;1]
// World center-centered
// (0;0;0) in view coordinates corresponds to (0;0;0) in world coordinates
static float ConvertMillimetersToViewCoordinates(const float& vMillimeters, const float& viewSizePixels) {
static float inchToMillimeter = 0.0393701;
auto vsph = viewSizePixels / 2.f;

auto vView = vMillimeters * Settings::PPI().Get() * inchToMillimeter / vsph;
return vView;
}


// Pixels to Millimeters
static glm::vec3 ConvertPixelsToMillimeters(const glm::vec3& vPixels) {
static float inchToMillimeter = 0.0393701;
// vPixels[pixel]
// inchToMillimeter[inch/millimeter]
// PPI[pixel/inch]
// vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter]
auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter;
return vMillimiters;
}
static glm::vec2 ConvertPixelsToMillimeters(const glm::vec2& vPixels) {
static float inchToMillimeter = 0.0393701;
// vPixels[pixel]
// inchToMillimeter[inch/millimeter]
// PPI[pixel/inch]
// vPixels/(PPI*inchToMillimeter)[pixel/((pixel/inch)*(inch/millimeter)) = pixel/(pixel/millimeter) = (pixel/pixel)*(millimeter) = millimiter]
auto vMillimiters = vPixels / Settings::PPI().Get() / inchToMillimeter;
return vMillimiters;
}

public:
// Pixels
ReadonlyProperty<glm::vec2> ViewSize;
Expand All @@ -925,9 +763,9 @@ class Camera : public LeafObject
Camera() {
Name = "camera";
EyeToCenterDistance.OnChanged() += [&](const float& v) {
eyeToCenterDistance = ConvertMillimetersToViewCoordinates(v, ViewSize->x); };
eyeToCenterDistance = Convert::MillimetersToViewCoordinates(v, ViewSize->x); };
PositionModifier.OnChanged() += [&](const glm::vec3& v) {
positionModifier = ConvertMillimetersToViewCoordinates(v, ViewSize.Get(), viewSizeZ); };
positionModifier = Convert::MillimetersToViewCoordinates(v, ViewSize.Get(), viewSizeZ); };

ViewSize.OnChanged() += [&](const glm::vec2 v) {
// Trigger conversion.
Expand All @@ -941,10 +779,10 @@ class Camera : public LeafObject
}

glm::vec3 GetLeft(const glm::vec3& v) {
return getLeft(v);
return Stereo::GetLeft(v, GetPos(), eyeToCenterDistance, ViewSize.Get(), viewSizeZ);
}
glm::vec3 GetRight(const glm::vec3& v) {
return getRight(v);
return Stereo::GetRight(v, GetPos(), eyeToCenterDistance, ViewSize.Get(), viewSizeZ);
}


Expand All @@ -957,7 +795,7 @@ class Camera : public LeafObject

ImGui::Extensions::PushActive(false);
ImGui::DragFloat2("view size", (float*)&ViewSize.Get());
auto viewSizeMillimeters = ConvertPixelsToMillimeters(ViewSize.Get());
auto viewSizeMillimeters = Convert::PixelsToMillimeters(ViewSize.Get());
ImGui::DragFloat2("view size millimeters", (float*)(&viewSizeMillimeters), 1, 0, 0, "%.1f");
ImGui::Extensions::PopActive();

Expand Down
134 changes: 0 additions & 134 deletions StereoPlus2/DomainUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,137 +281,3 @@ class DragDropBuffer {
}
};

class Transform {
// Trims angle to 360 degrees
static float trimAngle(float a) {
int b = a;
return b % 360 + (a - b);
}

// Trims angle to [-180;180] and converts to radian
static float convertToDeltaDegree(float a) {
return trimAngle(a) * 3.1415926f * 2 / 360;
}

// Get rotation angle around the axe.
// Calculates a simple sum of absolute values of angles from all axes,
// converts angle from radians to degrees
// and then trims it to 180 degrees.
static float getDirectedDeltaAngle(const glm::vec3& rotation) {
float angle = 0;
// Rotation axe determines the rotating direction
// so the rotation angles should be positive
for (auto i = 0; i < 3; i++)
angle += abs(rotation[i]);
return trimAngle(angle) * 3.1415926f * 2 / 360;
}

// Get rotation angle around the axe.
// Calculates a simple sum of absolute values of angles from all axes,
// trims angle to 180 degrees and then converts to radians
static bool tryGetLocalRotation(const glm::vec3& rotation, glm::vec3& axe, float& angle) {
glm::vec3 t[2] = { glm::vec3(), glm::vec3() };
float angles[2] = { 0, 0 };

// Supports rotation around 1,2 axes simultaneously.
auto modifiedAxeNumber = 0;
for (auto i = 0; i < 3; i++) {
assert(modifiedAxeNumber < 3);
if (rotation[i] != 0) {
t[modifiedAxeNumber][i] = rotation[i] > 0 ? 1 : -1;
angles[modifiedAxeNumber] = abs(rotation[i]);
modifiedAxeNumber++;
}
}

if (modifiedAxeNumber == 0) {
axe = glm::vec3();
return false;
}
if (modifiedAxeNumber == 1) {
angle = convertToDeltaDegree(angles[0]);
axe = t[0];
return true;
}

angle = convertToDeltaDegree(angles[0] + angles[1]);
axe = t[0] + t[1];
return true;
}

// Convert local rotation to global rotation relative to cross rotation.
//
// Shortly, Isolates rotation in cross' local space.
//
// Based on quaternion intransitivity, applying new local rotation and then applying inverted initial global rotation
// results in new local rotation being converted to global rotation.
// r0 * r1Local * r0^-1 = r1Global
//
// Basically, moves rotation initial point from (0;0;0;1) to cross global rotation.
// Compromises performance since cross new rotation is calculated both here and ourside of this method
// but improves readability and maintainability of the code.
static glm::quat getIsolatedRotation(const glm::quat& localRotation, const glm::quat crossGlobalRotation) {
auto crossNewRotation = crossGlobalRotation * localRotation;
auto rIsolated = crossNewRotation * glm::inverse(crossGlobalRotation);
return rIsolated;
}

public:
static void Scale(const glm::vec3& center, const float& oldScale, const float& scale, std::list<PON>& targets) {
for (auto target : targets) {
target->SetWorldPosition((target->GetWorldPosition() - center) / oldScale * scale + center);
for (size_t i = 0; i < target->GetVertices().size(); i++)
target->SetVertice(i, (target->GetVertices()[i] - center) / oldScale * scale + center);
}
}
static void Translate(const glm::vec3& transformVector, std::list<PON>& targets, SceneObject* cross) {
// Need to calculate average rotation.
// https://stackoverflow.com/questions/12374087/average-of-multiple-quaternions/27410865#27410865
if (Settings::SpaceMode().Get() == SpaceMode::Local) {
auto r = glm::rotate(cross->GetWorldRotation(), transformVector);

cross->SetWorldPosition(cross->GetWorldPosition() + r);
for (auto o : targets) {
o->SetWorldPosition(o->GetWorldPosition() + r);
for (size_t i = 0; i < o->GetVertices().size(); i++)
o->SetVertice(i, o->GetVertices()[i] + r);
}
return;
}

cross->SetWorldPosition(cross->GetWorldPosition() + transformVector);
for (auto o : targets) {
o->SetWorldPosition(o->GetWorldPosition() + transformVector);
for (size_t i = 0; i < o->GetVertices().size(); i++)
o->SetVertice(i, o->GetVertices()[i] + transformVector);
}
}
static void Rotate(const glm::vec3& center, const glm::vec3& rotation, std::list<PON>& targets, SceneObject* cross) {
glm::vec3 axe;
float angle;

if (!tryGetLocalRotation(rotation, axe, angle))
return;

auto r = glm::normalize(glm::angleAxis(angle, axe));

// Convert local rotation to global rotation.
// It is required to rotate all vertices since they don't store their own rotation
// meaning that their rotation = (0;0;0;1).
//
// When multiple objects are selected cross' rotation is equal to the first
// object in selection. See TransformTool::OnSelectionChanged
if (Settings::SpaceMode().Get() == SpaceMode::Local)
r = getIsolatedRotation(r, cross->GetWorldRotation());

cross->SetLocalRotation(r * cross->GetLocalRotation());

for (auto& target : targets) {
target->SetWorldPosition(glm::rotate(r, target->GetWorldPosition() - center) + center);
for (size_t i = 0; i < target->GetVertices().size(); i++)
target->SetVertice(i, glm::rotate(r, target->GetVertices()[i] - center) + center);

target->SetWorldRotation(r * target->GetWorldRotation());
}
}
};
Loading

0 comments on commit 4a0bd11

Please sign in to comment.