/*******************************************************************************
* Copyright (c) 2016 Weasis Team 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:
* Nicolas Roduit - initial API and implementation
*******************************************************************************/
package org.weasis.core.ui.model.graphic.imp.area;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.weasis.core.api.image.measure.MeasurementsAdapter;
import org.weasis.core.api.image.util.MeasurableLayer;
import org.weasis.core.api.image.util.Unit;
import org.weasis.core.ui.Messages;
import org.weasis.core.ui.model.graphic.AbstractDragGraphicArea;
import org.weasis.core.ui.model.utils.bean.MeasureItem;
import org.weasis.core.ui.model.utils.bean.Measurement;
import org.weasis.core.ui.model.utils.exceptions.InvalidShapeException;
import org.weasis.core.ui.util.MouseEventDouble;
@XmlType(name = "rectangle")
@XmlRootElement(name = "rectangle")
public class RectangleGraphic extends AbstractDragGraphicArea {
private static final long serialVersionUID = -2862114022989550927L;
public static final Integer POINTS_NUMBER = 8;
public static final Icon ICON = new ImageIcon(RectangleGraphic.class.getResource("/icon/22x22/draw-rectangle.png")); //$NON-NLS-1$
public static final Measurement AREA = new Measurement(Messages.getString("measure.area"), 1, true, true, true); //$NON-NLS-1$
public static final Measurement PERIMETER =
new Measurement(Messages.getString("measure.perimeter"), 2, true, true, false); //$NON-NLS-1$
public static final Measurement TOP_LEFT_POINT_X =
new Measurement(Messages.getString("measure.topx"), 3, true, true, false); //$NON-NLS-1$
public static final Measurement TOP_LEFT_POINT_Y =
new Measurement(Messages.getString("measure.topy"), 4, true, true, false); //$NON-NLS-1$
public static final Measurement CENTER_X =
new Measurement(Messages.getString("measure.centerx"), 5, true, true, false); //$NON-NLS-1$
public static final Measurement CENTER_Y =
new Measurement(Messages.getString("measure.centery"), 6, true, true, false); //$NON-NLS-1$
public static final Measurement WIDTH = new Measurement(Messages.getString("measure.width"), 7, true, true, false); //$NON-NLS-1$
public static final Measurement HEIGHT =
new Measurement(Messages.getString("measure.height"), 8, true, true, false); //$NON-NLS-1$
protected static final List<Measurement> MEASUREMENT_LIST = new ArrayList<>();
static {
MEASUREMENT_LIST.add(TOP_LEFT_POINT_X);
MEASUREMENT_LIST.add(TOP_LEFT_POINT_Y);
MEASUREMENT_LIST.add(CENTER_X);
MEASUREMENT_LIST.add(CENTER_Y);
MEASUREMENT_LIST.add(WIDTH);
MEASUREMENT_LIST.add(HEIGHT);
MEASUREMENT_LIST.add(AREA);
MEASUREMENT_LIST.add(PERIMETER);
}
public RectangleGraphic() {
super(POINTS_NUMBER);
}
public RectangleGraphic(RectangleGraphic graphic) {
super(graphic);
}
@Override
public RectangleGraphic copy() {
return new RectangleGraphic(this);
}
@Override
public Icon getIcon() {
return ICON;
}
@Override
public String getUIName() {
return Messages.getString("MeasureToolBar.rect"); //$NON-NLS-1$
}
public RectangleGraphic buildGraphic(Rectangle2D rectangle) throws InvalidShapeException {
Optional.ofNullable(rectangle).orElseThrow(() -> new InvalidShapeException("Rectangle2D is null!")); //$NON-NLS-1$
setHandlePointList(rectangle);
prepareShape();
return this;
}
@Override
protected void prepareShape() throws InvalidShapeException {
if (!isShapeValid()) {
throw new InvalidShapeException("This shape cannot be drawn"); //$NON-NLS-1$
}
buildShape(null);
}
@Override
public Integer moveAndResizeOnDrawing(Integer handlePointIndex, Double deltaX, Double deltaY,
MouseEventDouble mouseEvent) {
if (Objects.equals(handlePointIndex, UNDEFINED)) { // move shape
for (Point2D point : pts) {
if (point != null) {
point.setLocation(point.getX() + deltaX, point.getY() + deltaY);
}
}
} else {
Rectangle2D rectangle = new Rectangle2D.Double();
rectangle.setFrameFromDiagonal(getHandlePoint(eHandlePoint.NW.index),
getHandlePoint(eHandlePoint.SE.index));
double x = rectangle.getX();
double y = rectangle.getY();
double w = rectangle.getWidth();
double h = rectangle.getHeight();
eHandlePoint pt = eHandlePoint.valueFromIndex(handlePointIndex);
if (pt.equals(eHandlePoint.W) || pt.equals(eHandlePoint.NW) || pt.equals(eHandlePoint.SW)) {
x += deltaX;
w -= deltaX;
}
if (pt.equals(eHandlePoint.N) || pt.equals(eHandlePoint.NW) || pt.equals(eHandlePoint.NE)) {
y += deltaY;
h -= deltaY;
}
if (pt.equals(eHandlePoint.E) || pt.equals(eHandlePoint.NE) || pt.equals(eHandlePoint.SE)) {
w += deltaX;
}
if (pt.equals(eHandlePoint.S) || pt.equals(eHandlePoint.SW) || pt.equals(eHandlePoint.SE)) {
h += deltaY;
}
if (w < 0) {
w = -w;
x -= w;
pt = pt.getVerticalMirror();
}
if (h < 0) {
h = -h;
y -= h;
pt = pt.getHorizontalMirror();
}
handlePointIndex = pt.index;
rectangle.setFrame(x, y, w, h);
setHandlePointList(rectangle);
}
return handlePointIndex;
}
@Override
public void buildShape(MouseEventDouble mouseevent) {
Rectangle2D rectangle = null;
if (pts.size() > 1) {
if (!getHandlePoint(eHandlePoint.NW.index).equals(getHandlePoint(eHandlePoint.SE.index))) {
rectangle = new Rectangle2D.Double();
rectangle.setFrameFromDiagonal(getHandlePoint(eHandlePoint.NW.index),
getHandlePoint(eHandlePoint.SE.index));
}
}
setShape(rectangle, mouseevent);
updateLabel(mouseevent, getDefaultView2d(mouseevent));
}
@Override
public List<Measurement> getMeasurementList() {
return MEASUREMENT_LIST;
}
@Override
public List<MeasureItem> computeMeasurements(MeasurableLayer layer, boolean releaseEvent, Unit displayUnit) {
if (layer != null && layer.hasContent() && isShapeValid()) {
MeasurementsAdapter adapter = layer.getMeasurementAdapter(displayUnit);
if (adapter != null) {
ArrayList<MeasureItem> measVal = new ArrayList<>();
Rectangle2D rect = new Rectangle2D.Double();
rect.setFrameFromDiagonal(getHandlePoint(eHandlePoint.NW.index), getHandlePoint(eHandlePoint.SE.index));
double ratio = adapter.getCalibRatio();
if (TOP_LEFT_POINT_X.getComputed()) {
measVal.add(
new MeasureItem(TOP_LEFT_POINT_X, adapter.getXCalibratedValue(rect.getX()), adapter.getUnit()));
}
if (TOP_LEFT_POINT_Y.getComputed()) {
measVal.add(
new MeasureItem(TOP_LEFT_POINT_Y, adapter.getYCalibratedValue(rect.getY()), adapter.getUnit()));
}
if (CENTER_X.getComputed()) {
measVal.add(
new MeasureItem(CENTER_X, adapter.getXCalibratedValue(rect.getCenterX()), adapter.getUnit()));
}
if (CENTER_Y.getComputed()) {
measVal.add(
new MeasureItem(CENTER_Y, adapter.getYCalibratedValue(rect.getCenterY()), adapter.getUnit()));
}
if (WIDTH.getComputed()) {
measVal.add(new MeasureItem(WIDTH, ratio * rect.getWidth(), adapter.getUnit()));
}
if (HEIGHT.getComputed()) {
measVal.add(new MeasureItem(HEIGHT, ratio * rect.getHeight(), adapter.getUnit()));
}
if (AREA.getComputed()) {
Double val = rect.getWidth() * rect.getHeight() * ratio * ratio;
String unit = "pix".equals(adapter.getUnit()) ? adapter.getUnit() : adapter.getUnit() + "2"; //$NON-NLS-1$ //$NON-NLS-2$
measVal.add(new MeasureItem(AREA, val, unit));
}
if (PERIMETER.getComputed()) {
Double val = (rect.getWidth() + rect.getHeight()) * 2 * ratio;
measVal.add(new MeasureItem(PERIMETER, val, adapter.getUnit()));
}
List<MeasureItem> stats = getImageStatistics(layer, releaseEvent);
if (stats != null) {
measVal.addAll(stats);
}
return measVal;
}
}
return Collections.emptyList();
}
protected void setHandlePointList(Rectangle2D rectangle) {
double x = rectangle.getX();
double y = rectangle.getY();
double w = rectangle.getWidth();
double h = rectangle.getHeight();
while (pts.size() < pointNumber) {
pts.add(new Point2D.Double());
}
setHandlePoint(eHandlePoint.NW.index, new Point2D.Double(x, y));
setHandlePoint(eHandlePoint.N.index, new Point2D.Double(x + w / 2, y));
setHandlePoint(eHandlePoint.NE.index, new Point2D.Double(x + w, y));
setHandlePoint(eHandlePoint.E.index, new Point2D.Double(x + w, y + h / 2));
setHandlePoint(eHandlePoint.SE.index, new Point2D.Double(x + w, y + h));
setHandlePoint(eHandlePoint.S.index, new Point2D.Double(x + w / 2, y + h));
setHandlePoint(eHandlePoint.SW.index, new Point2D.Double(x, y + h));
setHandlePoint(eHandlePoint.W.index, new Point2D.Double(x, y + h / 2));
}
public enum eHandlePoint {
NONE(-1), NW(0), SE(1), NE(2), SW(3), N(4), S(5), E(6), W(7);
// 0 and 1 must be diagonal point of rectangle
static final Map<Integer, eHandlePoint> map = new HashMap<>(eHandlePoint.values().length);
static {
for (eHandlePoint corner : eHandlePoint.values()) {
map.put(corner.index, corner);
}
}
public final int index;
eHandlePoint(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
static eHandlePoint valueFromIndex(int index) {
return Optional.ofNullable(map.get(index))
.orElseThrow(() -> new RuntimeException("Not a valid index for a rectangular DragGraphic : " + index)); //$NON-NLS-1$
}
eHandlePoint getVerticalMirror() {
switch (this) {
case NW:
return eHandlePoint.NE;
case NE:
return eHandlePoint.NW;
case W:
return eHandlePoint.E;
case E:
return eHandlePoint.W;
case SW:
return eHandlePoint.SE;
case SE:
return eHandlePoint.SW;
default:
return this;
}
}
eHandlePoint getHorizontalMirror() {
switch (this) {
case NW:
return eHandlePoint.SW;
case SW:
return eHandlePoint.NW;
case N:
return eHandlePoint.S;
case S:
return eHandlePoint.N;
case NE:
return eHandlePoint.SE;
case SE:
return eHandlePoint.NE;
default:
return this;
}
}
}
}