org.hipparchus.samples.geometry.GeometryExample Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hipparchus-samples Show documentation
Show all versions of hipparchus-samples Show documentation
The Hipparchus samples module
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This is not the original file distributed by the Apache Software Foundation
* It has been modified by the Hipparchus project
*/
package org.hipparchus.samples.geometry;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import org.hipparchus.geometry.enclosing.Encloser;
import org.hipparchus.geometry.enclosing.EnclosingBall;
import org.hipparchus.geometry.enclosing.WelzlEncloser;
import org.hipparchus.geometry.euclidean.twod.DiskGenerator;
import org.hipparchus.geometry.euclidean.twod.Euclidean2D;
import org.hipparchus.geometry.euclidean.twod.Segment;
import org.hipparchus.geometry.euclidean.twod.Vector2D;
import org.hipparchus.geometry.euclidean.twod.hull.ConvexHull2D;
import org.hipparchus.geometry.euclidean.twod.hull.ConvexHullGenerator2D;
import org.hipparchus.geometry.euclidean.twod.hull.MonotoneChain;
import org.hipparchus.random.MersenneTwister;
import org.hipparchus.random.RandomGenerator;
import org.hipparchus.samples.ExampleUtils;
import org.hipparchus.samples.ExampleUtils.ExampleFrame;
import org.hipparchus.util.FastMath;
import org.hipparchus.util.SinCos;
import org.piccolo2d.PCamera;
import org.piccolo2d.PCanvas;
import org.piccolo2d.PNode;
import org.piccolo2d.event.PBasicInputEventHandler;
import org.piccolo2d.event.PInputEvent;
import org.piccolo2d.event.PMouseWheelZoomEventHandler;
import org.piccolo2d.nodes.PPath;
import org.piccolo2d.nodes.PText;
/**
* Simple example illustrating some parts of the geometry package.
*
* TODO:
* - select tolerance level
* - allow editing of the point set
*/
//CHECKSTYLE: stop HideUtilityClassConstructor
public class GeometryExample {
/** Tooltip. */
private static final String TOOLTIP = "tooltip";
/** Empty constructor.
*
* This constructor is not strictly necessary, but it prevents spurious
* javadoc warnings with JDK 18 and later.
*
* @since 3.0
*/
public GeometryExample() { // NOPMD - unnecessary constructor added intentionally to make javadoc happy
// nothing to do
}
/** Create a list of random points.
* @param size number of points
* @return random points
*/
public static List createRandomPoints(int size) {
RandomGenerator random = new MersenneTwister();
// create the cloud container
List points = new ArrayList(size);
// fill the cloud with a random distribution of points
for (int i = 0; i < size; i++) {
points.add(new Vector2D(FastMath.round(random.nextDouble() * 400 + 100),
FastMath.round(random.nextDouble() * 400 + 100)));
}
return points;
}
/** Create a circle sprite.
* @param samples number of points
* @return vectors describing the sprite
*/
public static List createCircle(int samples) {
List points = new ArrayList();
final Vector2D center = new Vector2D(300, 300);
double range = 2.0 * FastMath.PI;
double step = range / (samples + 1);
for (double angle = 0; angle < range; angle += step) {
Vector2D circle = buildVector(angle);
points.add(circle.scalarMultiply(200).add(center));
}
return points;
}
/** Create a cross sprite.
* @return vectors describing the sprite
*/
public static List createCross() {
List points = new ArrayList();
for (int i = 100; i < 500; i += 10) {
points.add(new Vector2D(300, i));
points.add(new Vector2D(i, 300));
}
return points;
}
/** Create a canvas
* @return canvas
*/
public static PCanvas createCanvas() {
final PCanvas canvas = new PCanvas();
final PCamera camera = canvas.getCamera();
final PText tooltipNode = new PText();
tooltipNode.setPickable(false);
camera.addChild(tooltipNode);
camera.addInputEventListener(new PBasicInputEventHandler() {
public void mouseMoved(final PInputEvent event) {
updateToolTip(event);
}
public void mouseDragged(final PInputEvent event) {
updateToolTip(event);
}
public void updateToolTip(final PInputEvent event) {
final PNode n = event.getPickedNode();
final Object object = (Object) n.getAttribute(TOOLTIP);
if (object != null) {
final String tooltipString = object.toString();
final Point2D p = event.getCanvasPosition();
event.getPath().canvasToLocal(p, camera);
tooltipNode.setText(tooltipString);
tooltipNode.setOffset(p.getX() + 8, p.getY() - 8);
} else {
tooltipNode.setText(null);
}
}
});
// uninstall default zoom event handler
canvas.removeInputEventListener(canvas.getZoomEventHandler());
// install mouse wheel zoom event handler
final PMouseWheelZoomEventHandler mouseWheelZoomEventHandler = new PMouseWheelZoomEventHandler();
canvas.addInputEventListener(mouseWheelZoomEventHandler);
return canvas;
}
/**
* Build the 2D vector corresponding to the given angle.
* @param alpha angle
* @return the corresponding 2D vector
*/
private static Vector2D buildVector(final double alpha) {
final SinCos sc = FastMath.sinCos(alpha);
return new Vector2D(sc.cos(), sc.sin());
}
/** Main frame for geometry examples.
*/
@SuppressWarnings("serial")
public static class Display extends ExampleFrame {
/** Points to plot. */
private List points;
/** Canvas for plotting. */
private PCanvas canvas;
/** Container. */
private JComponent container;
/** Simple constructor.
*/
public Display() {
setTitle("Hipparchus: Geometry Examples");
setSize(800, 700);
container = new JPanel(new BorderLayout());
canvas = createCanvas();
container.add(canvas);
container.setBorder(BorderFactory.createLineBorder(Color.black, 1));
JComponent controlPanel = new JPanel();
JButton random = new JButton("Randomize");
controlPanel.add(random);
random.addActionListener(new ActionListener() {
// @Override
public void actionPerformed(ActionEvent e) {
canvas.getLayer().removeAllChildren();
points = createRandomPoints(1000);
paintConvexHull();
}
});
JButton circle = new JButton("Circle");
controlPanel.add(circle);
circle.addActionListener(new ActionListener() {
// @Override
public void actionPerformed(ActionEvent e) {
canvas.getLayer().removeAllChildren();
points = createCircle(100);
paintConvexHull();
}
});
JButton cross = new JButton("Cross");
controlPanel.add(cross);
cross.addActionListener(new ActionListener() {
// @Override
public void actionPerformed(ActionEvent e) {
canvas.getLayer().removeAllChildren();
points = createCross();
paintConvexHull();
}
});
JSplitPane splitpane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, container,
controlPanel);
splitpane.setDividerLocation(600);
add(splitpane);
points = createRandomPoints(1000);
paintConvexHull();
}
/** {@inheritDoc} */
@Override
public Component getMainPanel() {
return container;
}
/** Paint a convex hull.
*/
public void paintConvexHull() {
PNode pointSet = new PNode();
for (Vector2D point : points) {
final PNode node = PPath.createEllipse(point.getX() - 1, point.getY() - 1, 2, 2);
node.addAttribute(TOOLTIP, point);
node.setPaint(Color.gray);
pointSet.addChild(node);
}
canvas.getLayer().addChild(pointSet);
ConvexHullGenerator2D generator = new MonotoneChain(true, 1e-6);
ConvexHull2D hull = generator.generate(points); //AklToussaintHeuristic.reducePoints(points));
PNode hullNode = new PNode();
for (Vector2D vertex : hull.getVertices()) {
final PPath node = PPath.createEllipse(vertex.getX() - 1, vertex.getY() - 1, 2, 2);
node.addAttribute(TOOLTIP, vertex);
node.setPaint(Color.red);
node.setStrokePaint(Color.red);
hullNode.addChild(node);
}
for (Segment line : hull.getLineSegments()) {
final PPath node = PPath.createLine(line.getStart().getX(), line.getStart().getY(),
line.getEnd().getX(), line.getEnd().getY());
node.setPickable(false);
node.setPaint(Color.red);
node.setStrokePaint(Color.red);
hullNode.addChild(node);
}
canvas.getLayer().addChild(hullNode);
Encloser encloser =
new WelzlEncloser(1e-10, new DiskGenerator());
EnclosingBall ball = encloser.enclose(points);
final double radius = ball.getRadius();
PPath ballCenter =
PPath.createEllipse(ball.getCenter().getX() - 1, ball.getCenter().getY() - 1, 2, 2);
ballCenter.setStrokePaint(Color.blue);
ballCenter.setPaint(Color.blue);
canvas.getLayer().addChild(0, ballCenter);
PPath ballNode =
PPath.createEllipse(ball.getCenter().getX() - radius, ball.getCenter().getY() - radius,
radius * 2, radius * 2);
ballNode.setTransparency(1.0f);
ballNode.setStrokePaint(Color.blue);
canvas.getLayer().addChild(0, ballNode);
}
}
/** Main entry point.
* @param argv program arguments (unused here)
*/
public static void main(final String[] argv) {
ExampleUtils.showExampleFrame(new Display());
}
}