package com.baselet.element.relation.helper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.baselet.control.basics.geom.GeometricFunctions;
import com.baselet.control.basics.geom.Line;
import com.baselet.control.basics.geom.PointDouble;
import com.baselet.control.basics.geom.Rectangle;
import com.baselet.control.constants.SharedConstants;
import com.baselet.control.enums.AlignHorizontal;
import com.baselet.control.enums.Direction;
import com.baselet.diagram.draw.DrawHandler;
import com.baselet.diagram.draw.helper.ColorOwn;
import com.baselet.element.sticking.PointDoubleIndexed;
public class RelationDrawer {
static final double SHORTEN_IF_ARROW = 1; // issue 270: if an arrow end is attached to a line, the line is shorter by this value to avoid the line going through the arrow-end
static final double ARROWEND_DISPLACEMENT = 0.5; // issue 270: the arrow end is placed slightly displaced to the inside to avoid going through elemens which they point at
public static final double ARROW_LENGTH = RelationPointConstants.POINT_SELECTION_RADIUS * 1.3;
private static final double DIAGONAL_CROSS_LENGTH = RelationPointConstants.POINT_SELECTION_RADIUS * 0.9;
private static final double BOX_SIZE = 20;
public static Rectangle drawBoxArrow(DrawHandler drawer, Line line, boolean drawOnStart, String matchedText, ResizableObject resizableObject) {
double oldFontsize = drawer.getFontSize();
drawer.setFontSize(12);
double height = BOX_SIZE;
double distance = drawer.getDistanceBorderToText();
double width = Math.max(BOX_SIZE, drawer.textWidth(matchedText) + distance * 2);
PointDoubleIndexed point = (PointDoubleIndexed) line.getPoint(drawOnStart);
Rectangle r = new Rectangle(point.getX() - width / 2, point.getY() - height / 2, width, height);
drawer.drawRectangle(r);
int arrow = 4;
ColorOwn oldBgColor = drawer.getBackgroundColor();
drawer.setBackgroundColor(drawer.getForegroundColor());
if (matchedText.equals("^")) {
PointDouble start = new PointDouble(point.getX(), point.getY() - arrow);
drawer.drawLines(start, new PointDouble(point.getX() + arrow, point.getY() + arrow), new PointDouble(point.getX() - arrow, point.getY() + arrow), start);
}
else if (matchedText.equals("<")) {
PointDouble start = new PointDouble(point.getX() - arrow, point.getY());
drawer.drawLines(start, new PointDouble(point.getX() + arrow, point.getY() - arrow), new PointDouble(point.getX() + arrow, point.getY() + arrow), start);
}
else if (matchedText.equals(">")) {
PointDouble start = new PointDouble(point.getX() + arrow, point.getY());
drawer.drawLines(start, new PointDouble(point.getX() - arrow, point.getY() - arrow), new PointDouble(point.getX() - arrow, point.getY() + arrow), start);
}
else if (matchedText.equals("v")) {
PointDouble start = new PointDouble(point.getX() - arrow, point.getY() - arrow);
drawer.drawLines(start, new PointDouble(point.getX() + arrow, point.getY() - arrow), new PointDouble(point.getX(), point.getY() + arrow), start);
}
else if (matchedText.equals("=")) {
int dist = 2;
int size = 6;
drawer.drawLines(new PointDouble(point.getX() - size, point.getY() - dist), new PointDouble(point.getX() + size, point.getY() - dist), new PointDouble(point.getX(), point.getY() - size));
drawer.drawLines(new PointDouble(point.getX() + size, point.getY() + dist), new PointDouble(point.getX() - size, point.getY() + dist), new PointDouble(point.getX(), point.getY() + size));
}
else {
drawer.print(matchedText, new PointDouble(point.getX() - width / 2 + distance, point.getY() + drawer.textHeightMax() / 2), AlignHorizontal.LEFT);
resizableObject.setPointMinSize(point.getIndex(), new Rectangle(-width / 2, -height / 2, width, height));
}
drawer.setFontSize(oldFontsize);
drawer.setBackgroundColor(oldBgColor);
return r;
}
public static enum ArrowEndType {
NORMAL, CLOSED, DIAMOND, MEASURE
}
public static void drawArrowToLine(DrawHandler drawer, Line line, boolean drawOnStart, ArrowEndType arrowEndType, boolean fillBody, boolean invertArrow) {
drawArrowToLine(line.getPointOnLineWithDistanceFrom(drawOnStart, ARROWEND_DISPLACEMENT), drawer, line, drawOnStart, arrowEndType, fillBody, invertArrow);
}
public static void drawArrowToLine(PointDouble point, DrawHandler drawer, Line line, boolean drawOnStart, ArrowEndType arrowEndType, boolean fillBody, boolean invertArrow) {
if (invertArrow) {
point = line.getPointOnLineWithDistanceFrom(drawOnStart, ARROW_LENGTH);
drawOnStart = !drawOnStart;
}
int arrowAngle = drawOnStart ? 150 : 30;
PointDouble p1 = calcPointArrow(point, line.getAngleOfSlope() - arrowAngle);
PointDouble p2 = calcPointArrow(point, line.getAngleOfSlope() + arrowAngle);
List<PointDouble> points = new ArrayList<PointDouble>(Arrays.asList(p1, point));
if (arrowEndType == ArrowEndType.MEASURE) {
PointDouble m1 = calcPoint(point, line.getAngleOfSlope() + 90, SharedConstants.DEFAULT_GRID_SIZE);
PointDouble m2 = calcPoint(point, line.getAngleOfSlope() - 90, SharedConstants.DEFAULT_GRID_SIZE);
points.add(m1);
points.add(m2);
points.add(point);
}
points.add(p2);
if (arrowEndType == ArrowEndType.CLOSED) {
points.add(p1);
}
else if (arrowEndType == ArrowEndType.DIAMOND) {
double lengthDiamond = GeometricFunctions.getDistanceBetweenLineAndPoint(p1, p2, point) * 2;
PointDouble pDiamond = drawOnStart ? line.getPointOnLineWithDistanceFrom(true, lengthDiamond) : line.getPointOnLineWithDistanceFrom(false, lengthDiamond);
points.add(pDiamond);
points.add(p1);
}
if (fillBody) {
ColorOwn bgColor = drawer.getBackgroundColor();
drawer.setBackgroundColor(drawer.getForegroundColor());
drawer.drawLines(points);
drawer.setBackgroundColor(bgColor);
}
else {
drawer.drawLines(points);
}
}
private static PointDouble calcPointArrow(PointDouble point, double angleTotal) {
return calcPoint(point, angleTotal, ARROW_LENGTH);
}
private static PointDouble calcPointCross(PointDouble point, double angleTotal) {
return calcPoint(point, angleTotal, DIAGONAL_CROSS_LENGTH);
}
private static PointDouble calcPoint(PointDouble point, double angleTotal, double length) {
double x = point.x + length * Math.cos(Math.toRadians(angleTotal));
double y = point.y + length * Math.sin(Math.toRadians(angleTotal));
return new PointDouble(x, y);
}
public static void drawCircle(DrawHandler drawer, Line line, boolean drawOnStart, ResizableObject resizableObject, Direction openDirection, boolean drawCross) {
PointDoubleIndexed point = (PointDoubleIndexed) line.getPoint(drawOnStart);
if (openDirection == null) { // full circle
drawer.drawCircle(point.getX(), point.getY(), RelationPointConstants.POINT_SELECTION_RADIUS);
}
else if (openDirection == Direction.LEFT || openDirection == Direction.RIGHT) { // interface half circle
ColorOwn bg = drawer.getBackgroundColor();
drawer.setBackgroundColor(ColorOwn.TRANSPARENT);
double circleRadius = RelationPointConstants.POINT_SELECTION_RADIUS * 3;
Direction directionOfCircle = line.getDirectionOfLine(drawOnStart);
if (directionOfCircle == Direction.RIGHT) {
drawer.drawArc(point.getX(), point.getY() - circleRadius / 2, circleRadius, circleRadius, 90, 180, true);
resizableObject.setPointMinSize(point.getIndex(), new Rectangle(-circleRadius / 4, -circleRadius / 2, circleRadius * 0.75, circleRadius));
}
else if (directionOfCircle == Direction.DOWN) {
drawer.drawArc(point.getX() - circleRadius / 2, point.getY(), circleRadius, circleRadius, 0, 180, true);
resizableObject.setPointMinSize(point.getIndex(), new Rectangle(-circleRadius / 2, -circleRadius / 4, circleRadius, circleRadius * 0.75));
}
else if (directionOfCircle == Direction.LEFT) {
drawer.drawArc(point.getX() - circleRadius, point.getY() - circleRadius / 2, circleRadius, circleRadius, -90, 180, true);
resizableObject.setPointMinSize(point.getIndex(), new Rectangle(-circleRadius / 2, -circleRadius / 2, circleRadius * 0.75, circleRadius));
}
else {
drawer.drawArc(point.getX() - circleRadius / 2, point.getY() - circleRadius, circleRadius, circleRadius, -180, 180, true);
resizableObject.setPointMinSize(point.getIndex(), new Rectangle(-circleRadius / 2, -circleRadius / 2, circleRadius, circleRadius * 0.75));
}
drawer.setBackgroundColor(bg);
}
if (drawCross) {
double length = RelationPointConstants.POINT_SELECTION_RADIUS / 2;
drawer.drawLine(point.getX() - length, point.getY(), point.getX() + length, point.getY());
drawer.drawLine(point.getX(), point.getY() - length, point.getX(), point.getY() + length);
}
}
public static void drawDiagonalCross(DrawHandler drawer, Line line, boolean drawOnStart, ResizableObject resizableObject, Direction openDirection, boolean drawCross) {
PointDouble p = line.getPointOnLineWithDistanceFrom(drawOnStart, ARROW_LENGTH);
drawer.drawLines(calcPointCross(p, line.getAngleOfSlope() + 45), calcPointCross(p, line.getAngleOfSlope() - 135));
drawer.drawLines(calcPointCross(p, line.getAngleOfSlope() - 45), calcPointCross(p, line.getAngleOfSlope() + 135));
}
}