Commit 7184fda7 authored by langurmonkey's avatar langurmonkey

feat: new cameraTransition() API call

New cameraTransition() creates a smooth transition between the current
camera and the target state {pos, dir, up} in the given amount of time.
A flag controls the synchronicity of the function.
parent 0b9e7b38
Pipeline #45455913 passed with stage
in 2 minutes and 12 seconds
......@@ -41,7 +41,7 @@ gs.setFov(49)
gs.goToObject("Earth", 91.38e-2)
print("We will now add a line between the Earth and Moon")
gs.print("We will now add a line between the Earth and Moon")
gs.sleep(2)
......@@ -63,7 +63,7 @@ gs.sleep(30)
gs.stopSimulationTime()
print("Cleaning up and ending")
gs.print("Cleaning up and ending")
gs.unparkRunnable("line-updater")
gs.removeModelObject("line-em")
......
......@@ -21,7 +21,7 @@ gs.sleep(3)
gs.addPolyline("Line1", [ 0.0, 0.0, 0.0, 1e9, 10.0, 200.0, 0.3, 6e9, 4444444.0 ], [ .2, .4, .8, .8 ], 1 )
gs.addPolyline("Line2", [ 0.0, 0.0, 0.0, 1e6, 7e8, 2000000.0, 0.99, 444444.0, 3e9 ], [ .9, .4, .3, .8 ], 2 )
print("Lines added")
gs.print("Lines added")
gs.sleep(3)
......@@ -31,7 +31,7 @@ gs.sleep(6)
gs.removeModelObject("Line1")
gs.removeModelObject("Line2")
print("Lines removed")
gs.print("Lines removed")
gs.cameraStop()
......
......@@ -11,23 +11,23 @@ gs.cameraStop()
gs.minimizeInterfaceWindow()
fname = "/home/tsagrista/.gaiasky/script/camera-path-test.gsc"
print("(1/2) Starting synchronous camera file execution: " + fname)
gs.print("(1/2) Starting synchronous camera file execution: %s" % fname)
t0 = time.time()
gs.runCameraPath(fname, True)
t1 = time.time()
print("Sync exec: script regained control after %.4f seconds" % (t1 - t0))
gs.print("Sync exec: script regained control after %.4f seconds" % (t1 - t0))
print("(2/2) Starting asynchronous camera file execution: " + fname)
gs.print("(2/2) Starting asynchronous camera file execution: %s" % fname)
t0 = time.time()
gs.runCameraPath(fname)
t1 = time.time()
print("Async exec: script regained control after %.4f seconds" % (t1 - t0))
gs.print("Async exec: script regained control after %.4f seconds" % (t1 - t0))
gs.maximizeInterfaceWindow()
gs.enableInput()
print("Script finishes")
gs.print("Script finishes")
......@@ -18,7 +18,7 @@ gs.goToObject(obj, 3.5)
rad = gs.getObjectRadius(obj)
print("%s radius: %f Km" % (obj, rad))
gs.print("%s radius: %f Km" % (obj, rad))
gs.sleep(1)
......@@ -27,7 +27,7 @@ absmag = body.getAbsmag()
appmag = body.getAppmag()
radec = body.getPosSph()
print("Absmag: %f, appmag: %f, RA: %f, DEC: %f" % (absmag, appmag, radec.x, radec.y))
gs.print("Absmag: %f, appmag: %f, RA: %f, DEC: %f" % (absmag, appmag, radec.x, radec.y))
# Now stop at a certain distance of earth
......
......@@ -8,7 +8,7 @@ gs = EventScriptingInterface.instance()
gs.disableInput()
gs.cameraStop()
print("Testing brightness")
gs.print("Testing brightness")
gs.setBrightnessLevel(-1.0)
gs.sleep(1)
......@@ -23,7 +23,7 @@ gs.sleep(1)
gs.setBrightnessLevel(0.0)
gs.sleep(1)
print("Testing contrast")
gs.print("Testing contrast")
gs.setContrastLevel(0.0)
gs.sleep(1)
......@@ -38,7 +38,7 @@ gs.sleep(1)
gs.setContrastLevel(1.0)
gs.sleep(1)
print("Testing hue")
gs.print("Testing hue")
gs.setHueLevel(0.0)
gs.sleep(1)
......@@ -53,7 +53,7 @@ gs.sleep(1)
gs.setHueLevel(1.0)
gs.sleep(1)
print("Testing saturation")
gs.print("Testing saturation")
gs.setSaturationLevel(0.0)
gs.sleep(1)
......@@ -68,7 +68,7 @@ gs.sleep(1)
gs.setSaturationLevel(1.0)
gs.sleep(1)
print("Check out of bounds parameter still works")
gs.print("Check out of bounds parameter still works")
gs.setContrastLevel(4.0)
gs.sleep(1)
gs.setContrastLevel(1.0)
......
......@@ -12,8 +12,8 @@ gs.stopSimulationTime()
gs.setCameraFocusInstantAndGo("Earth")
print("We will now add lines between Earth-Moon, Earth-Sol, Earth-Mercury and Arcturus-Achernar")
print("You will have 30 seconds to observe and explore the system before we remove the lines and end the script")
gs.print("We will now add lines between Earth-Moon, Earth-Sol, Earth-Mercury and Arcturus-Achernar")
gs.print("You will have 30 seconds to observe and explore the system before we remove the lines and end the script")
gs.sleep(2)
......@@ -29,11 +29,11 @@ gs.addPolyline("Line1", earthp + solp, [ .2, 1., .2, .8 ], 2 )
gs.addPolyline("Line2", earthp + mercuryp, [ 2., .2, 1., .8 ], 3 )
gs.addPolyline("Line3", arcturusp + achernarp, [ 1., 1., .2, .8 ], 2 )
print("Lines added, you have 30 seconds")
gs.print("Lines added, you have 30 seconds")
gs.sleep(30)
print("Removing lines and ending")
gs.print("Removing lines and ending")
gs.removeModelObject("Line0")
gs.removeModelObject("Line1")
gs.removeModelObject("Line2")
......
......@@ -6,7 +6,7 @@ from java.lang import Runnable
class PrintRunnable(Runnable):
def run(self):
print("I RUN!")
gs.print("I RUN!")
class FrameCounterRunnable(Runnable):
def __init__(self):
......@@ -15,7 +15,7 @@ class FrameCounterRunnable(Runnable):
def run(self):
self.n = self.n + 1
if self.n % 30 == 0:
print "Number of frames: %d" % self.n
gs.print("Number of frames: %d" % self.n)
gs = EventScriptingInterface.instance()
......@@ -32,5 +32,5 @@ gs.sleep(30.0)
# We unpark the frame counter
gs.unparkRunnable("frame_counter")
print "Exiting script"
gs.print("Exiting script")
......@@ -11,19 +11,19 @@ gs = EventScriptingInterface.instance()
gs.sleep(3)
print("360 mode")
gs.print("360 mode")
gs.set360Mode(True)
gs.sleep(3)
gs.set360Mode(False)
gs.sleep(3)
print("Planetarium mode")
gs.print("Planetarium mode")
gs.setPlanetariumMode(True)
gs.sleep(3)
gs.setPlanetariumMode(False)
gs.sleep(3)
print("Stereoscopic mode and profiles")
gs.print("Stereoscopic mode and profiles")
gs.setStereoscopicMode(True)
gs.sleep(3)
......
......@@ -28,8 +28,8 @@ while(gs.isSimulationTimeOn()):
sleep(0.2)
timearr = gs.getSimulationTimeArr()
print("%s - Time is: %i/%i/%i %i:%i:%i.%i" % (datetime.now().time(), timearr[2], timearr[1], timearr[0], timearr[3], timearr[4], timearr[5], timearr[6]))
print("%s - Time should be: 1/1/50000 10:05:00.000" % datetime.now().time())
gs.print("%s - Time is: %i/%i/%i %i:%i:%i.%i" % (datetime.now().time(), timearr[2], timearr[1], timearr[0], timearr[3], timearr[4], timearr[5], timearr[6]))
gs.print("%s - Time should be: 1/1/50000 10:05:00.000" % datetime.now().time())
gs.sleep(2)
# Back to 2017
......@@ -42,7 +42,7 @@ gs.startSimulationTime()
while(gs.isSimulationTimeOn()):
sleep(0.2)
print("Time should now be 1/12/2017 10:05:00.000")
gs.print("Time should now be 1/12/2017 10:05:00.000")
gs.sleep(2)
# Never forget to unset the target time, otherwise Gaia Sky will always stop at that time bookmark!
......
# This script tests the go-to commands. To be run asynchronously.
# Created by Toni Sagrista
from time import sleep
from gaia.cu9.ari.gaiaorbit.script import EventScriptingInterface
gs = EventScriptingInterface.instance()
gs.disableInput()
gs.cameraStop()
gs.minimizeInterfaceWindow()
gs.sleep(2)
# SYNC
gs.print("Starting SYNC transition that will last 15 seconds")
gs.cameraTransition([-3.755500744789524E11, -2.922083993465335E11, 1.177110695636744E12], [-0.07161522514290668, 0.26160383453064656, -0.9625147756198811], [0.22780313354328777, 0.9437774863679357, 0.2395616592296831], 15.0, True)
gs.print("Transition finalized")
gs.sleep(2)
# Back to Earth
gs.setCameraFocusInstantAndGo("Earth")
gs.sleep(2)
# ASYNC
gs.print("Starting ASYNC transition")
gs.cameraTransition([-3.755500744789524E11, -2.922083993465335E11, 1.177110695636744E12], [-0.07161522514290668, 0.26160383453064656, -0.9625147756198811], [0.22780313354328777, 0.9437774863679357, 0.2395616592296831], 5.0, False)
gs.print("Transition finalized")
gs.enableInput()
gs.maximizeInterfaceWindow()
gs.print("Script ended")
......@@ -15,7 +15,7 @@ gs.sleep(3)
gs.setCinematicCamera(True)
gs.cameraRotate(1.0, 0.0)
print("Bloom")
gs.print("Bloom")
gs.setBloom(100.0)
gs.sleep(4)
gs.setBloom(50.0)
......@@ -23,21 +23,21 @@ gs.sleep(4)
gs.setBloom(10.0)
gs.sleep(4)
print("Star glow")
gs.print("Star glow")
gs.setStarGlow(False)
gs.sleep(4)
gs.setStarGlow(True)
gs.sleep(4)
print("Motion blur")
gs.print("Motion blur")
gs.setMotionBlur(True)
gs.sleep(4)
gs.setMotionBlur(False)
gs.sleep(4)
print("Lens flare")
gs.print("Lens flare")
gs.setLensFlare(True)
gs.sleep(4)
gs.setLensFlare(False)
......
......@@ -1226,6 +1226,10 @@ public class NaturalCamera extends AbstractCamera implements IObserver {
return up;
}
public void setUp(Vector3d up){
this.up.set(up);
}
@Override
public Vector3d[] getDirections() {
return new Vector3d[]{direction};
......
......@@ -20,10 +20,7 @@ import gaia.cu9.ari.gaiaorbit.scenegraph.camera.NaturalCamera;
import gaia.cu9.ari.gaiaorbit.util.*;
import gaia.cu9.ari.gaiaorbit.util.Logger.Log;
import gaia.cu9.ari.gaiaorbit.util.coord.Coordinates;
import gaia.cu9.ari.gaiaorbit.util.math.Intersectord;
import gaia.cu9.ari.gaiaorbit.util.math.MathUtilsd;
import gaia.cu9.ari.gaiaorbit.util.math.Vector2d;
import gaia.cu9.ari.gaiaorbit.util.math.Vector3d;
import gaia.cu9.ari.gaiaorbit.util.math.*;
import gaia.cu9.ari.gaiaorbit.util.time.ITimeFrameProvider;
import java.time.Instant;
......@@ -777,6 +774,11 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
}
@Override
public void goToObjectInstant(String name){
setCameraFocusInstantAndGo(name);
}
@Override
public void landOnObject(String name) {
landOnObject(name, null);
......@@ -1227,7 +1229,7 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
em.post(Events.JAVA_EXCEPTION, e);
logger.error(e);
}
}
// Consume
......@@ -1241,7 +1243,7 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
em.post(Events.JAVA_EXCEPTION, e);
logger.error(e);
}
}
// Consume
......@@ -1254,7 +1256,7 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
em.post(Events.JAVA_EXCEPTION, e);
logger.error(e);
}
}
// Consume
......@@ -1317,7 +1319,7 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
@Override
public void expandGuiComponent(String name) {
IGui gui = GaiaSky.instance.mainGui;
ControlsWindow controls = (ControlsWindow) gui.getGuiStage().getRoot()
ControlsWindow controls = gui.getGuiStage().getRoot()
.findActor(I18n.bundle.get("gui.controlpanel"));
controls.getCollapsiblePane(name).expandPane();
}
......@@ -1325,7 +1327,7 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
@Override
public void collapseGuiComponent(String name) {
IGui gui = GaiaSky.instance.mainGui;
ControlsWindow controls = (ControlsWindow) gui.getGuiStage().getRoot()
ControlsWindow controls = gui.getGuiStage().getRoot()
.findActor(I18n.bundle.get("gui.controlpanel"));
controls.getCollapsiblePane(name).collapsePane();
}
......@@ -1343,7 +1345,7 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
em.post(Events.JAVA_EXCEPTION, e);
logger.error(e);
}
long spent = TimeUtils.millis() - iniTime;
if (timeoutMs > 0 && spent > timeoutMs) {
......@@ -1376,7 +1378,7 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
em.post(Events.JAVA_EXCEPTION, e);
logger.error(e);
}
}
Texture tex = manager.get(path, Texture.class);
......@@ -1437,6 +1439,110 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
runCameraPath(file, false);
}
class CameraTransitionRunnable implements Runnable {
NaturalCamera cam;
double seconds;
double elapsed;
double[] targetPos, targetDir, targetUp;
Pathd<Vector3d> posl, dirl, upl;
Runnable end;
Object lock;
Vector3d aux;
public CameraTransitionRunnable(NaturalCamera cam, double[] pos, double[] dir, double[] up, double seconds, Runnable end) {
this.cam = cam;
this.targetPos = pos;
this.targetDir = dir;
this.targetUp = up;
this.seconds = seconds;
this.elapsed = 0;
this.end = end;
this.lock = new Object();
// Set up interpolators
posl = getPathd(cam.getPos(), pos);
dirl = getPathd(cam.getDirection(), dir);
upl = getPathd(cam.getUp(), up);
// Aux
aux = new Vector3d();
}
private Pathd<Vector3d> getPathd(Vector3d p0, double[] p1) {
Vector3d[] points = new Vector3d[]{new Vector3d(p0), new Vector3d(p1[0], p1[1], p1[2])};
return new Lineard<>(points);
}
@Override
public void run() {
// Update elapsed time
elapsed += Gdx.graphics.getDeltaTime();
// Interpolation variable
double alpha = MathUtilsd.clamp(elapsed / seconds, 0.0, 0.99999999999999);
// Set camera state
cam.setPos(posl.valueAt(aux, alpha));
cam.setDirection(dirl.valueAt(aux, alpha));
cam.setUp(upl.valueAt(aux, alpha));
// Finish if needed
if (elapsed >= seconds) {
// On end, run runnable if present, otherwise notify lock
if (end != null) {
end.run();
} else {
synchronized (lock) {
lock.notify();
}
}
}
}
}
@Override
public void cameraTransition(double[] camPos, double[] camDir, double[] camUp, double seconds) {
cameraTransition(camPos, camDir, camUp, seconds, true);
}
private int cTransSeq = 0;
@Override
public void cameraTransition(double[] camPos, double[] camDir, double[] camUp, double seconds, boolean sync) {
NaturalCamera cam = GaiaSky.instance.cam.naturalCamera;
// Put in focus mode
em.post(Events.CAMERA_MODE_CMD, CameraMode.Free_Camera);
// Set up final actions
String name = "cameraTransition" + (cTransSeq++);
Runnable end = null;
if (!sync)
end = () -> {
unparkRunnable(name);
};
// Create and park runnable
CameraTransitionRunnable r = new CameraTransitionRunnable(cam, camPos, camDir, camUp, seconds, end);
parkRunnable(name, r);
if (sync) {
// Wait on lock
synchronized (r.lock) {
try {
r.lock.wait();
} catch (InterruptedException e) {
logger.error(e);
}
}
// Unpark and return
unparkRunnable(name);
}
}
@Override
public void sleep(float seconds) {
if (this.isFrameOutputActive()) {
......@@ -1445,7 +1551,7 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
try {
Thread.sleep(Math.round(seconds * 1000));
} catch (InterruptedException e) {
em.post(Events.JAVA_EXCEPTION, e);
logger.error(e);
}
}
......@@ -1459,7 +1565,7 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
em.post(Events.JAVA_EXCEPTION, e);
logger.error(e);
}
}
......@@ -1751,4 +1857,20 @@ public class EventScriptingInterface implements IScriptingInterface, IObserver {
});
}
@Override
public void print(String message) {
logger.info(message);
}
@Override
public void log(String message) {
logger.info(message);
}
@Override
public void error(String message) {
logger.error(message);
}
}
package gaia.cu9.ari.gaiaorbit.script;
import java.util.concurrent.atomic.AtomicBoolean;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
import gaia.cu9.ari.gaiaorbit.GaiaSky;
import gaia.cu9.ari.gaiaorbit.event.EventManager;
import gaia.cu9.ari.gaiaorbit.event.Events;
......@@ -12,6 +9,8 @@ import gaia.cu9.ari.gaiaorbit.event.IObserver;
import gaia.cu9.ari.gaiaorbit.scenegraph.CelestialBody;
import gaia.cu9.ari.gaiaorbit.scenegraph.IFocus;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* This guy implements high level operations which run concurrently to the main
* thread by starting new threads
......@@ -39,7 +38,7 @@ public class HiddenHelperUser implements IObserver {
private HiddenHelperUser() {
super();
currentTasks = new Array<HelperTask>(5);
currentTasks = new Array<>(5);
lastCommandTime = -1;
EventManager.instance.subscribe(this, Events.NAVIGATE_TO_OBJECT, Events.LAND_ON_OBJECT, Events.LAND_AT_LOCATION_OF_OBJECT, Events.INPUT_EVENT);
}
......
......@@ -233,7 +233,7 @@ public interface IScriptingInterface {
* Sets the camera in focus mode with the given focus object and instantly moves
* the camera next to the focus object.
*
* @param focusName
* @param focusName The name of the new focus object.
*/
void setCameraFocusInstantAndGo(final String focusName);
......@@ -811,6 +811,14 @@ public interface IScriptingInterface {
*/
void goToObject(String name, double viewAngle, float waitTimeSeconds);
/**
* Sets the camera in focus mode with the given focus object and instantly moves
* the camera next to the focus object.
*
* @param name The name of the new focus object.
*/
void goToObjectInstant(String name);
/**
* Lands on the object with the given name, if it is an instance of
* {@link gaia.cu9.ari.gaiaorbit.scenegraph.Planet}. The land location is
......@@ -1051,6 +1059,35 @@ public interface IScriptingInterface {
*/
void runCameraPath(String file, boolean sync);
/**
* Creates a smooth transition from the current camera state to the given camera state {camPos, camDir, camUp} in
* the given number of seconds. This function waits for the transition to finish and then returns control
* to the script.
* This function will put the camera in free mode, so make sure to change it afterwards if you need to. Also,
* this only works with the natural camera.
*
* @param camPos The target camera position in the internal reference system.
* @param camDir The target camera direction in the internal reference system.
* @param camUp The target camera up in the internal reference system.
* @param seconds The duration of the transition in seconds.
*/
void cameraTransition(double[] camPos, double[] camDir, double[] camUp, double seconds);
/**
* Creates a smooth transition from the current camera state to the given camera state {camPos, camDir, camUp} in
* the given number of seconds. Optionally, the transition may be run synchronously or asynchronously to the
* current script.
* This function will put the camera in free mode, so make sure to change it afterwards if you need to. Also,
* this only works with the natural camera.
*
* @param camPos The target camera position in the internal reference system.
* @param camDir The target camera direction in the internal reference system.
* @param camUp The target camera up in the internal reference system.
* @param seconds The duration of the transition in seconds.
* @param sync If true, the call waits for the transition to finish before returning, otherwise it returns immediately
*/
void cameraTransition(double[] camPos, double[] camDir, double[] camUp, double seconds, boolean sync);
/**
* Sleeps for the given number of seconds in the application time (FPS), so
* if we are capturing frames and the frame rate is set to 30 FPS, the
......@@ -1356,4 +1393,22 @@ public interface IScriptingInterface {
*/
double dot3(double[] vec1, double[] vec2);
/**
* Print text using the internal logging system
* @param message The message
*/
void print(String message);
/**
* Print text using the internal logging system
* @param message The message
*/
void log(String message);
/**
* Log an error using the internal logging system
* @param message The error message
*/
void error(String message);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment