/******************************************************************************* * Copyright 2016 Observational Health Data Sciences and Informatics * * This file is part of WhiteRabbit * * 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.ohdsi.rabbitInAHat; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Polygon; import org.ohdsi.rabbitInAHat.dataModel.ItemToItemMap; public class Arrow implements MappingComponent { public enum HighlightStatus { IS_SELECTED (new Color(204, 255, 204, 192)), BOTH_SELECTED (new Color(255, 255, 0, 192)), SOURCE_SELECTED (new Color(255, 128, 0, 192)), TARGET_SELECTED (new Color(0, 0, 255, 192)), NONE_SELECTED (new Color(128, 128, 128, 192)), IS_COMPLETED (new Color(128, 128, 128, 50)); private final Color color; HighlightStatus(Color color) { this.color = color; } } public static float thickness = 5; public static int headThickness = 15; public static Color color = HighlightStatus.NONE_SELECTED.color; private static BasicStroke dashed = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[] { 10.f }, 0.0f); private int x1; private int y1; private int x2; private int y2; private LabeledRectangle source = null; private LabeledRectangle target = null; private ItemToItemMap itemToItemMap; private int width; private int height; private Polygon polygon; private boolean isSelected = false; private boolean isVisible = true; public Arrow(LabeledRectangle source) { this.source = source; } public Arrow(int x1, int y1, int x2, int y2) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.width = Math.abs(x1 - x2); this.height = Math.abs(y1 - y2); } public Arrow(LabeledRectangle source, LabeledRectangle target) { this.source = source; this.target = target; } public Arrow(LabeledRectangle source, LabeledRectangle target, ItemToItemMap itemToItemMap) { this.source = source; this.target = target; this.itemToItemMap = itemToItemMap; } public ItemToItemMap getItemToItemMap() { return itemToItemMap; } public void setItemToItemMap(ItemToItemMap itemToItemMap) { this.itemToItemMap = itemToItemMap; } public int getWidth() { return width; } public int getHeight() { return height; } public boolean isVisible(){ return isVisible; } public LabeledRectangle getSource() { return source; } public void setTargetPoint(Point point) { if (point == null) { x2 = source.getX() + source.getWidth() + Arrow.headThickness; y2 = source.getY() + source.getHeight() / 2; } else { x2 = point.x; y2 = point.y; } } public void paint(Graphics g) { if (!isVisible) return; if( source != null && target != null){ if(!source.isVisible() || !target.isVisible()){ return; } } Graphics2D g2d = (Graphics2D) g; if (source != null) { x1 = source.getX() + source.getWidth(); y1 = source.getY() + source.getHeight() / 2; width = Math.abs(x1 - x2); height = Math.abs(y1 - y2); } if (target != null) { x2 = target.getX(); y2 = target.getY() + target.getHeight() / 2; width = Math.abs(x1 - x2); height = Math.abs(y1 - y2); } int nPoints = 25; int[] xPoints = new int[nPoints * 2 + 3]; int[] yPoints = new int[nPoints * 2 + 3]; float widthMinHead = getWidth() - headThickness; float stepSize = widthMinHead / (float) (nPoints - 1); for (int i = 0; i < nPoints; i++) { float x = x1 + stepSize * i; float y = (float) (y1 + (Math.cos(Math.PI * i / (float) nPoints) / 2d - 0.5) * (y1 - y2)); xPoints[i] = Math.round(x); yPoints[i] = Math.round(y - thickness); xPoints[nPoints * 2 + 3 - i - 1] = Math.round(x); yPoints[nPoints * 2 + 3 - i - 1] = Math.round(y + thickness); } xPoints[nPoints] = x2 - headThickness; yPoints[nPoints] = y2 - headThickness; xPoints[nPoints + 1] = x2; yPoints[nPoints + 1] = y2; xPoints[nPoints + 2] = x2 - headThickness; yPoints[nPoints + 2] = y2 + headThickness; polygon = new Polygon(xPoints, yPoints, nPoints * 2 + 3); g2d.setColor(fillColor()); g2d.fillPolygon(polygon); if (isSelected) { g2d.setColor(Color.BLACK); g2d.setStroke(dashed); g2d.drawPolygon(polygon); } } public Color fillColor() { return getHighlightStatus().color; } private boolean isTargetSelected() { return target != null && target.isSelected(); } private boolean isSourceSelected() { return source != null && source.isSelected(); } public static void drawArrowHead(Graphics2D g2d, int x, int y) { int nPoints = 3; int[] xPoints = new int[nPoints]; int[] yPoints = new int[nPoints]; xPoints[0] = x - headThickness; yPoints[0] = y - headThickness; xPoints[1] = x; yPoints[1] = y; xPoints[2] = x - headThickness; yPoints[2] = y + headThickness; g2d.setColor(color); g2d.fillPolygon(xPoints, yPoints, nPoints); } public void setTarget(LabeledRectangle target) { this.target = target; } public LabeledRectangle getTarget() { return target; } public HighlightStatus getHighlightStatus() { if (isSelected()) { return HighlightStatus.IS_SELECTED; } else if (isSourceSelected() && isTargetSelected()) { return HighlightStatus.BOTH_SELECTED; } else if (isSourceSelected()) { return HighlightStatus.SOURCE_SELECTED; } else if (isTargetSelected()) { return HighlightStatus.TARGET_SELECTED; } else if (isCompleted()) { return HighlightStatus.IS_COMPLETED; } else { return HighlightStatus.NONE_SELECTED; } } public boolean isSelected() { return isSelected; } public void setSelected(boolean isSelected) { this.isSelected = isSelected; } public boolean isCompleted() { if (getItemToItemMap() != null) { return getItemToItemMap().isCompleted(); } else { return false; } } public boolean contains(Point point) { return polygon.contains(point); } public void setVisible(boolean value) { isVisible = value; } public boolean isSourceAndTargetVisible(){ return source.isVisible() && target.isVisible(); } public boolean isConnected(){ return source != null && target != null; } }