/*
* Licensed Materials - Property of Rogue Wave Software, Inc.
* © Copyright Rogue Wave Software, Inc. 2014, 2017
* © 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 java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.io.IOException;
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;
class LineInfo {
double len;
double ddx;
double ddy;
double x1;
double y1;
double x2;
double y2;
double l1x1;
double l1y1;
double l1x2;
double l1y2;
double l2x1;
double l2y1;
double l2x2;
double l2y2;
IlvPoint p1 = new IlvPoint();
IlvPoint p2 = new IlvPoint();
int _ix;
int _iy;
boolean doJoin;
double jx1;
double jy1;
double jx2;
double jy2;
static final double SMALL = 1e-10d;
LineInfo() {
}
void create(IlvPoint p[], int i, IlvTransformer t, double 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;
double dx = x2 - x1;
double dy = y2 - y1;
len = 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(double x11, double y11, double x21, double 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)) {
double x = _ix;
double 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)) {
double x = _ix;
double y = _iy;
l2x2 = x;
l2y2 = y;
info.l2x1 = x;
info.l2y1 = y;
} else {
join(l2x2, l2y2, info.l2x1, info.l2y1);
}
}
boolean intersect(double x11, double y11, double x21, double y21, double x3, double y3, double x4, double y4) {
double d = (y4 - y3) * (x21 - x11) - (x4 - x3) * (y21 - y11);
if (Math.abs(d) == 0.)
return false;
double na = ((x4 - x3) * (y11 - y3) - (y4 - y3) * (x11 - x3)) / d;
if (na < 0d || na > 1d)
return false;
double nb = ((x21 - x11) * (y11 - y3) - (y21 - y11) * (x11 - x3)) / d;
if (nb < 0d || nb > 1d)
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) {
}
}
Override
public void write(IlvOutputStream stream) throws IOException {
super.write(stream);
if (_railAttributes != null)
stream.write("railAttributes", _railAttributes);
}
Override
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 double getRailSpacing(IlvTransformer t) {
IlvRailroadAttributes ra = getRailroadAttributes();
double val = ra.getRailSpacing();
double max = ra.getMaximumRailSpacing();
double scale = ra.getScale();
double zl = getZoomFactorFromScale(scale);
if (max == 0)
return val;
double zoomlevel = (t == null ? 1d : t.zoomFactor());
double v = zoomlevel * val / zl;
if (v >= max)
v = max;
return v;
}
public double getTieWidth(IlvTransformer t) {
IlvRailroadAttributes ra = getRailroadAttributes();
double val = ra.getTieWidth();
double max = ra.getMaximumTieWidth();
double scale = ra.getScale();
double zl = getZoomFactorFromScale(scale);
if (max == 0)
return val;
double zoomlevel = (t == null ? 1d : t.zoomFactor());
double v = zoomlevel * val / zl;
if (v >= max)
v = max;
return v;
}
Override
public IlvRect boundingBox(IlvTransformer t) {
IlvRect box;
box = super.boundingBox(t);
getRailroadAttributes();
double rs = getRailSpacing(t);
double tw = getTieWidth(t);
double width = Math.max(tw, rs);
box.expand(width / 2d);
return box;
}
Override
public boolean pointsInBBox() {
return true;
}
Override
public boolean contains(IlvPoint p, IlvPoint tp, IlvTransformer t) {
double zoom = t == null ? 1d : t.zoomFactor();
IlvPoint pts[] = getPoints();
getRailroadAttributes();
double tw = getTieWidth(t);
double rs = getRailSpacing(t);
double width = 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];
}
double drawTies(Graphics dst, IlvTransformer t, double offset, LineInfo current, LineInfo prev, LineInfo next) {
double d = current.len;
if (offset > d)
return offset - d;
IlvRailroadAttributes ra = getRailroadAttributes();
double tieSpacing = ra.getTieSpacing() * 2d;
double tieWidth = getTieWidth(t);
double tt = ra.getTieThickness();
if (tt > 0f)
initTmpPoints();
dst.setColor(ra.getTieColor());
double x1 = current.x1;
double y1 = current.y1;
double dx = current.x2 - x1;
double dy = current.y2 - y1;
double ddx = tieWidth * dy / d;
double ddy = tieWidth * dx / d;
double u;
for (u = offset; u < d; u += tieSpacing) {
double ud = u / d;
double px = x1 + ud * dx;
double py = y1 + ud * dy;
if (!dst.hitClip((int) (px - tieWidth) - 1, (int) (py - tieWidth) - 1, (int) (2f * tieWidth) + 2,
(int) (2f * tieWidth) + 2))
continue;
double fx = px - ddx;
double fy = py + ddy;
double tx = px + ddx;
double ty = py - ddy;
float limit = ra.getSlantingLimit();
if (limit > 0f) {
if ((next != null) && ((d - u) <= limit)) {
double angle = (angle(current, next) - Math.PI) / 2d;
angle *= 1f - (d - u) / limit;
double sa = - Math.sin(angle);
double ca = 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)) {
double angle = (angle(prev, current) - Math.PI) / 2d;
angle *= 1f - u / limit;
double sa = Math.sin(angle);
double ca = 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);
}
double angle(LineInfo l1, LineInfo l2) {
double dx1 = l1.x1 - l1.x2;
double dy1 = l1.y1 - l1.y2;
double dx2 = l2.x2 - l2.x1;
double dy2 = l2.y2 - l2.y1;
double dp = dx1 * dx2 + dy1 * dy2;
double cos = dp / (l1.len * l2.len);
if (cos < -1f)
cos = -1;
if (cos > 1f)
cos = 1f;
double angle = Math.acos(cos);
double cp = dx1 * dy2 - dx2 * dy1;
if (cp > 0)
angle = 2d * 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);
}
Override
public void draw(Graphics dst, IlvTransformer t) {
IlvPoint pts[] = getPoints();
if (pts.length < 2)
return;
IlvRailroadAttributes ra = getRailroadAttributes();
double railSpacing = getRailSpacing(t);
double 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;
}
double offset = 0d;
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);
}
}