/* * Licensed Materials - Property of Rogue Wave Software, Inc. * © Copyright Rogue Wave Software, Inc. 2014, 2015 * © Copyright IBM Corp. 2009, 2014 * © Copyright ILOG 1996, 2009 * All Rights Reserved. * * Note to U.S. Government Users Restricted Rights: * The Software and Documentation were developed at private expense and * are "Commercial Items" as that term is defined at 48 CFR 2.101, * consisting of "Commercial Computer Software" and * "Commercial Computer Software Documentation", as such terms are * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4, * as applicable. */ import ilog.views.IlvGraphic; import ilog.views.IlvGraphicBag; import ilog.views.IlvGraphicUtil; import ilog.views.IlvManager; import ilog.views.IlvPoint; import ilog.views.IlvRect; import ilog.views.IlvStroke; import ilog.views.IlvTransformer; import ilog.views.graphic.IlvGraphicSet; import ilog.views.graphic.IlvPolyPoints; import ilog.views.io.IlvFieldNotFoundException; import ilog.views.io.IlvInputStream; import ilog.views.io.IlvOutputStream; import ilog.views.io.IlvReadFileException; import ilog.views.maps.IlvCoordinateSystemProperty; import ilog.views.maps.IlvLinearUnit; import ilog.views.maps.IlvScaleController; import ilog.views.maps.projection.IlvProjectionUtil; import ilog.views.maps.srs.coordsys.IlvCoordinateSystem; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.io.IOException; class LineInfo { float len; float ddx; float ddy; float x1; float y1; float x2; float y2; float l1x1; float l1y1; float l1x2; float l1y2; float l2x1; float l2y1; float l2x2; float l2y2; IlvPoint p1 = new IlvPoint(); IlvPoint p2 = new IlvPoint(); float _ix; float _iy; boolean doJoin; float jx1; float jy1; float jx2; float jy2; static final float SMALL = 1e-10f; LineInfo() { } void create(IlvPoint p[], int i, IlvTransformer t, float spacing) { p1.x = p[i].x; p1.y = p[i].y; i++; p2.x = p[i].x; p2.y = p[i].y; if(t != null) { t.apply(p1); t.apply(p2); } x1 = p1.x; y1 = p1.y; x2 = p2.x; y2 = p2.y; float dx = x2 - x1; float dy = y2 - y1; len = (float)Math.sqrt(dx * dx + dy * dy); ddx = spacing * dy / len; ddy = spacing * dx / len; l1x1 = x1 + ddx; l1y1 = y1 - ddy; l1x2 = x2 + ddx; l1y2 = y2 - ddy; l2x1 = x1 - ddx; l2y1 = y1 + ddy; l2x2 = x2 - ddx; l2y2 = y2 + ddy; } void join(float x11, float y11, float x21, float y21) { jx1 = x11; jy1 = y11; jx2 = x21; jy2 = y21; doJoin = true; } void intersect(LineInfo info) { doJoin = false; if(intersect(l1x1, l1y1, l1x2, l1y2, info.l1x1, info.l1y1, info.l1x2, info.l1y2)) { float x = _ix; float y = _iy; l1x2 = x; l1y2 = y; info.l1x1 = x; info.l1y1 = y; } else { join(l1x2, l1y2, info.l1x1, info.l1y1); } if(intersect(l2x1, l2y1, l2x2, l2y2, info.l2x1, info.l2y1, info.l2x2, info.l2y2)) { float x = _ix; float y = _iy; l2x2 = x; l2y2 = y; info.l2x1 = x; info.l2y1 = y; } else { join(l2x2, l2y2, info.l2x1, info.l2y1); } } boolean intersect(float x11, float y11, float x21, float y21, float x3, float y3, float x4, float y4) { float d = (y4 - y3) * (x21 - x11) - (x4 - x3) * (y21 - y11); if(Math.abs(d) == 0.) return false; float na = ((x4 - x3) * (y11 - y3) - (y4 - y3) * (x11 - x3)) / d; if(na < 0f || na > 1f) return false; float nb = ((x21 - x11) * (y11 - y3) - (y21 - y11) * (x11 - x3)) / d; if(nb < 0f || nb > 1f) return false; _ix = (int)(x11 + na * (x21 - x11)); _iy = (int)(y11 + na * (y21 - y11)); return true; } void affect(LineInfo source) { len = source.len; ddx = source.ddx; ddy = source.ddy; x1 = source.x1; y1 = source.y1; x2 = source.x2; y2 = source.y2; l1x1 = source.l1x1; l1y1 = source.l1y1; l1x2 = source.l1x2; l1y2 = source.l1y2; l2x1 = source.l2x1; l2y1 = source.l2y1; l2x2 = source.l2x2; l2y2 = source.l2y2; doJoin = false; } } /** * A graphical object representing a road/railroad. * This object is configured by another class, <code>IlvRailroadAttributes</code>. */ public class IlvRailroad extends IlvPolyPoints { private IlvRailroadAttributes _railAttributes; private LineInfo _current = new LineInfo(); private LineInfo _prev = new LineInfo(); private LineInfo _next = new LineInfo(); private IlvPoint[] _tmp; private int _x[]; private int _y[]; BasicStroke _basicStroke; BasicStroke _resetStroke = new BasicStroke(); public IlvRailroad(IlvPoint[] points, boolean copy) { super(points, copy); } public IlvRailroad(IlvPoint[] points, boolean copy, IlvRailroadAttributes a) { super(points, copy); setRailroadAttributes(a); } public IlvRailroad(IlvRailroad source) { super(source); if (source._railAttributes != null) source.setRailroadAttributes(source._railAttributes.copy()); } public IlvRailroad(IlvInputStream stream) throws IlvReadFileException { super(stream); try { _railAttributes = (IlvRailroadAttributes)stream.readPersistentObject("railAttributes"); } catch (IlvFieldNotFoundException e) { } } public void write(IlvOutputStream stream) throws IOException { super.write(stream); if (_railAttributes != null) stream.write("railAttributes", _railAttributes); } public IlvGraphic copy() { return new IlvRailroad(this); } public IlvRailroadAttributes getRailroadAttributes() { if (_railAttributes == null) _railAttributes = new IlvRailroadAttributes(); return _railAttributes; } public void setRailroadAttributes(IlvRailroadAttributes ra) { _railAttributes = ra; } private Double _factor; private double getZoomFactorFromScale(double scale) { if (_factor != null) return _factor.doubleValue(); IlvManager manager = null; IlvGraphicBag b = getGraphicBag(); while (b instanceof IlvGraphicSet) b = ((IlvGraphic)b).getGraphicBag(); if (b instanceof IlvManager) manager = (IlvManager)b; double tFactor = 1.; if (manager != null) { IlvCoordinateSystem cs = IlvCoordinateSystemProperty.GetCoordinateSystem(manager); if(cs == null) tFactor = 1.; else { IlvLinearUnit unit = IlvProjectionUtil.GetLinearUnit(cs); tFactor = unit.toMeters(scale) * 1000f; tFactor /= IlvScaleController.GetScreenPixelSizeMM(); } } _factor = new Double(tFactor); return tFactor; } public float getRailSpacing(IlvTransformer t) { IlvRailroadAttributes ra = getRailroadAttributes(); float val = ra.getRailSpacing(); float max = ra.getMaximumRailSpacing(); float scale = ra.getScale(); double zl = getZoomFactorFromScale(scale); if (max == 0) return val; float zoomlevel = (t == null ? 1f : (float)t.zoomFactor()); double v = zoomlevel * val / zl; if (v >= max) v = max; return (float)v; } public float getTieWidth(IlvTransformer t) { IlvRailroadAttributes ra = getRailroadAttributes(); float val = ra.getTieWidth(); float max = ra.getMaximumTieWidth(); float scale = ra.getScale(); double zl = getZoomFactorFromScale(scale); if (max == 0) return val; float zoomlevel = (t == null ? 1f : (float)t.zoomFactor()); double v = zoomlevel * val / zl; if(v >= max) v = max; return (float)v; } public IlvRect boundingBox(IlvTransformer t) { IlvRect box; box = super.boundingBox(t); IlvRailroadAttributes ra = getRailroadAttributes(); float rs = getRailSpacing(t); float tw = getTieWidth(t); float width = (float)Math.max(tw, rs); box.expand(width / 2f); return box; } public boolean pointsInBBox() { return true; } public boolean contains(IlvPoint p, IlvPoint tp, IlvTransformer t) { float zoom = t == null ? 1f : (float)t.zoomFactor(); IlvPoint pts[] = getPoints(); IlvRailroadAttributes ra = getRailroadAttributes(); float tw = getTieWidth(t); float rs = getRailSpacing(t); float width = (float)Math.max(tw, rs); return IlvGraphicUtil.PointInPolyline(tp, pts, pts.length, width/zoom, IlvStroke.JOIN_MITER, IlvStroke.CAP_BUTT, t); } private void initTmpPoints() { if(_tmp != null) return; _tmp = new IlvPoint[3]; _tmp[0] = new IlvPoint(); _tmp[1] = new IlvPoint(); _tmp[2] = new IlvPoint(); } private void initTmpXYPoints() { if(_x == null) _x = new int[5]; if(_y == null) _y = new int[5]; } float drawTies(Graphics dst, IlvTransformer t, float offset, LineInfo current, LineInfo prev, LineInfo next) { float d = current.len; if (offset > d) return offset - d; IlvRailroadAttributes ra = getRailroadAttributes(); float tieSpacing = ra.getTieSpacing() * 2f; float tieWidth = getTieWidth(t); float tt = ra.getTieThickness(); if(tt > 0f) initTmpPoints(); dst.setColor(ra.getTieColor()); float x1 = current.x1; float y1 = current.y1; float dx = current.x2 - x1; float dy = current.y2 - y1; float ddx = tieWidth * dy / d; float ddy = tieWidth * dx / d; float u; for (u = offset; u < d; u += tieSpacing) { float ud = u / d; float px = x1 + ud * dx; float py = y1 + ud * dy; if(!dst.hitClip((int)(px - tieWidth) - 1, (int)(py - tieWidth) - 1, (int)(2f * tieWidth) + 2, (int)(2f * tieWidth) + 2)) continue; float fx = px - ddx; float fy = py + ddy; float tx = px + ddx; float ty = py - ddy; float limit = ra.getSlantingLimit(); if(limit > 0f) { if((next != null) && ((d - u) <= limit)) { float angle = (angle(current, next) - (float)Math.PI) / 2f; angle *= 1f - (d - u) / limit; float sa = -(float)Math.sin(angle); float ca = (float)Math.cos(angle); fx = -ddx * ca - ddy * sa + px; fy = -ddx * sa + ddy * ca + py; tx = ddx * ca + ddy * sa + px; ty = ddx * sa - ddy * ca + py; } if((prev != null) && (u <= limit)) { float angle = (angle(prev, current) - (float)Math.PI) / 2f; angle *= 1f - u / limit; float sa = (float)Math.sin(angle); float ca = (float)Math.cos(angle); fx = -ddx * ca - ddy * sa + px; fy = -ddx * sa + ddy * ca + py; tx = ddx * ca + ddy * sa + px; ty = ddx * sa - ddy * ca + py; } } if (tt > 0f) { _tmp[0].move(fx + 0.5f, fy + 0.5f); _tmp[1].move(tx + 0.5f, ty + 0.5f); IlvGraphicUtil.DrawPolyline(dst, _tmp, 2, tt, IlvStroke.JOIN_MITER, IlvStroke.CAP_BUTT, null, null); } else dst.drawLine((int)(fx), (int)(fy), (int)(tx), (int)(ty)); } return (u - d); } float angle(LineInfo l1, LineInfo l2) { float dx1 = l1.x1 - l1.x2; float dy1 = l1.y1 - l1.y2; float dx2 = l2.x2 - l2.x1; float dy2 = l2.y2 - l2.y1; float dp = dx1 * dx2 + dy1 * dy2; float cos = dp/(l1.len * l2.len); if (cos < -1f) cos = -1; if (cos > 1f) cos = 1f; float angle = (float)Math.acos(cos); float cp = dx1 * dy2 - dx2 * dy1; if (cp > 0) angle = 2f * (float)Math.PI - angle; return angle; } void drawBackground(Graphics dst, LineInfo info) { IlvRailroadAttributes ra = getRailroadAttributes(); Color b = ra.getBackground(); if (b != null) { initTmpXYPoints(); int i = 0; _x[i] = (int)(info.l1x1); _y[i] = (int)(info.l1y1); i++; _x[i] = (int)(info.l1x2); _y[i] = (int)(info.l1y2); i++; if (info.doJoin) { _x[i] = (int)(info.jx2); _y[i] = (int)(info.jy2); i++; } _x[i] = (int)(info.l2x2); _y[i] = (int)(info.l2y2); i++; _x[i] = (int)(info.l2x1); _y[i] = (int)(info.l2y1); i++; dst.setColor(b); dst.fillPolygon(_x, _y, i); } } void drawRails(Graphics dst, LineInfo info) { IlvRailroadAttributes ra = getRailroadAttributes(); dst.setColor(ra.getRailColor()); dst.drawLine((int)(info.l1x1), (int)(info.l1y1), (int)(info.l1x2), (int)(info.l1y2)); dst.drawLine((int)(info.l2x1), (int)(info.l2y1), (int)(info.l2x2), (int)(info.l2y2)); if (info.doJoin) dst.drawLine((int)(info.jx1), (int)(info.jy1), (int)(info.jx2), (int)(info.jy2)); } void drawCenterLine(Graphics dst, LineInfo info) { IlvRailroadAttributes ra = getRailroadAttributes(); Color c = ra.getCenterLineColor(); dst.setColor(c); float lw = ra.getCenterLineWidth(); boolean stroked = false; if (lw > 1.0) { if((_basicStroke == null) || (_basicStroke.getLineWidth() != lw)) _basicStroke = new BasicStroke(lw); stroked = true; ((Graphics2D)dst).setStroke(_basicStroke); } dst.drawLine((int)(info.x1), (int)(info.y1), (int)(info.x2), (int)(info.y2)); if (stroked) ((Graphics2D)dst).setStroke(_resetStroke); } public void draw(Graphics dst, IlvTransformer t) { IlvPoint pts[] = getPoints(); if (pts.length < 2) return; IlvRailroadAttributes ra = getRailroadAttributes(); float railSpacing = getRailSpacing(t); float tieWidth = getTieWidth(t); boolean doRails = !ra.isDrawingOneLine(); if (railSpacing < 1f) doRails = false; boolean doTies = ra.isDrawingTies(); if (tieWidth < 1f) doTies = false; boolean doCenterLine = ra.isDoingCenterLine(); if (!doRails) { dst.setColor(ra.getRailColor()); IlvGraphicUtil.DrawPolyline(dst, pts, pts.length, 0, IlvStroke.JOIN_MITER, IlvStroke.CAP_BUTT, null, t); if (!doTies) return; } _current.create(pts, 0, t, railSpacing); if (pts.length == 2) { if (doRails) { drawBackground(dst, _current); if (doCenterLine) drawCenterLine(dst, _current); drawRails(dst, _current); } if (doTies) drawTies(dst, t, 0f, _current, null, null); return; } float offset = 0f; for(int i = 1; i < pts.length - 1; i++) { _next.create(pts, i, t, railSpacing); _current.intersect(_next); if (doRails) { drawBackground(dst, _current); if (doCenterLine) drawCenterLine(dst, _current); drawRails(dst, _current); } if (doTies) offset = drawTies(dst, t, offset, _current, i == 1 ? null : _prev, _next); _prev.affect(_current); _current.affect(_next); } if (doRails) { drawBackground(dst, _current); if (doCenterLine) drawCenterLine(dst, _current); drawRails(dst, _current); } if (doTies) drawTies(dst, t, offset, _current, _prev, null); } }