FreeCAD
1// SPDX-License-Identifier: LGPL-2.1-or-later
2
3/***************************************************************************
4* Copyright (c) 2023 Werner Mayer <wmayer[at]users.sourceforge.net> *
5* *
6* This file is part of FreeCAD. *
7* *
8* FreeCAD is free software: you can redistribute it and/or modify it *
9* under the terms of the GNU Lesser General Public License as *
10* published by the Free Software Foundation, either version 2.1 of the *
11* License, or (at your option) any later version. *
12* *
13* FreeCAD is distributed in the hope that it will be useful, but *
14* WITHOUT ANY WARRANTY; without even the implied warranty of *
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16* Lesser General Public License for more details. *
17* *
18* You should have received a copy of the GNU Lesser General Public *
19* License along with FreeCAD. If not, see *
20* <https://www.gnu.org/licenses/>. *
21* *
22**************************************************************************/
23
24#include "PreCompiled.h"25
26#include "Camera.h"27#include "Utilities.h"28
29using namespace Gui;30
31
32/**
33Formulas to get quaternion for axonometric views:
34
35\code
36from math import sqrt, degrees, asin, atan
37p1=App.Rotation(App.Vector(1,0,0),90)
38p2=App.Rotation(App.Vector(0,0,1),alpha)
39p3=App.Rotation(p2.multVec(App.Vector(1,0,0)),beta)
40p4=p3.multiply(p2).multiply(p1)
41
42from pivy import coin
43c=Gui.ActiveDocument.ActiveView.getCameraNode()
44c.orientation.setValue(*p4.Q)
45\endcode
46
47The angles alpha and beta depend on the type of axonometry
48Isometric:
49\code
50alpha=45
51beta=degrees(asin(-sqrt(1.0/3.0)))
52\endcode
53
54Dimetric:
55\code
56alpha=degrees(asin(sqrt(1.0/8.0)))
57beta=degrees(-asin(1.0/3.0))
58\endcode
59
60Trimetric:
61\code
62alpha=30.0
63beta=-35.0
64\endcode
65
66Verification code that the axonomtries are correct:
67
68\code
69from pivy import coin
70c=Gui.ActiveDocument.ActiveView.getCameraNode()
71vo=App.Vector(c.getViewVolume().getMatrix().multVecMatrix(coin.SbVec3f(0,0,0)).getValue())
72vx=App.Vector(c.getViewVolume().getMatrix().multVecMatrix(coin.SbVec3f(10,0,0)).getValue())
73vy=App.Vector(c.getViewVolume().getMatrix().multVecMatrix(coin.SbVec3f(0,10,0)).getValue())
74vz=App.Vector(c.getViewVolume().getMatrix().multVecMatrix(coin.SbVec3f(0,0,10)).getValue())
75(vx-vo).Length
76(vy-vo).Length
77(vz-vo).Length
78
79# Projection
80vo.z=0
81vx.z=0
82vy.z=0
83vz.z=0
84
85(vx-vo).Length
86(vy-vo).Length
87(vz-vo).Length
88\endcode
89
90See also:
91http://www.mathematik.uni-marburg.de/~thormae/lectures/graphics1/graphics_6_2_ger_web.html#1
92http://www.mathematik.uni-marburg.de/~thormae/lectures/graphics1/code_v2/Axonometric/qt/Axonometric.cpp
93https://de.wikipedia.org/wiki/Arkussinus_und_Arkuskosinus
94*/
95
96SbRotation Camera::top()97{
98return {0, 0, 0, 1};99}
100
101SbRotation Camera::bottom()102{
103return {1, 0, 0, 0};104}
105
106SbRotation Camera::front()107{
108auto root = sqrtf(2.0)/2.0f;109return {root, 0, 0, root};110}
111
112SbRotation Camera::rear()113{
114auto root = sqrtf(2.0)/2.0f;115return {0, root, root, 0};116}
117
118SbRotation Camera::right()119{
120return {0.5, 0.5, 0.5, 0.5};121}
122
123SbRotation Camera::left()124{
125return {-0.5, 0.5, 0.5, -0.5};126}
127
128SbRotation Camera::isometric()129{
130//from math import sqrt, degrees, asin131//p1=App.Rotation(App.Vector(1,0,0),45)132//p2=App.Rotation(App.Vector(0,0,1),-45)133//p3=p2.multiply(p1)134//return SbRotation(0.353553f, -0.146447f, -0.353553f, 0.853553f);135
136//from math import sqrt, degrees, asin137//p1=App.Rotation(App.Vector(1,0,0),90)138//p2=App.Rotation(App.Vector(0,0,1),135)139//p3=App.Rotation(App.Vector(-1,1,0),degrees(asin(-sqrt(1.0/3.0))))140//p4=p3.multiply(p2).multiply(p1)141//return SbRotation(0.17592, 0.424708, 0.820473, 0.339851);142
143//from math import sqrt, degrees, asin144//p1=App.Rotation(App.Vector(1,0,0),90)145//p2=App.Rotation(App.Vector(0,0,1),45)146//#p3=App.Rotation(App.Vector(1,1,0),45)147//p3=App.Rotation(App.Vector(1,1,0),degrees(asin(-sqrt(1.0/3.0))))148//p4=p3.multiply(p2).multiply(p1)149return {0.424708F, 0.17592F, 0.339851F, 0.820473F};150}
151
152SbRotation Camera::dimetric()153{
154return {0.567952F, 0.103751F, 0.146726F, 0.803205F};155}
156
157SbRotation Camera::trimetric()158{
159return {0.446015F, 0.119509F, 0.229575F, 0.856787F};160}
161
162SbRotation Camera::rotation(Camera::Orientation view)163{
164switch (view) {165case Top:166return top();167case Bottom:168return bottom();169case Front:170return front();171case Rear:172return rear();173case Right:174return right();175case Left:176return left();177case Isometric:178return isometric();179case Dimetric:180return dimetric();181case Trimetric:182return trimetric();183default:184return top();185}186}
187
188Base::Rotation Camera::convert(Camera::Orientation view)189{
190return convert(Camera::rotation(view));191}
192
193Base::Rotation Camera::convert(const SbRotation& rot)194{
195return Base::convertTo<Base::Rotation>(rot);196}
197
198SbRotation Camera::convert(const Base::Rotation& rot)199{
200return Base::convertTo<SbRotation>(rot);201}
202