package com.nutiteq.components; import henson.midp.Float11; import javax.microedition.lcdui.Graphics; import com.nutiteq.maps.GeoMap; import com.nutiteq.utils.Utils; /** * Line object to be displayed on map */ public class Line implements OnMapElement { private final WgsPoint[] points; private MapPos[] positions; private Point boundingBoxMin; private Point boundingBoxMax; private LineStyle style; private final boolean serverSideRender; private final Label label; /** * Constructor for line object with default style * * @param points * points in line (in WGS84) */ public Line(final WgsPoint[] points) { this(points, new LineStyle(LineStyle.DEFAULT_COLOR, LineStyle.DEFAULT_WIDTH), false); } public Line(final WgsPoint[] points, final boolean serverSideRender) { this(points, new LineStyle(LineStyle.DEFAULT_COLOR, LineStyle.DEFAULT_WIDTH), serverSideRender); } /** * Constructor for line with user defined style * * @param points * points in line (in WGS84) * @param style * line style */ public Line(final WgsPoint[] points, final LineStyle style) { this(points, style, false); } public Line(final WgsPoint[] points, final LineStyle style, final Label label) { this(points, style, label, false); } public Line(final WgsPoint[] points, final LineStyle style, final boolean serverSideRender) { this(points, style, null, serverSideRender); } public Line(final WgsPoint[] points, final LineStyle style, final Label label, final boolean serverSideRender) { this.points = points; this.style = style; this.label = label; this.serverSideRender = serverSideRender; } public boolean isVisible(final int viewX, final int viewY, final int viewWidth, final int viewHeight, final int zoom) { if (!viewWithinBoundingBox(viewX, viewY, viewWidth, viewHeight)) { return false; } for (int j = 0; j < positions.length - 1; j++) { // work with point pairs final MapPos start = positions[j]; final MapPos end = positions[j + 1]; //TODO jaanus : check this hack! Problem in NutiGuide if (start == null || end == null) { continue; } if (Utils.rectanglesIntersect(start.getX(), start.getY(), end.getX() - start.getX(), end .getY() - start.getY(), viewX, viewY, viewWidth, viewHeight)) { return true; } } return false; } public void paint(final Graphics g, final MapPos middlePoint, final int displayCenterX, final int displayCenterY, final Rectangle changedMapArea) { if (serverSideRender) { return; } g.setColor(style.getColor()); final int lineWidth = style.getWidth(); for (int j = 0; j < positions.length - 1; j++) { // work with point pairs final MapPos start = positions[j]; final MapPos end = positions[j + 1]; if (Utils.rectanglesIntersect(start.getX(), start.getY(), end.getX() - start.getX(), end .getY() - start.getY(), changedMapArea.getX(), changedMapArea.getY(), changedMapArea.getWidth(), changedMapArea.getHeight())) { final int startX = start.getX() - middlePoint.getX() + displayCenterX; final int startY = start.getY() - middlePoint.getY() + displayCenterY; final int endX = end.getX() - middlePoint.getX() + displayCenterX; final int endY = end.getY() - middlePoint.getY() + displayCenterY; if (lineWidth < 3) { final int xLength = Math.abs(endX - startX); final int yLength = Math.abs(endY - startY); final int xModify = xLength > yLength ? 0 : 1; final int yModify = xLength > yLength ? 1 : 0; for (int i = 0; i < lineWidth; i++) { g.drawLine(startX + xModify * i, startY + yModify * i, endX + xModify * i, endY + yModify * i); } } else { drawSegment(g, startX, startY, endX, endY, lineWidth); } } } } /** * Draw a line as a polygon. * * @param g * Graphics object * @param x1 * first point * @param y1 * first point * @param x2 * second point * @param y2 * second point */ private void drawSegment(final Graphics g, final int x1, final int y1, final int x2, final int y2, final int lineWidth) { final double phi = Float11.atan2(y2 - y1, x2 - x1); final double sinphi = Math.sin(phi); final double cosphi = Math.cos(phi); final int dx = (int) (lineWidth / 2D * sinphi); final int dy = (int) (lineWidth / 2D * cosphi); final int xx1 = x1 + dx; final int yy1 = y1 - dy; final int xx2 = x1 - dx; final int yy2 = y1 + dy; final int xx3 = x2 + dx; final int yy3 = y2 - dy; final int xx4 = x2 - dx; final int yy4 = y2 + dy; g.fillTriangle(xx1, yy1, xx2, yy2, xx3, yy3); g.fillTriangle(xx4, yy4, xx2, yy2, xx3, yy3); } /** * Not part of public API. Removed by obfuscator */ public void calculatePosition(final GeoMap displayedMap, final int zoomLevel) { int minX = Integer.MAX_VALUE; int minY = Integer.MAX_VALUE; int maxX = Integer.MIN_VALUE; int maxY = Integer.MIN_VALUE; positions = new MapPos[points.length]; for (int j = 0; j < points.length; j++) { positions[j] = displayedMap.wgsToMapPos(points[j].toInternalWgs(), zoomLevel); final MapPos pos = positions[j]; minX = Math.min(minX, pos.getX()); minY = Math.min(minY, pos.getY()); maxX = Math.max(maxX, pos.getX()); maxY = Math.max(maxY, pos.getY()); } boundingBoxMin = new Point(minX, minY); boundingBoxMax = new Point(maxX, maxY); } /** * Set line style. */ public void setStyle(final LineStyle lineStyle) { style = lineStyle; } public WgsPoint[] getPoints() { return points; } /** * Not part of public API. Removed by obfuscator */ public LineStyle getLineStyle() { return style; } public boolean isCentered(final MapPos cursorPoint) { if (!viewWithinBoundingBox(cursorPoint.getX(), cursorPoint.getY(), 1, 1)) { return false; } final int lineWidth = style.getWidth(); //put a box around cursor final Rectangle cursorBox = new Rectangle(cursorPoint.getX() - lineWidth, cursorPoint.getY() - lineWidth, lineWidth * 2, lineWidth * 2); for (int i = 0; i < positions.length - 1; i++) { final MapPos one = positions[i]; final MapPos two = positions[i + 1]; if (!Utils.rectanglesIntersect(one.getX(), one.getY(), two.getX() - one.getX(), two.getY() - one.getY(), cursorBox.getX(), cursorBox.getY(), cursorBox.getWidth(), cursorBox .getHeight())) { continue; } final int cursorDistance = cursorPoint.distanceFromLineInPixels(one.getX(), one.getY(), two .getX(), two.getY()); if (lineWidth >= cursorDistance) { return true; } } return false; } private boolean viewWithinBoundingBox(final int viewX, final int viewY, final int viewW, final int viewH) { return Utils.rectanglesIntersect(boundingBoxMin.getX(), boundingBoxMin.getY(), boundingBoxMax .getX() - boundingBoxMin.getX(), boundingBoxMax.getY() - boundingBoxMin.getY(), viewX, viewY, viewW, viewH); } public int distanceInPixels(final MapPos cursorOnMap) { //TODO jaanus : check this return 0; } public Label getLabel() { return label; } }