Commit c20d1eec authored by Nico Mack's avatar Nico Mack

Extended force package in order to generalize its use.

parent e892bfb1
......@@ -43,6 +43,7 @@ DRAW_PRIORITY_NODE=drawPriority
DURATION_NODE=duration
DYNAMIC_NODE=variableIsDynamic
EDGE_COLOUR_NODE=edgeColour
EFFECTIVITY_THRESHOLD_NODE=effectivityThreshold
EMPTY_STRING=
END_NODE=end
ENDING_NODE=ending
......@@ -87,10 +88,12 @@ LINE_HEIGHT_RATIO_NODE=lineHeightRatio
LINE_NODE=line
LINE_WIDTH_NODE=lineWidth
LOCATION_NODE=location
LONG_RANGE_NODE=longRange
LOOPING_NODE=looping
LOWER_BOUND_NODE=lowerBound
MAGNIFICATION_NODE=magnification
MAGNIFIER_SHAPE_NODE=magnifierShape
MAGNITUDE_NODE=magnitude
MARKER_BUILDER_NAMESPACE=lu.list.itis.dkd.tui.marker.builder
MARKER_NODE=marker
MARKERS_NODE=markers
......@@ -136,6 +139,7 @@ SHADE_EXTRA_BRIGHT_VALUE=extra bright
SHADE_EXTRA_DARK_VALUE=extra dark
SHADE_DARKER_VALUE=darker
SHAPE_NODE=shape
SHORT_RANGE_NODE=shortRange
SOUND_BASE64_NODE=soundBase64
SOUND_NODE=sound
SPACE=\
......
......@@ -78,6 +78,7 @@ public class Externalization extends NLS {
public static String DURATION_NODE;
public static String DYNAMIC_NODE;
public static String EDGE_COLOUR_NODE;
public static String EFFECTIVITY_THRESHOLD_NODE;
public static String EMPTY_STRING;
public static String END_NODE;
public static String ENDING_NODE;
......@@ -122,10 +123,12 @@ public class Externalization extends NLS {
public static String LINE_NODE;
public static String LINE_WIDTH_NODE;
public static String LOCATION_NODE;
public static String LONG_RANGE_NODE;
public static String LOOPING_NODE;
public static String LOWER_BOUND_NODE;
public static String MAGNIFICATION_NODE;
public static String MAGNIFIER_SHAPE_NODE;
public static String MAGNITUDE_NODE;
public static String MARKER_BUILDER_NAMESPACE;
public static String MARKER_NODE;
public static String MARKERS_NODE;
......@@ -171,6 +174,7 @@ public class Externalization extends NLS {
public static String SHADE_EXTRA_DARK_VALUE;
public static String SHADE_DARKER_VALUE;
public static String SHAPE_NODE;
public static String SHORT_RANGE_NODE;
public static String SOUND_BASE64_NODE;
public static String SOUND_NODE;
public static String SPACE;
......
......@@ -304,11 +304,9 @@ public class ForceDirectedGraph implements GraphListener, Runnable {
private synchronized void step(double timestep) {
List<Body> graphBodies = this.getGraphBodies();
List<Spring> graphSprings = this.getGraphSprings();
// Map<Body, List<Body>> graphNexus = this.getGraphNexus();
this.applyRepulsion(graphBodies);
this.applySprings(graphSprings);
// this.applyAngularSymetry(graphNexus);
this.coalesce(graphBodies);
this.updateVelocities(graphBodies, timestep);
this.updatePositions(graphBodies, timestep);
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. 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.widget.force;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapCallback;
import lu.list.itis.dkd.tui.bootstrapping.BootstrapContext;
import lu.list.itis.dkd.tui.bootstrapping.BootstrappingUtils;
import lu.list.itis.dkd.tui.exception.BuildException;
import lu.list.itis.dkd.tui.utility.Externalization;
import org.jdom2.Element;
/**
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class Force {
private double shortRange;
private double longRange;
private double magnitude;
private double effectivityThreshold;
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param magnitude
* @param shortRange
* @param longRange
* @param effectivityThreshold
*/
// ---------------------------------------------------------------------------
public Force(double magnitude, double shortRange, double longRange, double effectivityThreshold) {
this.magnitude = magnitude;
this.shortRange = shortRange;
this.longRange = longRange;
this.effectivityThreshold = effectivityThreshold;
}
// ---------------------------------------------------------------------------
/**
* @param forceElement
* @param bootstrapContext
* @param callback
* @throws BuildException
*/
// ---------------------------------------------------------------------------
public Force(Element forceElement, BootstrapContext bootstrapContext, BootstrapCallback callback) throws BuildException {
this.magnitude = BootstrappingUtils.getContentAsDouble(forceElement, Externalization.MAGNITUDE_NODE, BootstrappingUtils.MANDATORY, null, bootstrapContext);
this.shortRange = BootstrappingUtils.getContentAsDouble(forceElement, Externalization.SHORT_RANGE_NODE, BootstrappingUtils.MANDATORY, null, bootstrapContext);
this.longRange = BootstrappingUtils.getContentAsDouble(forceElement, Externalization.LONG_RANGE_NODE, BootstrappingUtils.MANDATORY, null, bootstrapContext);
this.effectivityThreshold = BootstrappingUtils.getContentAsDouble(forceElement, Externalization.EFFECTIVITY_THRESHOLD_NODE, BootstrappingUtils.OPTIONAL, 10e-1, bootstrapContext);
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* Simple getter method for shortRange.
*
* @return The value of shortRange.
*/
// ---------------------------------------------------------------------------
public double getShortRange() {
return shortRange;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for longRange.
*
* @return The value of longRange.
*/
// ---------------------------------------------------------------------------
public double getLongRange() {
return longRange;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for magnitude.
*
* @return The value of magnitude.
*/
// ---------------------------------------------------------------------------
public double getMagnitude() {
return magnitude;
}
// ---------------------------------------------------------------------------
/**
* Simple getter method for effectivityThreshold.
*
* @return The value of effectivityThreshold.
*/
// ---------------------------------------------------------------------------
public double getEffectivityThreshold() {
return effectivityThreshold;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
......@@ -31,11 +31,7 @@ public interface ForceGenerator {
public boolean isRepelling(ForceReactive potential);
public double getShortRange();
public double getLongRange();
public double getMagnitude();
public Force getGeneratedForce();
public Point getOrigin();
}
......@@ -42,9 +42,10 @@ import java.util.List;
// * Class Definition and Members *
// ***************************************************************************
public class ForceManager {
public class ForceManager implements Runnable {
private ForceGenerator generator;
private List<ForceReactive> potentialSubjects;
private List<Motionable> motionables;
// ***************************************************************************
// * Constants *
......@@ -67,6 +68,7 @@ public class ForceManager {
public ForceManager(ForceGenerator generator) {
this.generator = generator;
this.potentialSubjects = new ArrayList<>();
this.motionables = new ArrayList<>();
}
// ---------------------------------------------------------------------------
......@@ -99,6 +101,30 @@ public class ForceManager {
return force;
}
// ---------------------------------------------------------------------------
private void exertForce(Point origin, ForceReactive subject, Force generated) {
double shortRange = generated.getShortRange();
double longRange = generated.getLongRange();
double magnitude = generated.getMagnitude();
boolean isRepelling = this.generator.isRepelling(subject);
Point target = subject.getPosition().clone().toCoordinates(ScreenCoordinates.class);
Point distance = origin.clone().subtract(target, false);
double radius = distance.magnitude();
Vector2D force = null;
if (isRepelling && (radius < longRange)) {
force = this.repell(distance, magnitude, longRange);
} else if (!isRepelling && (radius > shortRange) && (radius < longRange)) {
force = this.attract(distance, magnitude, shortRange, longRange);
}
if ((force != null) && (force.magnitude() >= generated.getEffectivityThreshold())) {
subject.applyForce(force);
}
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
......@@ -118,6 +144,9 @@ public class ForceManager {
if (!this.potentialSubjects.contains(potential)) {
this.potentialSubjects.add(potential);
if (potential instanceof Motionable) {
this.motionables.add((Motionable) potential);
}
} else {
logger.warn("Attempt to add an already known ForceReactive object as a potential subject!"); //$NON-NLS-1$
}
......@@ -137,6 +166,7 @@ public class ForceManager {
if (this.potentialSubjects.contains(potential)) {
this.potentialSubjects.remove(potential);
this.motionables.remove(potential);
} else {
logger.warn("Attempt to remove an unknown ForceReactive object from list of potential subject!"); //$NON-NLS-1$
}
......@@ -152,28 +182,26 @@ public class ForceManager {
// ---------------------------------------------------------------------------
public void move(Point newPosition) {
double shortRange = this.generator.getShortRange();
double longRange = this.generator.getLongRange();
double magnitude = this.generator.getMagnitude();
Force generated = this.generator.getGeneratedForce();
Point origin = newPosition.toCoordinates(ScreenCoordinates.class);
for (ForceReactive subject : this.potentialSubjects) {
if (subject.getPosition() == null)
continue;
boolean isRepelling = this.generator.isRepelling(subject);
Point target = subject.getPosition().clone().toCoordinates(ScreenCoordinates.class);
Point distance = origin.clone().subtract(target, false);
double radius = distance.magnitude();
if (isRepelling && (radius < longRange)) {
subject.applyForce(this.repell(distance, magnitude, longRange));
} else if (!isRepelling && (radius > shortRange) && (radius < longRange)) {
subject.applyForce(this.attract(distance, magnitude, shortRange, longRange));
}
this.exertForce(origin, subject, generated);
}
}
// ---------------------------------------------------------------------------
/** {@inheritDoc} */
@Override
public void run() {
// TODO Auto-generated method stub
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of class *
......
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. 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.widget.force;
import lu.list.itis.dkd.tui.utility.Point;
import lu.list.itis.dkd.tui.utility.Vector2D;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class managing motion resulting from imparted forces. The class relies on Newton's first and
* second law of motion to determine acceleration and resulting velocity as a reaction to an applied
* force.
*
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
// ***************************************************************************
// * Class Definition and Members *
// ***************************************************************************
public class MotionManager {
private double mass;
private Vector2D acceleration;
private Vector2D velocity;
private static double damping = 0.5;
private static double maxSpeed = 10e5;
// ***************************************************************************
// * Constants *
// ***************************************************************************
private static final Logger LOGGER = LoggerFactory.getLogger(MotionManager.class.getSimpleName());
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Constructor(s) *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param mass
* specifies the inertial mass required to apply Newton's second law of motion.
*/
// ---------------------------------------------------------------------------
public MotionManager(double mass) {
this.mass = mass;
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * Class Body *
// ***************************************************************************
// ---------------------------------------------------------------------------
/**
* @param value
*/
// ---------------------------------------------------------------------------
@SuppressWarnings("squid:S3010") // Static fields should not be updated in constructors (squid:S3010)
public static void setDamping(double value) {
damping = value;
LOGGER.info("Damping globally set to {}", value); //$NON-NLS-1$
}
// ---------------------------------------------------------------------------
/**
* @param speed
*/
// ---------------------------------------------------------------------------
@SuppressWarnings("squid:S3010") // Static fields should not be updated in constructors (squid:S3010)
public static void setMaxSpeed(double speed) {
maxSpeed = speed;
LOGGER.info("Max Speed globally set to {}", speed); //$NON-NLS-1$
}
// ---------------------------------------------------------------------------
/**
* @param force
*/
// ---------------------------------------------------------------------------
public void applyForce(Vector2D force) {
this.acceleration = this.acceleration.add(force.divideBy(this.mass));
}
// ---------------------------------------------------------------------------
/**
* @param timestep
*/
// ---------------------------------------------------------------------------
public void updateVelocity(double timestep) {
Vector2D deltaV = this.acceleration.multiplyBy(timestep);
velocity = velocity.add(deltaV).multiplyBy(damping);
if (velocity.magnitude() > maxSpeed) {
velocity = velocity.normalize().multiplyBy(maxSpeed);
}
this.acceleration = new Vector2D();
}
// ---------------------------------------------------------------------------
/**
* @return Kinetic energy of body = 1/2 * m * v^2
*/
// ---------------------------------------------------------------------------
public double getKineticEnergy() {
double energy = 0;
double speed = velocity.magnitude();
energy = 0.5 * mass * speed * speed;
return energy;
}
// ---------------------------------------------------------------------------
/**
* @param position
* @param timestep
* @return
*/
// ---------------------------------------------------------------------------
public Point updatePosition(Point position, double timestep) {
Vector2D displacement = this.velocity.multiplyBy(timestep);
return new Point((float) (position.x + displacement.getX()), (float) (position.y + displacement.getY()), position.getAngle(), position.getState().getClass());
}
// ---------------------------------------------------------------------------
// ***************************************************************************
// * End of class *
// ***************************************************************************
// ---------------------------------------------------------------------------
}
/**
* Copyright Luxembourg Institute of Science and Technology, 2017. 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.widget.force;
import lu.list.itis.dkd.tui.utility.Point;
/**
* The Motionable interface extends the ForceReactive interface. The extension consists in adding
* methods required to update velocities and positions over time.
*
* @author Nico Mack [nico.mack@list.lu]
* @since 2.5
* @version 2.5.0
*/
public interface Motionable extends ForceReactive {
/**
* @param timestep
* specifies the timestep (delta-t) to be used for calculating the velocity change (delta-v).
*/
public void updateVelocity(double timestep);
/**
* @param position
* specifies the current position.
* @param timestep
* specifies the timestep (delta-t) to be used for calculating the corresponding
* displacement.
* @return a new copy of the initial position plus the displacement corresponding to the specified
* timestep (delta-t)
*/
public Point updatePosition(Point position, double timestep);
/**
* @return the kinetic energy of the body in motion.
*/
public double getKineticEnergy();
}
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