/******************************************************************************* * Copyright (c) 2014, 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 * *******************************************************************************/ package org.eclipse.gef.mvc.examples.logo.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.gef.common.beans.property.ReadOnlyListWrapperEx; import org.eclipse.gef.common.collections.CollectionUtils; import org.eclipse.gef.geometry.planar.ICurve; import org.eclipse.gef.geometry.planar.IGeometry; import org.eclipse.gef.geometry.planar.Point; import org.eclipse.gef.geometry.planar.PolyBezier; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyListProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.effect.Effect; import javafx.scene.paint.Paint; // TODO: parameterize with concrete ICurve and encapsulate construction of geometry; limit the number of waypoints if needed public class GeometricCurve extends AbstractGeometricElement<ICurve> { public enum Decoration { NONE, ARROW, CIRCLE } public enum RoutingStyle { STRAIGHT, ORTHOGONAL } public static final String SOURCE_DECORATION_PROPERTY = "sourceDecoration"; public static final String TARGET_DECORATION_PROPERTY = "targetDecoration"; public static final String ROUTING_STYLE_PROPERTY = "routingStyle"; public static final String WAY_POINTS_PROPERTY = "wayPoints"; public static final String DASHES_PROPERTY = "dashes"; public static ICurve constructCurveFromWayPoints(Point... waypoints) { if (waypoints == null || waypoints.length < 2) { throw new IllegalArgumentException("Need at least two waypoints."); } return PolyBezier.interpolateCubic(waypoints); } private final ReadOnlyListWrapperEx<Point> wayPointsProperty = new ReadOnlyListWrapperEx<>(this, WAY_POINTS_PROPERTY, CollectionUtils.<Point> observableArrayList()); private final ObjectProperty<Decoration> sourceDecorationProperty = new SimpleObjectProperty<>(this, SOURCE_DECORATION_PROPERTY, Decoration.NONE); private final ObjectProperty<Decoration> targetDecorationProperty = new SimpleObjectProperty<>(this, TARGET_DECORATION_PROPERTY, Decoration.NONE); private final ObjectProperty<RoutingStyle> routingStyleProperty = new SimpleObjectProperty<>(this, ROUTING_STYLE_PROPERTY, RoutingStyle.STRAIGHT); private final ReadOnlyListWrapperEx<Double> dashesProperty = new ReadOnlyListWrapperEx<>(this, DASHES_PROPERTY, CollectionUtils.<Double> observableArrayList()); private final Set<AbstractGeometricElement<? extends IGeometry>> sourceAnchorages = new HashSet<>(); private final Set<AbstractGeometricElement<? extends IGeometry>> targetAnchorages = new HashSet<>(); public GeometricCurve(Point[] waypoints, Paint stroke, double strokeWidth, Double[] dashes, Effect effect) { super(constructCurveFromWayPoints(waypoints), stroke, strokeWidth, effect); if (waypoints.length < 2) { throw new IllegalArgumentException("At least start and end point need to be specified,"); } wayPointsProperty.addAll(Arrays.asList(waypoints)); dashesProperty.addAll(dashes); } public void addSourceAnchorage(AbstractGeometricElement<? extends IGeometry> anchored) { sourceAnchorages.add(anchored); } public void addTargetAnchorage(AbstractGeometricElement<? extends IGeometry> anchored) { targetAnchorages.add(anchored); } public void addWayPoint(int i, Point p) { List<Point> points = getWayPointsCopy(); points.add(i, p); setWayPoints(points.toArray(new Point[] {})); } public ReadOnlyListProperty<Double> dashesProperty() { return dashesProperty.getReadOnlyProperty(); } public GeometricCurve getCopy() { GeometricCurve copy = new GeometricCurve(getWayPointsCopy().toArray(new Point[] {}), getStroke(), getStrokeWidth(), getDashes(), getEffect()); copy.setTransform(getTransform()); copy.setRoutingStyle(getRoutingStyle()); copy.setSourceDecoration(getSourceDecoration()); copy.setTargetDecoration(getTargetDecoration()); return copy; } public Double[] getDashes() { return dashesProperty.get().toArray(new Double[] {}); } public RoutingStyle getRoutingStyle() { return routingStyleProperty.get(); } public Set<AbstractGeometricElement<? extends IGeometry>> getSourceAnchorages() { return sourceAnchorages; } public Decoration getSourceDecoration() { return sourceDecorationProperty.get(); } public Set<AbstractGeometricElement<? extends IGeometry>> getTargetAnchorages() { return targetAnchorages; } public Decoration getTargetDecoration() { return targetDecorationProperty.get(); } public List<Point> getWayPoints() { return Collections.unmodifiableList(wayPointsProperty.get()); } public List<Point> getWayPointsCopy() { return new ArrayList<>(getWayPoints()); } public void removeWayPoint(int i) { // TODO: check index List<Point> points = getWayPointsCopy(); points.remove(i); setWayPoints(points.toArray(new Point[] {})); } /** * Returns the {@link ObjectProperty} for the {@link RoutingStyle} of this * {@link GeometricCurve}. * * @return The {@link ObjectProperty} for the {@link RoutingStyle} of this * {@link GeometricCurve}. */ public ObjectProperty<RoutingStyle> routingStyleProperty() { return routingStyleProperty; } public void setRoutingStyle(RoutingStyle routingStyle) { routingStyleProperty.set(routingStyle); } public void setSourceDecoration(Decoration sourceDecoration) { sourceDecorationProperty.set(sourceDecoration); } public void setTargetDecoration(Decoration targetDecoration) { targetDecorationProperty.set(targetDecoration); } public void setWayPoint(int i, Point p) { List<Point> points = getWayPointsCopy(); points.set(i, p); setWayPoints(points.toArray(new Point[] {})); } public void setWayPoints(Point... waypoints) { if (waypoints.length < 2) { throw new IllegalArgumentException("Need at least two waypoints."); } this.wayPointsProperty.setAll(Arrays.asList(waypoints)); setGeometry(constructCurveFromWayPoints(waypoints)); } /** * Returns the {@link ObjectProperty} for the source {@link Decoration} of * this {@link GeometricCurve}. * * @return The {@link ObjectProperty} for the source {@link Decoration} of * this {@link GeometricCurve}. */ public ObjectProperty<Decoration> sourceDecorationProperty() { return sourceDecorationProperty; } /** * Returns the {@link ObjectProperty} for the target {@link Decoration} of * this {@link GeometricCurve}. * * @return The {@link ObjectProperty} for the target {@link Decoration} of * this {@link GeometricCurve}. */ public ObjectProperty<Decoration> targetDecorationProperty() { return targetDecorationProperty; } public ReadOnlyListProperty<Point> wayPointsProperty() { return wayPointsProperty.getReadOnlyProperty(); } }