Mercurial > projects > dwt-addons
view dwtx/draw2d/ManhattanConnectionRouter.d @ 103:2d6540440fe6
Replace static ctors with lazy init.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 03 Aug 2008 17:01:51 +0200 |
parents | 95307ad235d9 |
children |
line wrap: on
line source
/******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Port to the D programming language: * Frank Benoit <benoit@tionex.de> *******************************************************************************/ module dwtx.draw2d.ManhattanConnectionRouter; import dwt.dwthelper.utils; import dwtx.dwtxhelper.Collection; import dwtx.draw2d.geometry.Point; import dwtx.draw2d.geometry.PointList; import dwtx.draw2d.geometry.Ray; import dwtx.draw2d.geometry.Rectangle; import dwtx.draw2d.AbstractRouter; import dwtx.draw2d.Connection; import dwtx.draw2d.ConnectionAnchor; /** * Provides a {@link Connection} with an orthogonal route between the Connection's source * and target anchors. */ public final class ManhattanConnectionRouter : AbstractRouter { private Map rowsUsed; private Map colsUsed; //private Hashtable offsets = new Hashtable(7); private Map reservedInfo; private class ReservedInfo { public List reservedRows; public List reservedCols; this(){ reservedRows = new ArrayList(2); reservedCols = new ArrayList(2); } } private static Ray UP_, DOWN_, LEFT_, RIGHT_; private static Ray UP(){ if( !initStaticCtor_done ) initStaticCtor(); assert(UP_); return UP_; } private static Ray DOWN(){ if( !initStaticCtor_done ) initStaticCtor(); assert(DOWN_); return DOWN_; } private static Ray LEFT(){ if( !initStaticCtor_done ) initStaticCtor(); assert(LEFT_); return LEFT_; } private static Ray RIGHT(){ if( !initStaticCtor_done ) initStaticCtor(); assert(RIGHT_); return RIGHT_; } private static bool initStaticCtor_done = false; private static void initStaticCtor(){ synchronized( ManhattanConnectionRouter.classinfo ){ if( !initStaticCtor_done ){ UP_ = new Ray(0, -1); DOWN_ = new Ray(0, 1); LEFT_ = new Ray(-1, 0); RIGHT_ = new Ray(1, 0); initStaticCtor_done = true; } } } public this(){ rowsUsed = new HashMap(); colsUsed = new HashMap(); reservedInfo = new HashMap(); } /** * @see ConnectionRouter#invalidate(Connection) */ public void invalidate(Connection connection) { removeReservedLines(connection); } private int getColumnNear(Connection connection, int r, int n, int x) { int min = Math.min(n, x), max = Math.max(n, x); if (min > r) { max = min; min = r - (min - r); } if (max < r) { min = max; max = r + (r - max); } int proximity = 0; int direction = -1; if (r % 2 is 1) r--; Integer i; while (proximity < r) { i = new Integer(r + proximity * direction); if (!colsUsed.containsKey(i)) { colsUsed.put(i, i); reserveColumn(connection, i); return i.intValue(); } int j = i.intValue(); if (j <= min) return j + 2; if (j >= max) return j - 2; if (direction is 1) direction = -1; else { direction = 1; proximity += 2; } } return r; } /** * Returns the direction the point <i>p</i> is in relation to the given rectangle. * Possible values are LEFT (-1,0), RIGHT (1,0), UP (0,-1) and DOWN (0,1). * * @param r the rectangle * @param p the point * @return the direction from <i>r</i> to <i>p</i> */ protected Ray getDirection(Rectangle r, Point p) { int i, distance = Math.abs(r.x - p.x); Ray direction; direction = LEFT; i = Math.abs(r.y - p.y); if (i <= distance) { distance = i; direction = UP; } i = Math.abs(r.bottom() - p.y); if (i <= distance) { distance = i; direction = DOWN; } i = Math.abs(r.right() - p.x); if (i < distance) { distance = i; direction = RIGHT; } return direction; } protected Ray getEndDirection(Connection conn) { ConnectionAnchor anchor = conn.getTargetAnchor(); Point p = getEndPoint(conn); Rectangle rect; if (anchor.getOwner() is null) rect = new Rectangle(p.x - 1, p.y - 1, 2, 2); else { rect = conn.getTargetAnchor().getOwner().getBounds().getCopy(); conn.getTargetAnchor().getOwner().translateToAbsolute(rect); } return getDirection(rect, p); } protected int getRowNear(Connection connection, int r, int n, int x) { int min = Math.min(n, x), max = Math.max(n, x); if (min > r) { max = min; min = r - (min - r); } if (max < r) { min = max; max = r + (r - max); } int proximity = 0; int direction = -1; if (r % 2 is 1) r--; Integer i; while (proximity < r) { i = new Integer(r + proximity * direction); if (!rowsUsed.containsKey(i)) { rowsUsed.put(i, i); reserveRow(connection, i); return i.intValue(); } int j = i.intValue(); if (j <= min) return j + 2; if (j >= max) return j - 2; if (direction is 1) direction = -1; else { direction = 1; proximity += 2; } } return r; } protected Ray getStartDirection(Connection conn) { ConnectionAnchor anchor = conn.getSourceAnchor(); Point p = getStartPoint(conn); Rectangle rect; if (anchor.getOwner() is null) rect = new Rectangle(p.x - 1, p.y - 1, 2, 2); else { rect = conn.getSourceAnchor().getOwner().getBounds().getCopy(); conn.getSourceAnchor().getOwner().translateToAbsolute(rect); } return getDirection(rect, p); } protected void processPositions(Ray start, Ray end, List positions, bool horizontal, Connection conn) { removeReservedLines(conn); int pos[] = new int[positions.size() + 2]; if (horizontal) pos[0] = start.x; else pos[0] = start.y; int i; for (i = 0; i < positions.size(); i++) { pos[i + 1] = (cast(Integer)positions.get(i)).intValue(); } if (horizontal is (positions.size() % 2 is 1)) pos[++i] = end.x; else pos[++i] = end.y; PointList points = new PointList(); points.addPoint(new Point(start.x, start.y)); Point p; int current, prev, min, max; bool adjust; for (i = 2; i < pos.length - 1; i++) { horizontal = !horizontal; prev = pos[i - 1]; current = pos[i]; adjust = (i !is pos.length - 2); if (horizontal) { if (adjust) { min = pos[i - 2]; max = pos[i + 2]; pos[i] = current = getRowNear(conn, current, min, max); } p = new Point(prev, current); } else { if (adjust) { min = pos[i - 2]; max = pos[i + 2]; pos[i] = current = getColumnNear(conn, current, min, max); } p = new Point(current, prev); } points.addPoint(p); } points.addPoint(new Point(end.x, end.y)); conn.setPoints(points); } /** * @see ConnectionRouter#remove(Connection) */ public void remove(Connection connection) { removeReservedLines(connection); } protected void removeReservedLines(Connection connection) { ReservedInfo rInfo = cast(ReservedInfo) reservedInfo.get(cast(Object)connection); if (rInfo is null) return; for (int i = 0; i < rInfo.reservedRows.size(); i++) { rowsUsed.remove(rInfo.reservedRows.get(i)); } for (int i = 0; i < rInfo.reservedCols.size(); i++) { colsUsed.remove(rInfo.reservedCols.get(i)); } reservedInfo.remove(cast(Object)connection); } protected void reserveColumn(Connection connection, Integer column) { ReservedInfo info = cast(ReservedInfo) reservedInfo.get(cast(Object)connection); if (info is null) { info = new ReservedInfo(); reservedInfo.put(cast(Object)connection, info); } info.reservedCols.add(column); } protected void reserveRow(Connection connection, Integer row) { ReservedInfo info = cast(ReservedInfo) reservedInfo.get(cast(Object)connection); if (info is null) { info = new ReservedInfo(); reservedInfo.put(cast(Object)connection, info); } info.reservedRows.add(row); } /** * @see ConnectionRouter#route(Connection) */ public void route(Connection conn) { if ((conn.getSourceAnchor() is null) || (conn.getTargetAnchor() is null)) return; int i; Point startPoint = getStartPoint(conn); conn.translateToRelative(startPoint); Point endPoint = getEndPoint(conn); conn.translateToRelative(endPoint); Ray start = new Ray(startPoint); Ray end = new Ray(endPoint); Ray average = start.getAveraged(end); Ray direction = new Ray(start, end); Ray startNormal = getStartDirection(conn); Ray endNormal = getEndDirection(conn); List positions = new ArrayList(5); bool horizontal = startNormal.isHorizontal(); if (horizontal) positions.add(new Integer(start.y)); else positions.add(new Integer(start.x)); horizontal = !horizontal; if (startNormal.dotProduct(endNormal) is 0) { if ((startNormal.dotProduct(direction) >= 0) && (endNormal.dotProduct(direction) <= 0)) { // 0 } else { // 2 if (startNormal.dotProduct(direction) < 0) i = startNormal.similarity(start.getAdded(startNormal.getScaled(10))); else { if (horizontal) i = average.y; else i = average.x; } positions.add(new Integer(i)); horizontal = !horizontal; if (endNormal.dotProduct(direction) > 0) i = endNormal.similarity(end.getAdded(endNormal.getScaled(10))); else { if (horizontal) i = average.y; else i = average.x; } positions.add(new Integer(i)); horizontal = !horizontal; } } else { if (startNormal.dotProduct(endNormal) > 0) { //1 if (startNormal.dotProduct(direction) >= 0) i = startNormal.similarity(start.getAdded(startNormal.getScaled(10))); else i = endNormal.similarity(end.getAdded(endNormal.getScaled(10))); positions.add(new Integer(i)); horizontal = !horizontal; } else { //3 or 1 if (startNormal.dotProduct(direction) < 0) { i = startNormal.similarity(start.getAdded(startNormal.getScaled(10))); positions.add(new Integer(i)); horizontal = !horizontal; } if (horizontal) i = average.y; else i = average.x; positions.add(new Integer(i)); horizontal = !horizontal; if (startNormal.dotProduct(direction) < 0) { i = endNormal.similarity(end.getAdded(endNormal.getScaled(10))); positions.add(new Integer(i)); horizontal = !horizontal; } } } if (horizontal) positions.add(new Integer(end.y)); else positions.add(new Integer(end.x)); processPositions(start, end, positions, startNormal.isHorizontal(), conn); } }