/******************************************************************************* * Copyright (c) 2015, 2016 itemis AG and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Alexander Nyßen (itemis AG) - initial API and implementation * Matthias Wienand (itemis AG) - initial API and implementation * *******************************************************************************/ package org.eclipse.gef.fx.utils; import org.eclipse.gef.geometry.euclidean.Angle; import org.eclipse.gef.geometry.planar.IGeometry; import org.eclipse.gef.geometry.planar.Point; import org.eclipse.gef.geometry.planar.Path.Segment; import javafx.collections.ObservableList; import javafx.scene.shape.Arc; import javafx.scene.shape.Circle; import javafx.scene.shape.ClosePath; import javafx.scene.shape.CubicCurve; import javafx.scene.shape.CubicCurveTo; import javafx.scene.shape.Ellipse; import javafx.scene.shape.FillRule; import javafx.scene.shape.Line; import javafx.scene.shape.LineTo; import javafx.scene.shape.MoveTo; import javafx.scene.shape.Path; import javafx.scene.shape.PathElement; import javafx.scene.shape.Polygon; import javafx.scene.shape.Polyline; import javafx.scene.shape.QuadCurve; import javafx.scene.shape.QuadCurveTo; import javafx.scene.shape.Rectangle; import javafx.scene.shape.SVGPath; import javafx.scene.shape.Shape; import javafx.scene.text.Text; /** * The utility class {@link Shape2Geometry} provides methods for the conversion * of JavaFX {@link Shape} implementations to {@link IGeometry} implementations. * * @author anyssen * @author mwienand * */ public class Shape2Geometry { /** * Converts the given JavaFX {@link Arc} to a * {@link org.eclipse.gef.geometry.planar.Arc}. * * @param arc * The JavaFX {@link Arc} to convert. * @return The newly created {@link org.eclipse.gef.geometry.planar.Arc} * that describes the given {@link Arc}. */ public static org.eclipse.gef.geometry.planar.Arc toArc(Arc arc) { return new org.eclipse.gef.geometry.planar.Arc( arc.getCenterX() - arc.getRadiusX(), arc.getCenterY() - arc.getRadiusY(), arc.getRadiusX() + arc.getRadiusX(), arc.getRadiusY() + arc.getRadiusY(), Angle.fromDeg(arc.getStartAngle()), Angle.fromDeg(arc.getLength())); } /** * Converts the given JavaFX {@link CubicCurve} to a * {@link org.eclipse.gef.geometry.planar.CubicCurve}. * * @param cubic * The JavaFX {@link CubicCurve} to convert. * @return The newly created * {@link org.eclipse.gef.geometry.planar.CubicCurve} that * describes the given {@link CubicCurve}. */ public static org.eclipse.gef.geometry.planar.CubicCurve toCubicCurve( CubicCurve cubic) { return new org.eclipse.gef.geometry.planar.CubicCurve( cubic.getStartX(), cubic.getStartY(), cubic.getControlX1(), cubic.getControlY1(), cubic.getControlX2(), cubic.getControlY2(), cubic.getEndX(), cubic.getEndY()); } /** * Converts the given JavaFX {@link Circle} to a * {@link org.eclipse.gef.geometry.planar.Ellipse}. * * @param circle * The JavaFX {@link Circle} to convert. * @return The newly created * {@link org.eclipse.gef.geometry.planar.Ellipse} that describes * the given {@link Circle}. */ public static org.eclipse.gef.geometry.planar.Ellipse toEllipse( Circle circle) { return new org.eclipse.gef.geometry.planar.Ellipse( circle.getCenterX() - circle.getRadius(), circle.getCenterY() - circle.getRadius(), circle.getRadius() + circle.getRadius(), circle.getRadius() + circle.getRadius()); } /** * Converts the given JavaFX {@link Ellipse} to a * {@link org.eclipse.gef.geometry.planar.Ellipse}. * * @param ellipse * The JavaFX {@link Ellipse} to convert. * @return The newly created * {@link org.eclipse.gef.geometry.planar.Ellipse} that describes * the given {@link Ellipse}. */ public static org.eclipse.gef.geometry.planar.Ellipse toEllipse( Ellipse ellipse) { return new org.eclipse.gef.geometry.planar.Ellipse( ellipse.getCenterX() - ellipse.getRadiusX(), ellipse.getCenterY() - ellipse.getRadiusY(), ellipse.getRadiusX() + ellipse.getRadiusX(), ellipse.getRadiusY() + ellipse.getRadiusY()); } /** * Returns an {@link IGeometry} that describes the geometric outline of the * given {@link Shape}, i.e. excluding the stroke. * <p> * The conversion is supported for the following {@link Shape}s: * <ul> * <li>{@link Arc} * <li>{@link Circle} * <li>{@link CubicCurve} * <li>{@link Ellipse} * <li>{@link Line} * <li>{@link Path} * <li>{@link Polygon} * <li>{@link Polyline} * <li>{@link QuadCurve} * <li>{@link Rectangle} * </ul> * The following {@link Shape}s cannot be converted, yet: * <ul> * <li>{@link Text} * <li>{@link SVGPath} * </ul> * * @param visual * The {@link Shape} for which an {@link IGeometry} is * determined. * @return The newly created {@link IGeometry} that best describes the * geometric outline of the given {@link Shape}. * @throws IllegalStateException * if the given {@link Shape} is not supported. */ public static IGeometry toGeometry(Shape visual) { if (visual instanceof Arc) { return toArc((Arc) visual); } else if (visual instanceof Circle) { return toEllipse((Circle) visual); } else if (visual instanceof CubicCurve) { return toCubicCurve((CubicCurve) visual); } else if (visual instanceof Ellipse) { return toEllipse((Ellipse) visual); } else if (visual instanceof Line) { return toLine((Line) visual); } else if (visual instanceof Path) { return toPath((Path) visual); } else if (visual instanceof Polygon) { return toPolygon((Polygon) visual); } else if (visual instanceof Polyline) { return toPolyline((Polyline) visual); } else if (visual instanceof QuadCurve) { QuadCurve quad = (QuadCurve) visual; return toQuadraticCurve(quad); } else if (visual instanceof Rectangle) { Rectangle rect = (Rectangle) visual; if (rect.getArcWidth() == 0 && rect.getArcHeight() == 0) { // corners are not rounded => normal rectangle is sufficient return toRectangle(rect); } return toRoundedRectangle((Rectangle) visual); } else { // Text and SVGPath shapes are currently not supported throw new IllegalStateException( "Cannot compute geometric outline for Shape of type <" + visual.getClass() + ">."); } } /** * Converts the given JavaFX {@link Line} to a * {@link org.eclipse.gef.geometry.planar.Line}. * * @param line * The JavaFX {@link Line} to convert. * @return The newly created {@link org.eclipse.gef.geometry.planar.Line} * that describes the given {@link Line}. */ public static org.eclipse.gef.geometry.planar.Line toLine(Line line) { return new org.eclipse.gef.geometry.planar.Line(line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY()); } /** * Converts the given JavaFX {@link Path} to a * {@link org.eclipse.gef.geometry.planar.Path}. * * @param path * The JavaFX {@link Path} to convert. * @return The newly created {@link org.eclipse.gef.geometry.planar.Path} * that describes the given {@link Path}. */ public static final org.eclipse.gef.geometry.planar.Path toPath( Path path) { ObservableList<PathElement> elements = path.getElements(); org.eclipse.gef.geometry.planar.Path.Segment[] segments = new org.eclipse.gef.geometry.planar.Path.Segment[elements .size()]; for (int i = 0; i < segments.length; i++) { PathElement element = elements.get(i); if (element instanceof MoveTo) { MoveTo moveTo = (MoveTo) element; segments[i] = new Segment(Segment.MOVE_TO, new Point(moveTo.getX(), moveTo.getY())); } else if (element instanceof LineTo) { LineTo lineTo = (LineTo) element; segments[i] = new Segment(Segment.LINE_TO, new Point(lineTo.getX(), lineTo.getY())); } else if (element instanceof QuadCurveTo) { QuadCurveTo quadTo = (QuadCurveTo) element; segments[i] = new Segment(Segment.QUAD_TO, new Point(quadTo.getControlX(), quadTo.getControlY()), new Point(quadTo.getX(), quadTo.getY())); } else if (element instanceof CubicCurveTo) { CubicCurveTo cubicTo = (CubicCurveTo) element; segments[i] = new Segment(Segment.CUBIC_TO, new Point(cubicTo.getControlX1(), cubicTo.getControlY1()), new Point(cubicTo.getControlX2(), cubicTo.getControlY2()), new Point(cubicTo.getX(), cubicTo.getY())); } else if (element instanceof ClosePath) { segments[i] = new Segment(Segment.CLOSE); } } int windingRule = path.getFillRule() == FillRule.EVEN_ODD ? org.eclipse.gef.geometry.planar.Path.WIND_EVEN_ODD : org.eclipse.gef.geometry.planar.Path.WIND_NON_ZERO; return new org.eclipse.gef.geometry.planar.Path(windingRule, segments); } /** * Converts the given JavaFX {@link Polygon} to a * {@link org.eclipse.gef.geometry.planar.Polygon}. * * @param polygon * The JavaFX {@link Polygon} to convert. * @return The newly created * {@link org.eclipse.gef.geometry.planar.Polygon} that describes * the given {@link Polygon}. */ public static org.eclipse.gef.geometry.planar.Polygon toPolygon( Polygon polygon) { double[] coords = new double[polygon.getPoints().size()]; for (int i = 0; i < coords.length; i++) { coords[i] = polygon.getPoints().get(i).doubleValue(); } return new org.eclipse.gef.geometry.planar.Polygon(coords); } /** * Converts the given JavaFX {@link Polyline} to a * {@link org.eclipse.gef.geometry.planar.Polyline}. * * @param polyline * The JavaFX {@link Polyline} to convert. * @return The newly created * {@link org.eclipse.gef.geometry.planar.Polyline} that describes * the given {@link Polyline}. */ public static org.eclipse.gef.geometry.planar.Polyline toPolyline( Polyline polyline) { double[] coords = new double[polyline.getPoints().size()]; for (int i = 0; i < coords.length; i++) { coords[i] = polyline.getPoints().get(i).doubleValue(); } return new org.eclipse.gef.geometry.planar.Polyline(coords); } /** * Converts the given JavaFX {@link QuadCurve} to a * {@link org.eclipse.gef.geometry.planar.QuadraticCurve}. * * @param quad * The JavaFX {@link QuadCurve} to convert. * @return The newly created * {@link org.eclipse.gef.geometry.planar.QuadraticCurve} that * describes the given {@link QuadCurve}. */ public static org.eclipse.gef.geometry.planar.QuadraticCurve toQuadraticCurve( QuadCurve quad) { return new org.eclipse.gef.geometry.planar.QuadraticCurve( quad.getStartX(), quad.getStartY(), quad.getControlX(), quad.getControlY(), quad.getEndX(), quad.getEndY()); } /** * Converts the given JavaFX {@link Rectangle} to a * {@link org.eclipse.gef.geometry.planar.Rectangle}. Note, that the * arc-width and arc-height of the given {@link Rectangle} will not be * preserved in the resulting geometry. * * @param rect * The JavaFX {@link Rectangle} to convert. * @return The newly created * {@link org.eclipse.gef.geometry.planar.Rectangle} that describes * the given {@link Rectangle} (without its arc-width and * arc-height). */ public static org.eclipse.gef.geometry.planar.Rectangle toRectangle( Rectangle rect) { return new org.eclipse.gef.geometry.planar.Rectangle(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); } /** * Converts the given JavaFX {@link Rectangle} to a * {@link org.eclipse.gef.geometry.planar.RoundedRectangle}. * * @param rect * The JavaFX {@link Rectangle} to convert. * @return The newly created * {@link org.eclipse.gef.geometry.planar.RoundedRectangle} that * describes the given {@link Rectangle}. */ public static org.eclipse.gef.geometry.planar.RoundedRectangle toRoundedRectangle( Rectangle rect) { return new org.eclipse.gef.geometry.planar.RoundedRectangle( rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight(), rect.getArcWidth(), rect.getArcHeight()); } }