/*
* $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.d3.ifx;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper;
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.d3.ai.Prism3ai;
/** A rectangular shape with 3 integer FX properties.
*
* @param <IT> is the type of the implementation of this shape.
* @author $Author: sgalland$
* @author $Author: tpiotrow$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 13.0
*/
public abstract class AbstractRectangularShape3ifx<IT extends AbstractRectangularShape3ifx<?>>
extends AbstractShape3ifx<IT>
implements Prism3ai<Shape3ifx<?>, IT, PathElement3ifx, Point3ifx, Vector3ifx, RectangularPrism3ifx> {
private static final long serialVersionUID = -6551989261232962403L;
/** minX property.
*/
Point3ifx min = new Point3ifx();
/** maxX property.
*/
Point3ifx max = new Point3ifx();
/** width property.
*/
private ReadOnlyIntegerWrapper width;
/** height property.
*/
private ReadOnlyIntegerWrapper height;
/** depth property.
*/
private ReadOnlyIntegerWrapper depth;
/** Construct an empty rectangular shape.
*/
public AbstractRectangularShape3ifx() {
super();
}
/** Constructor by copy.
* @param shape the shape to copy.
*/
public AbstractRectangularShape3ifx(Prism3ai<?, ?, ?, ?, ?, ?> shape) {
setFromCorners(shape.getMinX(), shape.getMinY(), shape.getMinZ(), shape.getMaxX(), shape.getMaxY(), shape.getMaxZ());
}
@Override
public IT clone() {
final IT clone = super.clone();
if (clone.min != null) {
clone.min = null;
clone.min = this.min.clone();
}
if (clone.max != null) {
clone.max = null;
clone.max = this.max.clone();
}
return clone;
}
@Override
public void setFromCorners(int x1, int y1, int z1, int x2, int y2, int z2) {
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);
}
if (z1 <= z2) {
minZProperty().set(z1);
maxZProperty().set(z2);
} else {
minZProperty().set(z2);
maxZProperty().set(z1);
}
addListeners();
}
private void addListeners() {
this.min.xProperty().addListener((observable, oldValue, nValue) -> {
final int currentMin = nValue.intValue();
final int currentMax = getMaxX();
if (currentMax < currentMin) {
// min-max constrain is broken
maxXProperty().set(currentMin);
}
});
this.min.yProperty().addListener((observable, oValue, nValue) -> {
final int currentMin = nValue.intValue();
final int currentMax = getMaxY();
if (currentMax < currentMin) {
// min-max constrain is broken
maxYProperty().set(currentMin);
}
});
this.min.zProperty().addListener((observable, oValue, nValue) -> {
final int currentMin = nValue.intValue();
final int currentMax = getMaxZ();
if (currentMax < currentMin) {
// min-max constrain is broken
maxZProperty().set(currentMin);
}
});
this.max.xProperty().addListener((observable, oValue, nValue) -> {
final int currentMax = nValue.intValue();
final int currentMin = getMinX();
if (currentMax < currentMin) {
// min-max constrain is broken
minXProperty().set(currentMax);
}
});
this.max.yProperty().addListener((observable, oValue, nValue) -> {
final int currentMax = nValue.intValue();
final int currentMin = getMinY();
if (currentMax < currentMin) {
// min-max constrain is broken
minYProperty().set(currentMax);
}
});
this.max.zProperty().addListener((observable, oValue, nValue) -> {
final int currentMax = nValue.intValue();
final int currentMin = getMinZ();
if (currentMax < currentMin) {
// min-max constrain is broken
minZProperty().set(currentMax);
}
});
}
@Pure
@Override
public int getMinX() {
return this.min.ix();
}
@Override
public void setMinX(int x) {
minXProperty().set(x);
}
/** Replies the property that is the minimum x coordinate of the box.
*
* @return the minX property.
*/
@Pure
public IntegerProperty minXProperty() {
return this.min.xProperty();
}
@Pure
@Override
public int getMaxX() {
return this.max.ix();
}
@Override
public void setMaxX(int x) {
maxXProperty().set(x);
}
/** Replies the property that is the maximum x coordinate of the box.
*
* @return the maxX property.
*/
@Pure
public IntegerProperty maxXProperty() {
return this.max.xProperty();
}
@Pure
@Override
public int getMinY() {
return this.min.iy();
}
@Override
public void setMinY(int y) {
minYProperty().set(y);
}
/** Replies the property that is the minimum y coordinate of the box.
*
* @return the minY property.
*/
@Pure
public IntegerProperty minYProperty() {
return this.min.yProperty();
}
@Pure
@Override
public int getMaxY() {
return this.max.iy();
}
@Override
public void setMaxY(int y) {
maxYProperty().set(y);
}
/** Replies the property that is the maximum y coordinate of the box.
*
* @return the maxY property.
*/
@Pure
public IntegerProperty maxYProperty() {
return this.max.yProperty();
}
@Pure
@Override
public int getMinZ() {
return this.min.iz();
}
@Override
public void setMinZ(int z) {
minZProperty().set(z);
}
/** Replies the property that is the minimum z coordinate of the box.
*
* @return the minZ property.
*/
@Pure
public IntegerProperty minZProperty() {
return this.min.zProperty();
}
@Pure
@Override
public int getMaxZ() {
return this.max.iz();
}
@Override
public void setMaxZ(int z) {
maxZProperty().set(z);
}
/** Replies the property that is the maximum z coordinate of the box.
*
* @return the maxZ property.
*/
@Pure
public IntegerProperty maxZProperty() {
return this.max.zProperty();
}
@Pure
@Override
public int hashCode() {
int bits = 1;
bits = 31 * bits + getMinX();
bits = 31 * bits + getMinY();
bits = 31 * bits + getMaxX();
bits = 31 * bits + getMaxY();
return bits ^ (bits >> 31);
}
@Override
public int getWidth() {
return widthProperty().get();
}
/** Replies the property that is the width of the box.
*
* @return the width property.
*/
@Pure
public IntegerProperty widthProperty() {
if (this.width == null) {
this.width = new ReadOnlyIntegerWrapper(this, MathFXAttributeNames.WIDTH);
this.width.bind(Bindings.subtract(maxXProperty(), minXProperty()));
}
return this.width;
}
@Override
public int getHeight() {
return heightProperty().get();
}
/** Replies the property that is the height of the box.
*
* @return the height property.
*/
@Pure
public IntegerProperty heightProperty() {
if (this.height == null) {
this.height = new ReadOnlyIntegerWrapper(this, MathFXAttributeNames.HEIGHT);
this.height.bind(Bindings.subtract(maxYProperty(), minYProperty()));
}
return this.height;
}
@Override
public int getDepth() {
return depthProperty().get();
}
/** Replies the property that is the depth of the box.
*
* @return the depth property.
*/
@Pure
public IntegerProperty depthProperty() {
if (this.depth == null) {
this.depth = new ReadOnlyIntegerWrapper(this, MathFXAttributeNames.DEPTH);
this.depth.bind(Bindings.subtract(maxZProperty(), minZProperty()));
}
return this.depth;
}
@Override
public ObjectProperty<RectangularPrism3ifx> 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;
}
}