private Point2D makeControlPoint(final double endX, final double endY, final Circle circle, final int numSegments, int direction) { final double controlPointDistance = (4.0 / 3.0) * Math.tan(Math.PI / (2 * numSegments)) * circle.getRadius(); final Point2D center = new Point2D(circle.getCenterX(), circle.getCenterY()); final Point2D end = new Point2D(endX, endY); Point2D perp = rotate(center, end, direction * Math.PI / 2.); Point2D diff = perp.subtract(end); diff = diff.normalize(); diff = scale(diff, controlPointDistance); return end.add(diff); }
Point2D p2 = segmentPoints.get(i + 1); Point2D tangent = p2.subtract(p1); Point2D q1 = p1.add(tangent.multiply(scale)); Point2D p0 = segmentPoints.get(i - 1); Point2D p1 = segmentPoints.get(i); Point2D tangent = p1.subtract(p0); Point2D q0 = p1.subtract(tangent.multiply(scale)); Point2D p1 = segmentPoints.get(i); Point2D p2 = segmentPoints.get(i + 1); Point2D tangent = p2.subtract(p0).normalize(); Point2D q0 = p1.subtract(tangent.multiply(scale * p1.subtract(p0).magnitude())); Point2D q1 = p1.add(tangent.multiply(scale * p2.subtract(p1).magnitude()));
Point2D currentPoint = initialPoints.get(i); Point2D nextPoint = initialPoints.get(i + 1); Point2D v1 = nextPoint.subtract(currentPoint); double max = currentPoint.distance(nextPoint); for (int j = i+1; j < initialPoints.size(); j++) { Point2D next = initialPoints.get(j); Point2D v2 = next.subtract(currentPoint); if (v1.angle(v2) < 1) { Point2D before = initialPoints.get(i - 1); Point2D next = initialPoints.get(i + 1); Point2D v1 = currentPoint.subtract(before); Point2D v2 = next.subtract(currentPoint); isCorner = v1.angle(v2) >= 1;
Point2D p1; Point2D p2; Point2D p3; Point2D p4; p1 = new Point2D(1, 1); p2 = new Point2D(10, 10); p3 = p2.subtract(p1); p4 = new Point2D(1, 0); System.out.println( "Point2D: " + p4.angle(p3));
private Shape polygon(Point2D[] points, Point2D boundsCenterLocal, Point2D bboxCenterLocal) { Vec2[] vertices = new Vec2[points.length]; for (int i = 0; i < vertices.length; i++) { vertices[i] = toVector(points[i].subtract(boundsCenterLocal)).subLocal(toVector(bboxCenterLocal)); } PolygonShape shape = new PolygonShape(); shape.set(vertices); return shape; }
/** * @param position the point to move towards * @param distance the distance to move */ public void translateTowards(Point2D position, double distance) { translate(position.subtract(getX(), getY()).normalize().multiply(distance)); }
private Shape chain(Point2D[] points, Point2D boundsCenterLocal, Point2D bboxCenterLocal) { Vec2[] vertices = new Vec2[points.length]; for (int i = 0; i < vertices.length; i++) { vertices[i] = toVector(points[i].subtract(boundsCenterLocal)).subLocal(toVector(bboxCenterLocal)); } ChainShape shape = new ChainShape(); shape.createLoop(vertices, vertices.length); return shape; }
private Shape polygon(Point2D[] points, Point2D boundsCenterLocal, Point2D bboxCenterLocal) { Vec2[] vertices = new Vec2[points.length]; for (int i = 0; i < vertices.length; i++) { vertices[i] = toVector(points[i].subtract(boundsCenterLocal)).subLocal(toVector(bboxCenterLocal)); } PolygonShape shape = new PolygonShape(); shape.set(vertices); return shape; }
private Shape chain(Point2D[] points, Point2D boundsCenterLocal, Point2D bboxCenterLocal) { Vec2[] vertices = new Vec2[points.length]; for (int i = 0; i < vertices.length; i++) { vertices[i] = toVector(points[i].subtract(boundsCenterLocal)).subLocal(toVector(bboxCenterLocal)); } ChainShape shape = new ChainShape(); shape.createLoop(vertices, vertices.length); return shape; }
private Point2D makeControlPoint(final double endX, final double endY, final Circle circle, final int numSegments, int direction) { final double controlPointDistance = (4.0 / 3.0) * Math.tan(Math.PI / (2 * numSegments)) * circle.getRadius(); final Point2D center = new Point2D(circle.getCenterX(), circle.getCenterY()); final Point2D end = new Point2D(endX, endY); Point2D perp = rotate(center, end, direction * Math.PI / 2.); Point2D diff = perp.subtract(end); diff = diff.normalize(); diff = scale(diff, controlPointDistance); return end.add(diff); }
/** * Calculate the point on the path that is at <code>frac</code>tion of the total length. * @param frac fraction of the total path in the range of [0,1] * @return new postition on the path, when moving to <code>frac</code> */ public Point2D interpolate(double frac) { Preconditions.checkArgument(frac >= 0 && frac <= 1, "Fraction must be between [0,1] inclusive. frac="+frac); double pathLengthToFrac = totalLength * frac; Preconditions.checkArgument(pathLengthToFrac >= currentSegment.getData().getLengthToStart() , "The path to the new position must be larger than the previous one"); moveCurrentSegment(frac); // the destination point is somewhere in currentSegment final LinearPathSegment data = currentSegment.getData(); double lengthIntoSegment = pathLengthToFrac - data.getLengthToStart(); double frationIntoSegment = lengthIntoSegment / data.getLength(); Point2D direction = data.getEnd().subtract(data.getStart()); // Vector from start to End Point2D newLocation = data.getStart().add(direction.multiply(frationIntoSegment)); traveldFraction = frac; if (traveldFraction > 1) { traveldFraction = 1; } LOGGER.trace("Interpolate path by {} to {}", frac, newLocation); return newLocation; }
@Override public Point2D getScenePosition() { Scene scene; if(source instanceof Node) { scene = ((Node) source).getScene(); } else if(source instanceof Scene) { scene = (Scene) source; } else { return null; } return screenPos.subtract( scene.getX() + scene.getWindow().getX(), scene.getY() + scene.getWindow().getY()); }
@Override public Point2D getScenePosition() { Scene scene; if(source instanceof Node) { scene = ((Node) source).getScene(); } else if(source instanceof Scene) { scene = (Scene) source; } else { return null; } return screenPos.subtract( scene.getX() + scene.getWindow().getX(), scene.getY() + scene.getWindow().getY()); }
/** * Moves the polygon in the direction specified.<br/> * Using this method is preferred over using the Node's setTranslate methods directory,<br/> * Because this method will also update the polygon's center position reference.<br/> * @param direction The direction of movement. * @param value The distance to move the polygon. */ public void move(Direction direction, double value) { if(UP == direction) { this.setTranslateY(this.getTranslateY() - value); this.getCenter().subtract(0d, value); } // END if if(DOWN == direction) { this.setTranslateY(this.getTranslateY() + value); this.getCenter().add(0d, value); } // END if if(LEFT == direction) { this.setTranslateX(this.getTranslateX() - value); this.getCenter().subtract(value, 0d); } // END if if(RIGHT == direction) { this.setTranslateX(this.getTranslateX() + value); this.getCenter().add(value, 0d); } // END if } // END move
/** * Moves the circle in the direction specified.<br/> * Using this method is preferred over using the Node's setTranslate methods directory,<br/> * Because this method will also update the circle's center position reference.<br/> * @param direction The direction of movement. * @param value The distance to move the circle. */ public void move(Direction direction, double value) { if(UP == direction) { this.setCenterY(this.getCenterY() - value); this.getCenter().subtract(0d, value); } // END if if(DOWN == direction) { this.setCenterY(this.getCenterY() + value); this.getCenter().add(0d, value); } // END if if(LEFT == direction) { this.setCenterX(this.getCenterX() - value); this.getCenter().subtract(value, 0d); } // END if if(RIGHT == direction) { this.setCenterX(this.getCenterX() + value); this.getCenter().add(value, 0d); } // END if } // END move } // END class Circle
/** * @return new emitter with implosion configuration */ public static ParticleEmitter newImplosionEmitter() { ParticleEmitter emitter = new ParticleEmitter(); emitter.setNumParticles(100); emitter.setEmissionRate(0.0166); emitter.setSize(5, 20); emitter.setSpawnPointFunction(i -> { Point2D vector = new Point2D(Math.cos(i), Math.sin(i)); return new Point2D(0, 0).add(vector.multiply(25)); }); emitter.setVelocityFunction(i -> { Point2D vector = new Point2D(Math.cos(i), Math.sin(i)); Point2D newPos = new Point2D(0, 0).add(vector.multiply(25)); return newPos.subtract(Point2D.ZERO).multiply(-0.05 * 60); }); emitter.setScaleFunction(i -> new Point2D(random() * -0.1, random() * -0.1)); emitter.setExpireFunction(i -> Duration.seconds(0.5)); emitter.setColor(Color.rgb((int) random(200, 255), 30, 20)); emitter.setBlendMode(BlendMode.ADD); return emitter; }
/** * @return new emitter with implosion configuration */ public static ParticleEmitter newImplosionEmitter() { ParticleEmitter emitter = new ParticleEmitter(); emitter.setNumParticles(100); emitter.setEmissionRate(0.0166); emitter.setSize(5, 20); emitter.setSpawnPointFunction(i -> { Point2D vector = new Point2D(Math.cos(i), Math.sin(i)); return new Point2D(0, 0).add(vector.multiply(25)); }); emitter.setVelocityFunction(i -> { Point2D vector = new Point2D(Math.cos(i), Math.sin(i)); Point2D newPos = new Point2D(0, 0).add(vector.multiply(25)); return newPos.subtract(Point2D.ZERO).multiply(-0.05 * 60); }); emitter.setScaleFunction(i -> new Point2D(random() * -0.1, random() * -0.1)); emitter.setExpireFunction(i -> Duration.seconds(0.5)); emitter.setColor(Color.rgb((int) random(200, 255), 30, 20)); emitter.setBlendMode(BlendMode.ADD); return emitter; }
/** * Computes a point with the same relative position in the specified new bounds as the specified old selection's * center point in the specified old bounds. (See * {@link #transformSelectionToNewBounds(Rectangle2D, Rectangle2D, Rectangle2D) transformSelectionToNewBounds} * for a definition of "relative position"). * * @param oldSelection * the selection whose center point is the base for the returned center point as a * {@link Rectangle2D} * @param oldBounds * the bounds of the old selection as a {@link Rectangle2D} * @param newBounds * the bounds for the new selection as a {@link Rectangle2D} * @return a {@link Point2D} with the same relative position in the new bounds as the old selection's center * point in the old bounds */ private Point2D computeNewSelectionCenter(Rectangle2D oldSelection, Rectangle2D oldBounds, Rectangle2D newBounds) { Point2D oldSelectionCenter = Rectangles2D.getCenterPoint(oldSelection); Point2D oldBoundsCenter = Rectangles2D.getCenterPoint(oldBounds); Point2D oldSelectionCenterOffset = oldSelectionCenter.subtract(oldBoundsCenter); double widthRatio = newBounds.getWidth() / oldBounds.getWidth(); double heightRatio = newBounds.getHeight() / oldBounds.getHeight(); Point2D newSelectionCenterOffset = new Point2D( oldSelectionCenterOffset.getX() * widthRatio, oldSelectionCenterOffset.getY() * heightRatio); Point2D newBoundsCenter = Rectangles2D.getCenterPoint(newBounds); Point2D newSelectionCenter = newBoundsCenter.add(newSelectionCenterOffset); return newSelectionCenter; }
private Shape createShape(HitBox box, Entity e) { // take world center bounds and subtract from entity center (all in pixels) to get local center // because box2d operates on vector offsets from the body center, also in local coordinates Point2D boundsCenterWorld = new Point2D((box.getMinXWorld() + box.getMaxXWorld()) / 2, (box.getMinYWorld() + box.getMaxYWorld()) / 2); Point2D boundsCenterLocal = boundsCenterWorld.subtract(e.getCenter()); double w = box.getMaxXWorld() - box.getMinXWorld(); double h = box.getMaxYWorld() - box.getMinYWorld(); BoundingShape boundingShape = box.getShape(); switch (boundingShape.type) { case CIRCLE: return circle(w, boundsCenterLocal); case POLYGON: if (boundingShape.data instanceof Dimension2D) { return polygonAsBox(w, h, boundsCenterLocal); } else { return polygon((Point2D[]) boundingShape.data, boundsCenterLocal, e.getBoundingBoxComponent().getCenterLocal()); } case CHAIN: if (e.getComponent(PhysicsComponent.class).body.getType() != BodyType.STATIC) { throw new IllegalArgumentException("BoundingShape.chain() can only be used with BodyType.STATIC"); } return chain((Point2D[]) boundingShape.data, boundsCenterLocal, e.getBoundingBoxComponent().getCenterLocal()); case EDGE: default: log.warning("Unsupported hit box shape"); throw new UnsupportedOperationException("Using unsupported shape: " + boundingShape.type); } }
private Shape createShape(HitBox box, Entity e) { Bounds bounds = box.translate(e.getX(), e.getY()); // take world center bounds and subtract from entity center (all in pixels) to get local center // because box2d operates on vector offsets from the body center, also in local coordinates Point2D boundsCenterWorld = new Point2D((bounds.getMinX() + bounds.getMaxX()) / 2, (bounds.getMinY() + bounds.getMaxY()) / 2); Point2D boundsCenterLocal = boundsCenterWorld.subtract(e.getCenter()); double w = bounds.getWidth(); double h = bounds.getHeight(); BoundingShape boundingShape = box.getShape(); switch (boundingShape.type) { case CIRCLE: return circle(w, boundsCenterLocal); case POLYGON: if (boundingShape.data instanceof Dimension2D) { return polygonAsBox(w, h, boundsCenterLocal); } else { return polygon((Point2D[]) boundingShape.data, boundsCenterLocal, e.getBoundingBoxComponent().getCenterLocal()); } case CHAIN: if (e.getComponent(PhysicsComponent.class).body.getType() != BodyType.STATIC) { throw new IllegalArgumentException("BoundingShape.chain() can only be used with BodyType.STATIC"); } return chain((Point2D[]) boundingShape.data, boundsCenterLocal, e.getBoundingBoxComponent().getCenterLocal()); case EDGE: default: log.warning("Unsupported hit box shape"); throw new UnsupportedOperationException("Using unsupported shape: " + boundingShape.type); } }