/* * $Id$ * This file is a part of the Arakhne Foundation Classes, http://www.arakhne.org/afc * * Copyright (c) 2000-2012 Stephane GALLAND. * Copyright (c) 2005-10, Multiagent Team, Laboratoire Systemes et Transports, * Universite de Technologie de Belfort-Montbeliard. * Copyright (c) 2013-2016 The original authors, and other authors. * * Licensed 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 http://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. */ package org.arakhne.afc.math.geometry.d2.dfx; import javafx.beans.binding.Bindings; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleObjectProperty; import org.eclipse.xtext.xbase.lib.Pure; import org.arakhne.afc.math.geometry.MathFXAttributeNames; import org.arakhne.afc.math.geometry.d2.afp.RectangularShape2afp; import org.arakhne.afc.vmutil.asserts.AssertMessages; /** Abstract rectangular shape with 2 double precision floating-point FX properties. * * @param <IT> is the type of the implementation of this shape. * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ * @since 13.0 */ public abstract class AbstractRectangularShape2dfx<IT extends AbstractRectangularShape2dfx<?>> extends AbstractShape2dfx<IT> implements RectangularShape2afp<Shape2dfx<?>, IT, PathElement2dfx, Point2dfx, Vector2dfx, Rectangle2dfx> { private static final long serialVersionUID = 562658629477723655L; /** minX property. */ DoubleProperty minX; /** minY property. */ DoubleProperty minY; /** maxX property. */ DoubleProperty maxX; /** maxY property. */ DoubleProperty maxY; /** width property. */ DoubleProperty width; /** height property. */ DoubleProperty height; /** Construct an empty rectangular shape. */ public AbstractRectangularShape2dfx() { // } /** Constructor by copy. * @param shape the shape to copy. */ public AbstractRectangularShape2dfx(RectangularShape2afp<?, ?, ?, ?, ?, ?> shape) { assert shape != null : AssertMessages.notNullParameter(); setFromCorners(shape.getMinX(), shape.getMinY(), shape.getMaxX(), shape.getMaxY()); } @Override public IT clone() { final IT clone = super.clone(); if (clone.minX != null) { clone.minX = null; clone.minXProperty().set(getMinX()); } if (clone.minY != null) { clone.minY = null; clone.minYProperty().set(getMinY()); } if (clone.maxX != null) { clone.maxX = null; clone.maxXProperty().set(getMaxX()); } if (clone.maxY != null) { clone.maxY = null; clone.maxYProperty().set(getMaxY()); } clone.width = null; clone.height = null; return clone; } @Override public void setFromCorners(double x1, double y1, double x2, double y2) { if (x1 <= x2) { minXProperty().set(x1); maxXProperty().set(x2); } else { minXProperty().set(x2); maxXProperty().set(x1); } if (y1 <= y2) { minYProperty().set(y1); maxYProperty().set(y2); } else { minYProperty().set(y2); maxYProperty().set(y1); } } @Pure @Override public double getMinX() { return this.minX == null ? 0 : this.minX.get(); } @Override public void setMinX(double x) { minXProperty().set(x); } /** Replies the property that is the minimum x coordinate of the box. * * @return the minX property. */ @Pure public DoubleProperty minXProperty() { if (this.minX == null) { this.minX = new SimpleDoubleProperty(this, MathFXAttributeNames.MINIMUM_X) { @Override protected void invalidated() { final double currentMin = get(); final double currentMax = getMaxX(); if (currentMin > currentMax) { // min-max constrain is broken maxXProperty().set(currentMin); } } }; } return this.minX; } @Pure @Override public double getMaxX() { return this.maxX == null ? 0 : this.maxX.get(); } @Override public void setMaxX(double x) { maxXProperty().set(x); } /** Replies the property that is the maximum x coordinate of the box. * * @return the maxX property. */ @Pure public DoubleProperty maxXProperty() { if (this.maxX == null) { this.maxX = new SimpleDoubleProperty(this, MathFXAttributeNames.MAXIMUM_X) { @Override protected void invalidated() { final double currentMax = get(); final double currentMin = getMinX(); if (currentMin > currentMax) { // min-max constrain is broken minXProperty().set(currentMax); } } }; } return this.maxX; } @Pure @Override public double getMinY() { return this.minY == null ? 0 : this.minY.get(); } @Override public void setMinY(double y) { minYProperty().set(y); } /** Replies the property that is the minimum y coordinate of the box. * * @return the minY property. */ @Pure public DoubleProperty minYProperty() { if (this.minY == null) { this.minY = new SimpleDoubleProperty(this, MathFXAttributeNames.MINIMUM_Y) { @Override protected void invalidated() { final double currentMin = get(); final double currentMax = getMaxY(); if (currentMin > currentMax) { // min-max constrain is broken maxYProperty().set(currentMin); } } }; } return this.minY; } @Pure @Override public double getMaxY() { return this.maxY == null ? 0 : this.maxY.get(); } @Override public void setMaxY(double y) { maxYProperty().set(y); } /** Replies the property that is the maximum y coordinate of the box. * * @return the maxY property. */ @Pure public DoubleProperty maxYProperty() { if (this.maxY == null) { this.maxY = new SimpleDoubleProperty(this, MathFXAttributeNames.MAXIMUM_Y) { @Override protected void invalidated() { final double currentMax = get(); final double currentMin = getMinY(); if (currentMin > currentMax) { // min-max constrain is broken minYProperty().set(currentMax); } } }; } return this.maxY; } @Override public double getWidth() { return widthProperty().get(); } /** Replies the property that is the width of the box. * * @return the width property. */ @Pure public DoubleProperty widthProperty() { if (this.width == null) { this.width = new SimpleDoubleProperty(this, MathFXAttributeNames.WIDTH); this.width.bind(Bindings.subtract(maxXProperty(), minXProperty())); } return this.width; } @Override public double getHeight() { return heightProperty().get(); } /** Replies the property that is the height of the box. * * @return the height property. */ @Pure public DoubleProperty heightProperty() { if (this.height == null) { this.height = new SimpleDoubleProperty(this, MathFXAttributeNames.HEIGHT); this.height.bind(Bindings.subtract(maxYProperty(), minYProperty())); } return this.height; } @Pure @Override public int hashCode() { long bits = 1; bits = 31 * bits + Double.hashCode(getMinX()); bits = 31 * bits + Double.hashCode(getMinY()); bits = 31 * bits + Double.hashCode(getMaxX()); bits = 31 * bits + Double.hashCode(getMaxY()); final int b = (int) bits; return b ^ (b >> 31); } @Override public ObjectProperty<Rectangle2dfx> boundingBoxProperty() { if (this.boundingBox == null) { this.boundingBox = new SimpleObjectProperty<>(this, MathFXAttributeNames.BOUNDING_BOX); this.boundingBox.bind(Bindings.createObjectBinding(() -> toBoundingBox(), minXProperty(), minYProperty(), widthProperty(), heightProperty())); } return this.boundingBox; } }