Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
CityDoctor
CityDoctor2
Commits
24c5c355
Commit
24c5c355
authored
Jun 19, 2026
by
Matthias Betz
Browse files
Add OrbitCamera reproducing legacy view interaction
parent
10508066
Changes
2
Show whitespace changes
Inline
Side-by-side
CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/gl/OrbitCamera.java
0 → 100644
View file @
24c5c355
package
de.hft.stuttgart.citydoctor2.gui.gl
;
/**
* Orbit camera reproducing the legacy JavaFX interaction model: world is rotated about Z then X, the
* camera sits at {@code distance} along -Z (negative distance = farther away) and pans in X/Y.
*/
public
class
OrbitCamera
{
private
static
final
double
INITIAL_AZIMUTH
=
120.0
;
private
static
final
double
INITIAL_ELEVATION
=
20.0
;
private
static
final
double
INITIAL_DISTANCE
=
100.0
;
private
static
final
double
FOVY_RAD
=
Math
.
toRadians
(
30
);
private
static
final
float
NEAR
=
0.1f
;
private
static
final
float
FAR
=
10000
f
;
private
double
azimuthDeg
=
INITIAL_AZIMUTH
;
private
double
elevationDeg
=
INITIAL_ELEVATION
;
private
double
distance
=
INITIAL_DISTANCE
;
private
double
panX
=
0
;
private
double
panY
=
0
;
private
float
aspect
=
1.0f
;
public
void
setAspect
(
float
aspect
)
{
if
(
aspect
>
0
)
{
this
.
aspect
=
aspect
;
}
}
public
void
orbit
(
double
deltaAzimuthDeg
,
double
deltaElevationDeg
)
{
azimuthDeg
+=
deltaAzimuthDeg
;
elevationDeg
+=
deltaElevationDeg
;
}
public
void
pan
(
double
dx
,
double
dy
)
{
panX
+=
dx
;
panY
+=
dy
;
}
/** factor > 1 moves farther, < 1 moves closer. */
public
void
zoom
(
double
factor
)
{
distance
*=
factor
;
}
/** Matches legacy MainWindow.zoomOutForBoundingBox distance computation. */
public
void
zoomOutForBoundingBox
(
double
diagonalLength
)
{
double
longestSide
=
diagonalLength
*
0.4
;
distance
=
longestSide
/
Math
.
tan
(
FOVY_RAD
/
2.0
);
panX
=
0
;
panY
=
0
;
}
public
void
reset
()
{
azimuthDeg
=
INITIAL_AZIMUTH
;
elevationDeg
=
INITIAL_ELEVATION
;
distance
=
INITIAL_DISTANCE
;
panX
=
0
;
panY
=
0
;
}
public
double
distance
()
{
return
distance
;
}
/** Combined projection * view * model-rotation, column-major, ready for a GL uniform. */
public
float
[]
viewProjection
()
{
float
[]
proj
=
Mat4
.
perspective
((
float
)
FOVY_RAD
,
aspect
,
NEAR
,
FAR
);
float
[]
view
=
Mat4
.
translation
((
float
)
-
panX
,
(
float
)
-
panY
,
(
float
)
-
distance
);
float
[]
rot
=
Mat4
.
multiply
(
Mat4
.
rotationX
((
float
)
Math
.
toRadians
(
elevationDeg
)),
Mat4
.
rotationZ
((
float
)
Math
.
toRadians
(
azimuthDeg
)));
return
Mat4
.
multiply
(
proj
,
Mat4
.
multiply
(
view
,
rot
));
}
}
CityDoctorParent/Extensions/CityDoctorGUI/src/test/java/de/hft/stuttgart/citydoctor2/gui/gl/OrbitCameraTest.java
0 → 100644
View file @
24c5c355
package
de.hft.stuttgart.citydoctor2.gui.gl
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
org.junit.Test
;
public
class
OrbitCameraTest
{
private
static
float
[]
ndc
(
OrbitCamera
cam
,
float
x
,
float
y
,
float
z
)
{
float
[]
clip
=
Mat4
.
transform
(
cam
.
viewProjection
(),
x
,
y
,
z
,
1
);
return
new
float
[]{
clip
[
0
]
/
clip
[
3
],
clip
[
1
]
/
clip
[
3
],
clip
[
2
]
/
clip
[
3
]};
}
@Test
public
void
focusPointProjectsToScreenCentre
()
{
OrbitCamera
cam
=
new
OrbitCamera
();
cam
.
setAspect
(
1.0f
);
cam
.
zoomOutForBoundingBox
(
50.0
);
float
[]
p
=
ndc
(
cam
,
0
,
0
,
0
);
assertEquals
(
0
f
,
p
[
0
],
1
e
-
4
f
);
assertEquals
(
0
f
,
p
[
1
],
1
e
-
4
f
);
assertTrue
(
"origin in front of camera (within clip)"
,
p
[
2
]
>
-
1
f
&&
p
[
2
]
<
1
f
);
}
@Test
public
void
zoomingKeepsFocusCentredButChangesDepth
()
{
OrbitCamera
cam
=
new
OrbitCamera
();
cam
.
setAspect
(
1.0f
);
cam
.
zoomOutForBoundingBox
(
50.0
);
float
depthBefore
=
ndc
(
cam
,
0
,
0
,
0
)[
2
];
cam
.
zoom
(
1.5
);
float
[]
p
=
ndc
(
cam
,
0
,
0
,
0
);
assertEquals
(
0
f
,
p
[
0
],
1
e
-
4
f
);
assertEquals
(
0
f
,
p
[
1
],
1
e
-
4
f
);
assertTrue
(
"depth changes when zooming"
,
Math
.
abs
(
p
[
2
]
-
depthBefore
)
>
1
e
-
4
f
);
}
@Test
public
void
resetRestoresInitialDistanceAndAngles
()
{
OrbitCamera
cam
=
new
OrbitCamera
();
cam
.
setAspect
(
1.0f
);
cam
.
orbit
(
40
,
25
);
cam
.
pan
(
10
,
-
5
);
cam
.
zoom
(
2.0
);
cam
.
reset
();
float
[]
before
=
cam
.
viewProjection
();
OrbitCamera
fresh
=
new
OrbitCamera
();
fresh
.
setAspect
(
1.0f
);
org
.
junit
.
Assert
.
assertArrayEquals
(
fresh
.
viewProjection
(),
before
,
1
e
-
5
f
);
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment