/******************************************************************************* * 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.line; import java.awt.Shape; import java.awt.geom.Path2D; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Collections; import java.util.List; 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.AbstractDragGraphic; 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 = "polyline") @XmlRootElement(name = "polyline") public class PolylineGraphic extends AbstractDragGraphic { private static final long serialVersionUID = -4516499480176907755L; public static final Integer POINTS_NUMBER = UNDEFINED; public static final Icon ICON = new ImageIcon(PolylineGraphic.class.getResource("/icon/22x22/draw-polyline.png")); //$NON-NLS-1$ public static final Measurement LINE_LENGTH = new Measurement(Messages.getString("measure.length"), 5, true, true, true); //$NON-NLS-1$ protected static final List<Measurement> MEASUREMENT_LIST = new ArrayList<>(); static { MEASUREMENT_LIST.add(LINE_LENGTH); } public PolylineGraphic() { super(POINTS_NUMBER); } public PolylineGraphic(PolylineGraphic graphic) { super(graphic); } @Override public PolylineGraphic copy() { return new PolylineGraphic(this); } @Override public Icon getIcon() { return ICON; } @Override public String getUIName() { return Messages.getString("MeasureToolBar.polyline"); //$NON-NLS-1$ } @Override protected void prepareShape() throws InvalidShapeException { setPointNumber(pts.size()); buildShape(null); if (!isShapeValid()) { int lastPointIndex = pts.size() - 1; if (lastPointIndex > 0) { Point2D checkPoint = pts.get(lastPointIndex); /* * Must not have two or several points with the same position at the end of the list (two points is the * convention to have a uncompleted shape when drawing) */ for (int i = lastPointIndex - 1; i >= 0; i--) { if (checkPoint.equals(pts.get(i))) { pts.remove(i); } else { break; } } setPointNumber(pts.size()); } if (!isShapeValid() || pts.size() < 2) { throw new IllegalStateException("This Polyline cannot be drawn"); //$NON-NLS-1$ } buildShape(null); } } @Override public void buildShape(MouseEventDouble mouseEvent) { Shape newShape = null; Optional<Point2D.Double> firstHandlePoint = pts.stream().findFirst(); if (firstHandlePoint.isPresent()) { Point2D.Double p = firstHandlePoint.get(); Path2D polygonPath = new Path2D.Double(Path2D.WIND_NON_ZERO, pts.size()); polygonPath.moveTo(p.getX(), p.getY()); for (Point2D.Double pt : pts) { if (pt == null) { break; } polygonPath.lineTo(pt.getX(), pt.getY()); } newShape = polygonPath; } setShape(newShape, mouseEvent); updateLabel(mouseEvent, getDefaultView2d(mouseEvent)); } @Override public boolean isShapeValid() { if (!isGraphicComplete()) { return false; } int lastPointIndex = pts.size() - 1; if (lastPointIndex > 0) { Point2D checkPoint = pts.get(lastPointIndex); if (Objects.equals(checkPoint, pts.get(--lastPointIndex))) { return false; } } return true; } @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<>(5); double ratio = adapter.getCalibRatio(); String unitStr = adapter.getUnit(); // Get copy to be sure that point value are not modified any more and filter point equal to null. List<Point2D.Double> handlePointListcopy = new ArrayList<>(pts.size()); for (Point2D.Double handlePt : pts) { if (handlePt != null) { handlePointListcopy.add((Point2D.Double) handlePt.clone()); } } if (LINE_LENGTH.getComputed()) { Double val = (handlePointListcopy.size() > 1) ? getPerimeter(handlePointListcopy) * ratio : null; measVal.add(new MeasureItem(LINE_LENGTH, val, unitStr)); } return measVal; } } return Collections.emptyList(); } @Override public List<Measurement> getMeasurementList() { return MEASUREMENT_LIST; } protected Double getPerimeter(List<Point2D.Double> handlePointList) { if (handlePointList.size() > 1) { Double perimeter = 0d; Point2D.Double pLast = handlePointList.get(0); for (Point2D.Double p2 : handlePointList) { perimeter += pLast.distance(p2); pLast = p2; } return perimeter; } return null; } @Override public void forceToAddPoints(Integer fromPtIndex) { if (getVariablePointsNumber() && fromPtIndex >= 0 && fromPtIndex < pts.size()) { if (fromPtIndex < pts.size() - 1) { // Add only one point pts.add(fromPtIndex, getHandlePoint(fromPtIndex)); pointNumber++; } else { // Continue to draw when it is the last point setPointNumber(UNDEFINED); } } } }