/** * WeightedPoint.java * * Copyright (c) 2013-2016, F(X)yz * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of F(X)yz, any associated website, nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL F(X)yz BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.fxyz3d.shapes.complex.cloth; import java.util.HashMap; import org.fxyz3d.geometry.Point3D; /** * * @author Jason Pollastrini aka jdub1581 */ public class WeightedPoint { private final ClothMesh parent; public double mass = 0; public Point3D position, oldPosition, anchorPosition, force; private final HashMap<WeightedPoint, Constraint> constraints = new HashMap<>(); private boolean anchored = false, forceAffected = true; /*========================================================================== Constructors */ private WeightedPoint() { this.parent = null; } public WeightedPoint(ClothMesh parent) { this(parent, 0.1, 0, 0, 0, false); } public WeightedPoint(ClothMesh parent, double mass) { this(parent, mass, 0, 0, 0, false); } public WeightedPoint(ClothMesh parent, double mass, double x, double y, double z) { this(parent, mass, x, y, z, false); } public WeightedPoint(ClothMesh parent, double mass, double x, double y, double z, boolean anchored) { this.position = new Point3D((float) x, (float) y, (float) z); this.oldPosition = new Point3D((float) x, (float) y, (float) z); this.anchorPosition = new Point3D(0, 0, 0); this.force = new Point3D(0, 0, 0); this.parent = parent; this.mass = mass; this.anchored = anchored; } /*========================================================================== Constraints */ public final void attatchTo(WeightedPoint other, double linkDistance, double stiffness) { attatchTo(this, other, linkDistance, stiffness); } public final void attatchTo(WeightedPoint self, WeightedPoint other, double linkDistance, double stiffness) { Link pl = new Link(self, other, linkDistance, stiffness); addConstraint(other, (Constraint) pl); } //========================================================================== public HashMap<WeightedPoint, Constraint> getConstraints() { return constraints; } public void addConstraint(WeightedPoint other, Constraint constraint) { this.constraints.put(other, constraint); } public void addConstraint(Constraint c){ this.constraints.put(this, c); } public void removeConstraint(Constraint pl) { } public void clearConstraints() { constraints.clear(); } /*========================================================================== Updating */ public void solveConstraints() { constraints.values().parallelStream().forEach(Constraint::solve); } public void updatePhysics(double dt, double t) { synchronized (this) { if (isAnchored()) { setPosition(getAnchorPosition()); return; } Point3D vel = new Point3D( (position.x - oldPosition.x), (position.y - oldPosition.y), (position.z - oldPosition.z) ); float dtSq = (float) (dt * dt); // calculate the next position using Verlet Integration Point3D next = new Point3D( position.x + (vel.x + (((force.x / (float) (mass)) * 0.5f) * dtSq)), position.y + (vel.y + (((force.y / (float) (mass)) * 0.5f) * dtSq)), position.z + (vel.z + (((force.z / (float) (mass)) * 0.5f) * dtSq)) ); // reset variables setOldPosition(position); setPosition(next); clearForces(); //log.log(Level.INFO, "\n Velocity: {0}", vel); } } /*========================================================================== Variable's Getters / setters */ public double getMass() { return mass; } public void setMass(double mass) { this.mass = mass; } /*========================================================================== Positions */ public final Point3D getPosition() { return new Point3D(position.x, position.y, position.z); } public void setPosition(Point3D pos) { position.x = pos.x; position.y = pos.y; position.z = pos.z; } public void setPosition(double x, double y, double z) { position.x = (float) x; position.y = (float) y; position.z = (float) z; } //========================================================================== public Point3D getOldPosition() { return oldPosition; } public void setOldPosition(Point3D oldPosition) { this.oldPosition.x = oldPosition.x; this.oldPosition.y = oldPosition.y; this.oldPosition.z = oldPosition.z; } public void setOldPosition(float x, float y, float z) { this.oldPosition.x = x; this.oldPosition.y = y; this.oldPosition.z = z; } public void setOldPosition(double x, double y, double z) { this.oldPosition.x = (float) x; this.oldPosition.y = (float) y; this.oldPosition.z = (float) z; } //========================================================================== public boolean isAnchored() { return anchored; } public void setAnchored(boolean anchored) { this.anchored = anchored; if (anchored) { setAnchorPosition(new Point3D(position.x, position.y, position.z)); } else { setAnchorPosition(null); } } public Point3D getAnchorPosition() { return anchorPosition; } public void setAnchorPosition(Point3D anchorPosition) { this.anchorPosition = anchorPosition; } /*========================================================================== Forces */ public Point3D getForce() { return force; } private void setForce(Point3D p) { this.force = p; } public void applyForce(Point3D force) { if (isForceAffected()) { this.force.x += force.x; this.force.y += force.y; this.force.z += force.z; } } public void clearForces() { setForce(new Point3D(0, 0, 0)); } public boolean isForceAffected() { return forceAffected; } public void setForceAffected(boolean forceAffected) { this.forceAffected = forceAffected; } /*========================================================================== */ @Override public String toString() { return "WeightedPoint: ".concat(position.toString()); } }//End WeightedPoint========================================================