Commit 429b9e17 authored by Nico Mack's avatar Nico Mack

Started implementation of build-in TUIO Simulator

parent 6ddaf274
......@@ -166,11 +166,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
......@@ -281,6 +276,19 @@
<version>5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.illposed.osc</groupId>
<artifactId>javaosc-core</artifactId>
<version>0.7</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<reporting>
......
......@@ -495,6 +495,12 @@ TRIGGER_ELEMENT = trigger
TULIP_NAMESPACE = lu.list.itis.dkd.tui
TUIO_SIMULATOR_PROPERTY = tuio.simulator
TUIO_SIMULATOR_HOST_PROPERTY = tuio.simulator.host
TUIO_SIMULATOR_PORT_PROPERTY = tuio.simulator.port
TUIO_SIMULATOR_TRANSLATION_JITTER_PROPERTY = tuio.simulator.translation_jitter
TUIO_SIMULATOR_ROTATION_JITTER_PROPERTY = tuio.simulator.rotation_jitter
TYPE_ATTRIBUTE = type
TYPE_NODE = type
......
......@@ -25,6 +25,7 @@ import lu.list.itis.dkd.dbc.annotation.Nullable;
import lu.list.itis.dkd.tui.bootstrapping.BootstrappingUtils;
import lu.list.itis.dkd.tui.content.Stage;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.simulator.SimulatorOverlay;
import lu.list.itis.dkd.tui.utility.About;
import lu.list.itis.dkd.tui.utility.Calibration;
import lu.list.itis.dkd.tui.utility.CalibrationScreen;
......@@ -95,10 +96,7 @@ public class TangibleInterfaceManager extends Stage {
/** The URI of the calibration file as qualified from this file. */
protected String calibrationFileURI = "calibration.xml"; //$NON-NLS-1$
/** Field indicating whether the application should be shown full screen or not. */
// protected boolean fullscreen;
protected boolean splashShown;
/** Title of the frame visualising the application. */
private String title;
......@@ -106,13 +104,18 @@ public class TangibleInterfaceManager extends Stage {
/** Field indicating whether the interface is in calibration mode. */
protected boolean calibrationShown;
/** Index pointer used to switch between different configuration points. */
protected int configurationPoint = 0;
protected boolean splashShown;
protected boolean simulatorEnabled;
protected boolean simulatorShown;
private SplashScreen splashScreen;
private CalibrationScreen calibrationScreen;
private SimulatorOverlay simulatorOverlay;
private String aboutHtml;
private String helpHtml;
......@@ -149,6 +152,7 @@ public class TangibleInterfaceManager extends Stage {
this.bootstrap = bootstrap;
this.splashShown = false;
this.calibrationShown = false;
this.simulatorShown = false;
title = interfaceProperties.getProperty("frameTitle", "TangibleApplication"); //$NON-NLS-1$ //$NON-NLS-2$
transparent = Boolean.parseBoolean(interfaceProperties.getProperty(Externalization.TRANSPARENT_NODE, "False")); //$NON-NLS-1$
......@@ -159,6 +163,8 @@ public class TangibleInterfaceManager extends Stage {
}
Calibration.loadFromFile(calibrationFileURI);
simulatorEnabled = Boolean.parseBoolean(interfaceProperties.getProperty(Externalization.TUIO_SIMULATOR_PROPERTY, "False")); //$NON-NLS-1$
aboutHtml = this.renderAbout();
helpHtml = this.renderHelp();
......@@ -373,6 +379,15 @@ public class TangibleInterfaceManager extends Stage {
calibrationScreen.setHelp(helpHtml);
calibrationScreen.setVisible(false);
window.getContentPane().add(calibrationScreen);
if (simulatorEnabled) {
String tuioHost = interfaceProperties.getProperty(Externalization.TUIO_SIMULATOR_HOST_PROPERTY, "127.0.0.1"); //$NON-NLS-1$
int tuioPort = Integer.parseInt(interfaceProperties.getProperty(Externalization.TUIO_SIMULATOR_PORT_PROPERTY, "3333"));
simulatorOverlay = new SimulatorOverlay(tuioHost, tuioPort, Calibration.getScreenWidth(), Calibration.getScreenHeight());
simulatorOverlay.setVisible(false);
window.getContentPane().add(simulatorOverlay);
}
}
// ---------------------------------------------------------------------------
......@@ -408,6 +423,14 @@ public class TangibleInterfaceManager extends Stage {
}
break;
case KeyEvent.VK_S:
if (simulatorShown) {
hideSimulatorOverlay();
} else {
showSimulatorOverlay();
}
break;
default:
break;
}
......@@ -462,6 +485,25 @@ public class TangibleInterfaceManager extends Stage {
window.requestFocus();
}
// ---------------------------------------------------------------------------
protected void showSimulatorOverlay() {
if (this.simulatorOverlay != null) {
this.simulatorOverlay.setVisible(true);
this.simulatorShown = true;
}
}
// ---------------------------------------------------------------------------
protected void hideSimulatorOverlay() {
if (this.simulatorOverlay != null) {
this.simulatorOverlay.setVisible(false);
this.simulatorShown = false;
window.requestFocus();
}
}
// ---------------------------------------------------------------------------
/** Method used to destroy the current frame. */
// ---------------------------------------------------------------------------
......
package lu.list.itis.dkd.tui.simulator;
import lu.list.itis.dkd.tui.utility.Point;
import lu.list.itis.dkd.tui.utility.ScreenCoordinates;
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
/**
* @author mack
* @since [major].[minor]
* @version [major].[minor].[micro]
*/
public class Cursor {
private TangibleProperties properties;
private boolean isSticky;
// ***************************************************************************
// * Constant(s)
// ***************************************************************************
private static final double VICINITY = 7.0d;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
*
*/
// ---------------------------------------------------------------------------
public Cursor() {
this.properties = new TangibleProperties(false);
this.isSticky = false;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives
// ***************************************************************************
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
public boolean touchedBy(Point position) {
Point centre = this.properties.getPosition();
centre = centre.toCoordinates(ScreenCoordinates.class);
return (centre.subtract(position, false).magnitude() < VICINITY);
}
// ---------------------------------------------------------------------------
public TangibleProperties getProperties() {
return this.properties;
}
// ---------------------------------------------------------------------------
public boolean isSticky() {
return this.isSticky;
}
// ---------------------------------------------------------------------------
public void setSticky(boolean makeSticky) {
this.isSticky = makeSticky;
}
// ---------------------------------------------------------------------------
/**
* @param position
* @param sessionId
*/
// ---------------------------------------------------------------------------
public void drop(Point position, int sessionId) {
this.properties.setSessionId(sessionId);
this.properties.setPosition(position);
}
// ---------------------------------------------------------------------------
/**
* @param position
*/
// ---------------------------------------------------------------------------
public void move(Point position) {
if (this.properties != null) {
this.properties.setPosition(position);
}
}
// ---------------------------------------------------------------------------
/**
*
*/
// ---------------------------------------------------------------------------
public void lift() {
if (this.properties != null) {
this.properties.reset();
}
}
// ---------------------------------------------------------------------------
/**
*
*/
// ---------------------------------------------------------------------------
public final void stop() {
this.properties.stop();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class
// ***************************************************************************
// ---------------------------------------------------------------------------
}
\ No newline at end of file
This diff is collapsed.
package lu.list.itis.dkd.tui.simulator;
import lu.list.itis.dkd.tui.utility.Point;
import lu.list.itis.dkd.tui.utility.ScreenCoordinates;
import lu.list.itis.dkd.tui.widget.corona.ShapeFactory;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
/**
* @author mack
* @since [major].[minor]
* @version [major].[minor].[micro]
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class Tangible {
private int fiducialId;
private boolean isActive;
private Shape shape;
private Shape transformedShape;
private TangibleProperties properties;
// ***************************************************************************
// * Constants
// ***************************************************************************
private static final int HASH_SEED = 17;
private static final int HASH_VALUE = 67;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param fiducialId
*/
// ---------------------------------------------------------------------------
public Tangible(int fiducialId) {
this.fiducialId = fiducialId;
this.properties = new TangibleProperties(true);
this.shape = ShapeFactory.buildRoundedSquare(50);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives
// ***************************************************************************
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param position
* @return
*/
// ---------------------------------------------------------------------------
public boolean touchedBy(Point position) {
return (transformedShape != null)
? transformedShape.contains(position.toCoordinates(ScreenCoordinates.class))
: false;
}
// ---------------------------------------------------------------------------
public TangibleProperties getProperties() {
return this.properties;
}
// ---------------------------------------------------------------------------
public int getFiducialId() {
return this.fiducialId;
}
// ---------------------------------------------------------------------------
public boolean isActive() {
return this.isActive;
}
// ---------------------------------------------------------------------------
/**
* @param position
* @param sessionId
*/
// ---------------------------------------------------------------------------
public void drop(Point position, int sessionId) {
this.properties.setSessionId(sessionId);
this.properties.setPosition(position);
this.isActive = true;
}
// ---------------------------------------------------------------------------
/**
* @param position
*/
// ---------------------------------------------------------------------------
public void move(Point position) {
if (this.isActive) {
this.properties.setPosition(position);
}
}
// ---------------------------------------------------------------------------
/**
* @param position
* @param sessionId
*/
// ---------------------------------------------------------------------------
public void lift() {
this.properties.reset();
this.isActive = false;
}
// ---------------------------------------------------------------------------
/**
*
*/
// ---------------------------------------------------------------------------
public final void reset() {
this.properties.reset();
}
// ---------------------------------------------------------------------------
/**
*
*/
// ---------------------------------------------------------------------------
public final void stop() {
this.properties.stop();
}
// ---------------------------------------------------------------------------
/**
* @param canvas
*/
// ---------------------------------------------------------------------------
public void paint(Graphics2D canvas) {
if (!this.isActive) {
return;
}
Graphics2D localCanvas = (Graphics2D) canvas.create();
Point centre = this.properties.getPosition().clone();
centre = centre.toCoordinates(ScreenCoordinates.class);
AffineTransform transform = AffineTransform.getTranslateInstance(centre.x, centre.y);
transform.rotate(centre.getAngle());
transformedShape = transform.createTransformedShape(this.shape);
localCanvas.setColor(Color.WHITE);
localCanvas.draw(transformedShape);
localCanvas.dispose();
}
// ---------------------------------------------------------------------------
@Override
public boolean equals(Object other) {
boolean isEqual = false;
if (other instanceof Tangible) {
Tangible tangible = (Tangible) other;
isEqual = this.getFiducialId() == tangible.getFiducialId();
isEqual &= this.getProperties().getSessionId() == tangible.getProperties().getSessionId();
}
return isEqual;
}
// ---------------------------------------------------------------------------
@Override
public int hashCode() {
int hash = HASH_SEED;
hash *= HASH_VALUE * Integer.hashCode(this.getFiducialId());
hash *= HASH_VALUE * Integer.hashCode(this.getProperties().getSessionId());
return hash;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of Class
// ***************************************************************************
// ---------------------------------------------------------------------------
}
\ No newline at end of file
/**
* Copyright Luxembourg Institute of Science and Technology, 2020. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, version 3 of the
* License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.simulator;
import lu.list.itis.dkd.tui.utility.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author mack
* @since [major].[minor]
* @version [major].[minor].[micro]
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class TangibleManager {
private Map<Integer, Cursor> cursorList;
private Map<Integer, Tangible> objectList;
private List<Integer> cursorSessionIds;
private List<Integer> objectSessionIds;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
public TangibleManager() {
this.cursorList = new ConcurrentHashMap<>();
this.objectList = new ConcurrentHashMap<>();
this.cursorSessionIds = new ArrayList<>();
this.objectSessionIds = new ArrayList<>();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitives
// ***************************************************************************
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param sessionId
* @param object
* @return
*/
// ---------------------------------------------------------------------------
public int addObject(int sessionId, Tangible object) {
if (!this.objectList.containsValue(object)) {
object.getProperties().setSessionId(sessionId);
this.objectList.put(sessionId, object);
this.objectSessionIds.add(sessionId);
}
return sessionId - 1;
}
// ---------------------------------------------------------------------------
public Collection<Cursor> getCursors() {
return this.cursorList.values();
}
// ---------------------------------------------------------------------------
public Collection<Tangible> getObjects() {
return this.objectList.values();
}
// ---------------------------------------------------------------------------
public List<Integer> getCursorSessionIds() {
return this.cursorSessionIds;
}
// ---------------------------------------------------------------------------
public List<Integer> getObjectSessionIds() {
return this.objectSessionIds;
}
// ---------------------------------------------------------------------------
public void reset() {
this.cursorList.clear();
this.cursorSessionIds.clear();
this.objectList.clear();
this.objectSessionIds.clear();
}
// ---------------------------------------------------------------------------
/**
* @param object
* @param position
* @return
*/
// ---------------------------------------------------------------------------
public int dropObject(Tangible object, Point position) {
int sessionId = object.getProperties().getSessionId();
if (objectList.containsKey(sessionId)) {
Tangible tangible = objectList.get(sessionId);
if (!tangible.isActive()) {
objectList.remove(sessionId);
int index = objectSessionIds.indexOf(sessionId);
if (index >= 0) {
objectSessionIds.remove(index);
}
sessionId++;
tangible.drop(position, sessionId);
objectList.put(sessionId, tangible);
objectSessionIds.add(sessionId);
}
}
return sessionId;
}
// ---------------------------------------------------------------------------
public void moveObject(Tangible object, Point position) {
if (object.isActive()) {
object.move(position);
}
}
// ---------------------------------------------------------------------------
public void liftObject(Tangible object) {
if (object.isActive()) {
object.lift();
}
}
// ---------------------------------------------------------------------------
public Cursor dropCursor(int sessionId, Point position) {
int newSessionId = sessionId + 1;
Cursor cursor = new Cursor();
cursor.drop(position, newSessionId);
cursorList.put(newSessionId, cursor);
this.cursorSessionIds.add(newSessionId);
return cursor;
}
// ---------------------------------------------------------------------------
public void moveCursor(Cursor cursor, Point position) {
cursor.move(position);
}
// ---------------------------------------------------------------------------
public void liftCursor(Cursor cursor) {
int sessionId = cursor.getProperties().getSessionId();
cursor.lift();
this.cursorList.remove(sessionId);
this.cursorSessionIds.remove(sessionId);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2020. All rights reserved.
*
* This file is part of TULIP.
*
* TULIP is free software: you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation, version 3 of the
* License.
*
* TULIP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with TULIP. If
* not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package lu.list.itis.dkd.tui.simulator;
import lu.list.itis.dkd.tui.utility.AngleUtils;
import lu.list.itis.dkd.tui.utility.NormalizedCoordinates;
import lu.list.itis.dkd.tui.utility.Point;
import lu.list.itis.dkd.tui.utility.ScreenCoordinates;
/**
* @author mack
* @since [major].[minor]
* @version [major].[minor].[micro]
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class TangibleProperties {
private int sessionId;
private Point position;
private boolean doesRotate;
private float xSpeed;
private float ySpeed;
private float transAcceleration;
private float transSpeed;
private float rotAcceleration;
private float rotSpeed;
private long lastTime;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param doesRotate
*/
// ---------------------------------------------------------------------------
public TangibleProperties(boolean doesRotate) {
this.doesRotate = doesRotate;
this.reset();
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Primitive(s)
// ***************************************************************************
// ---------------------------------------------------------------------------
private void rotate(float theta, float deltaTinSeconds) {
double deltaTheta = (float) AngleUtils.wrapTwoPi(theta) / AngleUtils.TWO_PI;
float newSpeed = (float) (deltaTheta / deltaTinSeconds);
this.rotAcceleration = (newSpeed - this.rotSpeed) / deltaTinSeconds;
this.rotSpeed = newSpeed;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
*
*/
// ---------------------------------------------------------------------------
public void reset() {
this.position = null;
this.stop();
}
// ---------------------------------------------------------------------------
/**
*
*/
// ---------------------------------------------------------------------------
public void stop() {
this.xSpeed = 0.0f;
this.ySpeed = 0.0f;
this.transAcceleration = 0.0f;
this.transSpeed = 0.0f;
this.rotAcceleration = 0.0f;
this.rotSpeed = 0.0f;
this.lastTime = System.currentTimeMillis();
}
// ---------------------------------------------------------------------------
public void setSessionId(int sessionId) {
this.sessionId = sessionId;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for sessionId.
*
* @return The value of sessionId.
*/
// ---------------------------------------------------------------------------
public int getSessionId() {
return sessionId;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for position.
*
* @return The value of position.
*/
// ---------------------------------------------------------------------------
public Point getPosition() {
return this.position;
}
// ---------------------------------------------------------------------------
/**
* Simple setter method for position.
*
* @param position
* The value to set position to.
*/
// ---------------------------------------------------------------------------
public void setPosition(Point position) {
long currentTime = System.currentTimeMillis();
long elapsed = currentTime - lastTime;
float deltaTinSeconds = elapsed / 1000.0f;
if (deltaTinSeconds > 0) {
Point lastPosition = getPosition();
if (lastPosition != null) {
lastPosition.clone();
lastPosition.toCoordinates(ScreenCoordinates.class);
}
Point newPosition = position.toCoordinates(ScreenCoordinates.class);
Point offset = newPosition.subtract(lastPosition, this.doesRotate).toCoordinates(NormalizedCoordinates.class);
float newSpeed = (float) (offset.magnitude() / deltaTinSeconds);
this.xSpeed = offset.x / deltaTinSeconds;
this.ySpeed = offset.y / deltaTinSeconds;
this.transAcceleration = (newSpeed - this.transSpeed) / deltaTinSeconds;
this.transSpeed = newSpeed;
if (this.doesRotate) {
this.rotate(offset.getAngle(), deltaTinSeconds);
}
this.position = newPosition;
}
lastTime = currentTime;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for xSpeed.
*
* @return The value of xSpeed.
*/
// ---------------------------------------------------------------------------
public float getxSpeed() {
return xSpeed;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for ySpeed.
*
* @return The value of ySpeed.
*/
// ---------------------------------------------------------------------------
public float getySpeed() {
return ySpeed;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for transAcceleration.
*
* @return The value of transAcceleration.
*/
// ---------------------------------------------------------------------------
public float getTransAcceleration() {
return transAcceleration;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for transSpeed.
*
* @return The value of transSpeed.
*/
// ---------------------------------------------------------------------------
public float getTransSpeed() {
return transSpeed;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for rotAcceleration.
*
* @return The value of rotAcceleration.
*/
// ---------------------------------------------------------------------------
public float getRotAcceleration() {
return rotAcceleration;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for rotSpeed.
*
* @return The value of rotSpeed.
*/
// ---------------------------------------------------------------------------
public float getRotSpeed() {
return rotSpeed;
}
}
This diff is collapsed.
......@@ -337,6 +337,11 @@ public class Externalization extends NLS {
public static String TRIGGER_CONDITION_NODE;
public static String TRIGGER_ELEMENT;
public static String TRIGGERS_NODE;
public static String TUIO_SIMULATOR_PROPERTY;
public static String TUIO_SIMULATOR_HOST_PROPERTY;
public static String TUIO_SIMULATOR_PORT_PROPERTY;
public static String TUIO_SIMULATOR_TRANSLATION_JITTER_PROPERTY;
public static String TUIO_SIMULATOR_ROTATION_JITTER_PROPERTY;
public static String TULIP_NAMESPACE;
public static String TYPE_NODE;
public static String TYPE_ATTRIBUTE;
......
......@@ -34,7 +34,7 @@ import com.google.common.base.Preconditions;
*/
public class NormalizedCoordinates extends CoordinateState {
private static final Bounds2D BOUNDS = new Bounds2D(0, 0, 1, 1);
private static final Bounds2D BOUNDS = new Bounds2D(-1, -1, 1, 1);
/**
* Constructing an instance with the provided points.
......@@ -93,8 +93,8 @@ public class NormalizedCoordinates extends CoordinateState {
/** {@inheritDoc} */
@Override
public Point transform(Point normalized) {
Preconditions.checkArgument((normalized.x >= 0) && (normalized.x <= 1));
Preconditions.checkArgument((normalized.y >= 0) && (normalized.y <= 1));
Preconditions.checkArgument((normalized.x >= -1) && (normalized.x <= 1));
Preconditions.checkArgument((normalized.y >= -1) && (normalized.y <= 1));
return normalized.clone();
}
......
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