~ubuntu-branches/ubuntu/maverick/electric/maverick

« back to all changes in this revision

Viewing changes to com/sun/electric/tool/routing/InteractiveRouter.java

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2010-01-09 16:26:04 UTC
  • mfrom: (1.1.4 upstream) (3.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100109162604-1ypvmy8ijmlc6oq7
Tags: 8.10-1
* New upstream version.
* debian/control
  - Add libjava3d-java and quilt build dependencies.
  - Update standards version to 3.8.3.
  - Add libjava3d-java as recommends to binary package.
* debian/rules
  - Use quilt patch system instead of simple patchsys.
  - Add java3d related jar files to DEB_JARS.
* debian/patches/*
  - Update as per current upstream source. Convert to quilt.
* debian/ant.properties
  - Do not disable 3D plugin anymore.
  - Use new property to disable compilation of OS X related classes.
* debian/wrappers/electric
  - Add java3d related jar files to runtime classpath.
* debian/README.source
  - Change text to the appropriate one for quilt.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
package com.sun.electric.tool.routing;
26
26
 
27
27
import com.sun.electric.database.EditingPreferences;
28
 
import com.sun.electric.database.geometry.*;
 
28
import com.sun.electric.database.geometry.DBMath;
 
29
import com.sun.electric.database.geometry.Dimension2D;
 
30
import com.sun.electric.database.geometry.EPoint;
 
31
import com.sun.electric.database.geometry.GenMath;
 
32
import com.sun.electric.database.geometry.Poly;
 
33
import com.sun.electric.database.geometry.PolyMerge;
29
34
import com.sun.electric.database.hierarchy.Cell;
30
35
import com.sun.electric.database.hierarchy.Export;
 
36
import com.sun.electric.database.prototype.NodeProto;
31
37
import com.sun.electric.database.prototype.PortProto;
32
 
import com.sun.electric.database.prototype.NodeProto;
33
 
import com.sun.electric.database.topology.*;
 
38
import com.sun.electric.database.topology.ArcInst;
 
39
import com.sun.electric.database.topology.Connection;
 
40
import com.sun.electric.database.topology.NodeInst;
 
41
import com.sun.electric.database.topology.PortInst;
34
42
import com.sun.electric.database.variable.ElectricObject;
35
 
import com.sun.electric.technology.*;
 
43
import com.sun.electric.technology.ArcProto;
 
44
import com.sun.electric.technology.Layer;
 
45
import com.sun.electric.technology.PrimitiveNode;
 
46
import com.sun.electric.technology.SizeOffset;
36
47
import com.sun.electric.technology.technologies.Artwork;
 
48
import com.sun.electric.tool.Job;
37
49
import com.sun.electric.tool.JobException;
38
 
import com.sun.electric.tool.Job;
39
50
import com.sun.electric.tool.user.CircuitChangeJobs;
40
 
import com.sun.electric.tool.user.Highlight2;
 
51
import com.sun.electric.tool.user.Highlight;
41
52
import com.sun.electric.tool.user.Highlighter;
42
53
import com.sun.electric.tool.user.ui.EditWindow;
43
 
import com.sun.electric.tool.user.ui.ClickZoomWireListener;
44
54
 
45
55
import java.awt.geom.Line2D;
46
56
import java.awt.geom.Point2D;
47
57
import java.awt.geom.Rectangle2D;
48
58
import java.util.ArrayList;
 
59
import java.util.Iterator;
49
60
import java.util.List;
50
 
import java.util.Iterator;
51
61
 
52
62
/**
53
63
 * An Interactive Router has several methods that build on Router
69
79
 */
70
80
public abstract class InteractiveRouter extends Router {
71
81
 
72
 
    /** for highlighting the start of the route */  private List<Highlight2> startRouteHighlights = new ArrayList<Highlight2>();
 
82
    /** for highlighting the start of the route */  private List<Highlight> startRouteHighlights = new ArrayList<Highlight>();
73
83
    /** if start has been called */                 private boolean started;
74
84
    /** EditWindow we are routing in */             private EditWindow wnd;
75
85
 
101
111
        this.wnd = wnd;
102
112
        // copy current highlights
103
113
        startRouteHighlights.clear();
104
 
        for (Highlight2 h : wnd.getHighlighter().getHighlights()) {
 
114
        for (Highlight h : wnd.getHighlighter().getHighlights()) {
105
115
            startRouteHighlights.add(h);
106
116
        }
107
117
        wnd.clearHighlighting();
134
144
    public void makeRoute(EditWindow wnd, Cell cell, ElectricObject startObj, ElectricObject endObj, Point2D clicked) {
135
145
        if (!started) startInteractiveRoute(wnd);
136
146
        // plan the route
137
 
        Route route = planRoute(cell, startObj, endObj, clicked, null, true, true);
 
147
        Route route = planRoute(cell, startObj, endObj, clicked, null, true, true, null, null);
138
148
        // restore highlights at start of planning, so that
139
149
        // they will correctly show up if this job is undone.
140
150
        wnd.clearHighlighting();
173
183
        ArcProto startArc = vroute.getStartArc();
174
184
        ArcProto endArc = vroute.getEndArc();
175
185
 
176
 
        ContactSize sizer = new ContactSize(startPort, null, startLoc, startLoc, startLoc, startArc, endArc, false);
 
186
        EditingPreferences ep = EditingPreferences.getThreadEditingPreferences();
 
187
        ContactSize sizer = new ContactSize(startPort, null, startLoc, startLoc, startLoc, startArc, endArc, false, ep.fatWires);
177
188
        Rectangle2D contactArea = sizer.getContactSize();
178
189
        Dimension2D contactSize = new Dimension2D.Double(contactArea.getWidth(), contactArea.getHeight());
179
190
        int startAngle = sizer.getStartAngle();
191
202
            if (route.getStart() == startRE) route.setStart(vertRoute.getStart());
192
203
        } else {
193
204
            addConnectingArc(route, cell, startRE, vertRoute.getStart(), startLoc, startLoc, startArc,
194
 
                    startArcWidth, startAngle, true, true, null);
 
205
                    startArcWidth, startAngle, true, true, null, null);
195
206
        }
196
207
 
197
208
        // restore highlights at start of planning, so that
217
228
                // if this is a pin, replace it with the first contact in vertical route
218
229
                PortInst pi = startRE.getPortInst();
219
230
                NodeInst ni = pi.getNodeInst();
220
 
                if (ni.getProto().getFunction() == PrimitiveNode.Function.PIN) {
 
231
                if (ni.getProto().getFunction().isPin()) {
221
232
                        CircuitChangeJobs.Reconnect re = CircuitChangeJobs.Reconnect.erasePassThru(ni, false, true);
222
233
                    if (re != null) re.reconnectArcs();
223
234
                    if (!ni.hasExports()) ni.kill();
240
251
    public void highlightRoute(EditWindow wnd, Cell cell, ElectricObject startObj, ElectricObject endObj, Point2D clicked) {
241
252
        if (!started) startInteractiveRoute(wnd);
242
253
        // highlight route
243
 
        Route route = planRoute(cell, startObj, endObj, clicked, null, true, true);
 
254
        Route route = planRoute(cell, startObj, endObj, clicked, null, true, true, null, null);
244
255
        highlightRoute(wnd, route, cell);
245
256
    }
246
257
 
270
281
     * if the user is drawing to empty space.
271
282
     * @param clicked the point where the user clicked
272
283
     * @param stayInside the area in which to route (null if not applicable).
273
 
     * @param extendArcHead true to use default arc extension; false to force no arc extension.
274
 
     * @param extendArcTail true to use default arc extension; false to force no arc extension.
275
 
     * @return a List of RouteElements denoting route
276
 
     */
277
 
    public Route planRoute(Cell cell, ElectricObject startObj, ElectricObject endObj, Point2D clicked, PolyMerge stayInside,
278
 
                           boolean extendArcHead, boolean extendArcTail) {
279
 
        return planRoute(cell, startObj, endObj, clicked, stayInside, extendArcHead, extendArcTail, null);
280
 
    }
281
 
 
282
 
    /**
283
 
     * Plan a route from startObj to endObj, taking into account
284
 
     * where the user clicked in the cell.
285
 
     * @param cell the cell in which to create the arc
286
 
     * @param startObj a PortInst or ArcInst from which to start the route
287
 
     * @param endObj a PortInst or ArcInst to end the route on. May be null
288
 
     * if the user is drawing to empty space.
289
 
     * @param clicked the point where the user clicked
290
 
     * @param stayInside the area in which to route (null if not applicable).
291
 
     * @param extendArcHead true to use default arc extension; false to force no arc extension.
292
 
     * @param extendArcTail true to use default arc extension; false to force no arc extension.
293
 
     * @return a List of RouteElements denoting route
294
 
     */
295
 
    public Route planRoute(Cell cell, ElectricObject startObj, ElectricObject endObj, Point2D clicked, PolyMerge stayInside,
296
 
                           boolean extendArcHead, boolean extendArcTail, Rectangle2D contactArea) {
297
 
 
 
284
     * @param extendArcHead true to use default arc extension; false to force no arc extension. (head connects to startObj).
 
285
     * @param extendArcTail true to use default arc extension; false to force no arc extension. (tail connects to endObj).
 
286
     * @param contactArea
 
287
     * @param alignment edge alignment factors (null for no alignment).
 
288
     * @return a List of RouteElements denoting route
 
289
     */
 
290
    public Route planRoute(Cell cell, ElectricObject startObj, ElectricObject endObj, Point2D clicked, PolyMerge stayInside,
 
291
        boolean extendArcHead, boolean extendArcTail, Rectangle2D contactArea, Dimension2D alignment)
 
292
    {
298
293
        EditingPreferences ep = cell.getEditingPreferences();
299
294
        Route route = new Route();               // hold the route
300
295
        if (cell == null) return route;
318
313
            ArcProto useArc = getArcToUse(startPort, null);
319
314
            if (useArc == null) return route;
320
315
            PrimitiveNode pn = useArc.findOverridablePinProto(ep);
 
316
            if (pn == null) // something wrong with technology. No pin found
 
317
            {
 
318
                System.out.println("No primitive node found for arc '" + useArc.getName() + "'");
 
319
                return route; // error
 
320
            }
321
321
            endPort = pn.getPort(0);
322
322
        } else {
323
323
            endPort = getRoutePort(endObj);
336
336
        double startArcWidth = 0;
337
337
        double endArcWidth = 0;
338
338
 
339
 
        if (!ClickZoomWireListener.theOne.getUseFatWiringMode()) {
 
339
        if (!ep.fatWires) {
340
340
            // if not using fat wiring mode, determine arc sizes now, and
341
341
            // start and end points based off of arc sizes and startObj and endObj port sizes
342
 
            startArcWidth = getArcWidthToUse(startObj, startArc, 0, true);
343
 
            endArcWidth = (endObj == null) ? startArcWidth : getArcWidthToUse(endObj, endArc, 0, true);
 
342
            startArcWidth = getArcWidthToUse(startObj, startArc, 0, true, ep.fatWires);
 
343
            endArcWidth = (endObj == null) ? startArcWidth : getArcWidthToUse(endObj, endArc, 0, true, ep.fatWires);
344
344
            if (startArc == endArc) {
345
345
                if (startArcWidth > endArcWidth) endArcWidth = startArcWidth;
346
346
                if (endArcWidth > startArcWidth) startArcWidth = endArcWidth;
363
363
        // arc(s) should connect
364
364
        Point2D startPoint = new Point2D.Double(0, 0);
365
365
        Point2D endPoint = new Point2D.Double(0,0);
366
 
        getConnectingPoints(startObj, endObj, clicked, startPoint, endPoint, startPoly, endPoly, startArc, endArc);
 
366
        getConnectingPoints(startObj, endObj, clicked, startPoint, endPoint, startPoly, endPoly,
 
367
                startArc, endArc, alignment, ep.fatWires);
367
368
 
368
369
        PortInst existingStartPort = null;
369
370
        PortInst existingEndPort = null;
379
380
        }
380
381
        if (startObj instanceof ArcInst) {
381
382
            // arc: figure out where on arc to start
382
 
            startRE = findArcConnectingPoint(route, (ArcInst)startObj, startPoint, stayInside);
 
383
            ArcInst ai = (ArcInst)startObj;
 
384
            startRE = findArcConnectingPoint(route, ai, startPoint, stayInside, alignment);
 
385
            if (startRE.getPortInst() == ai.getHeadPortInst() && extendArcHead) extendArcHead = ai.isHeadExtended();
 
386
            if (startRE.getPortInst() == ai.getTailPortInst() && extendArcHead) extendArcHead = ai.isTailExtended();
383
387
            if (startRE.isBisectArcPin()) contactsOnEndObject = false;
384
388
        }
385
389
        if (startRE == null) {
400
404
            if (endObj instanceof ArcInst) {
401
405
                // arc: figure out where on arc to end
402
406
                // use startRE location when possible if connecting to arc
403
 
                endRE = findArcConnectingPoint(route, (ArcInst)endObj, endPoint, stayInside);
 
407
                ArcInst ai = (ArcInst)endObj;
 
408
                endRE = findArcConnectingPoint(route, ai, endPoint, stayInside, alignment);
 
409
                if (endRE.getPortInst() == ai.getHeadPortInst() && extendArcTail) extendArcTail = ai.isHeadExtended();
 
410
                if (endRE.getPortInst() == ai.getTailPortInst() && extendArcTail) extendArcTail = ai.isTailExtended();
404
411
                if (endRE.isBisectArcPin()) contactsOnEndObject = true;
405
412
            }
406
413
            if (endRE == null) {
444
451
        int endAngle = GenMath.figureAngle(endPoint, cornerLoc);
445
452
 
446
453
        // figure out sizes to use
447
 
        ContactSize sizer = new ContactSize(startObj, endObj, startPoint, endPoint, cornerLoc, startArc, endArc, false);
 
454
        ContactSize sizer = new ContactSize(startObj, endObj, startPoint, endPoint, cornerLoc, startArc, endArc, false, ep.fatWires);
448
455
        contactArea = sizer.getContactSize();
449
456
        startAngle = sizer.getStartAngle();
450
457
        endAngle = sizer.getEndAngle();
482
489
            } else {
483
490
                // create arc between startRE and start of vertical route
484
491
                addConnectingArc(route, cell, startRE, vertRoute.getStart(), startPoint, cornerLoc, startArc,
485
 
                        startArcWidth, startAngle, extendArcHead, extendArcTail, stayInside);
 
492
                        startArcWidth, startAngle, extendArcHead, extendArcTail, stayInside, alignment);
486
493
            }
487
494
            // replace endpoints if possible (remove redundant pins), endRE
488
495
            if (route.replacePin(endRE, vertRoute.getEnd(), stayInside)) {
491
498
            } else {
492
499
                // create arc between endRE and end of vertical route
493
500
                addConnectingArc(route, cell, endRE, vertRoute.getEnd(), endPoint, cornerLoc, endArc,
494
 
                        endArcWidth, endAngle, extendArcHead, extendArcTail, stayInside);
 
501
                        endArcWidth, endAngle, extendArcHead, extendArcTail, stayInside, alignment);
495
502
            }
496
503
        }
497
504
        else {
509
516
            if (startArc.getAngleIncrement(ep) == 0 || (DBMath.figureAngle(startPoint, endPoint) % (10*startArc.getAngleIncrement(ep))) == 0) {
510
517
                // single arc
511
518
                addConnectingArc(route, cell, startRE, endRE, startPoint, endPoint, startArc,
512
 
                        startArcWidth, startAngle, extendArcHead, extendArcTail, stayInside);
 
519
                        startArcWidth, startAngle, extendArcHead, extendArcTail, stayInside, alignment);
513
520
            } else {
514
521
                PrimitiveNode pn = startArc.findOverridablePinProto(ep);
515
522
                SizeOffset so = pn.getProtoSizeOffset();
519
526
                        defwidth, defheight);
520
527
                route.add(pinRE);
521
528
                addConnectingArc(route, cell, startRE, pinRE, startPoint, cornerLoc, startArc,
522
 
                        startArcWidth, startAngle, extendArcHead, extendArcTail, stayInside);
 
529
                        startArcWidth, startAngle, extendArcHead, extendArcTail, stayInside, alignment);
523
530
                addConnectingArc(route, cell, endRE, pinRE, endPoint, cornerLoc, endArc,
524
 
                        endArcWidth, endAngle, extendArcHead, extendArcTail, stayInside);
 
531
                        endArcWidth, endAngle, extendArcHead, extendArcTail, stayInside, alignment);
525
532
            }
526
533
 
527
534
        }
609
616
     * @param endPoly valid port site on endObj
610
617
     * @param startArc the arc type to connect to startObj
611
618
     * @param endArc the arc type to connect to endObj
 
619
     * @param fatWiringMode true to make arcs as wide as their connecting nodes.
612
620
     */
613
621
    protected static void getConnectingPoints(ElectricObject startObj, ElectricObject endObj, Point2D clicked,
614
622
                                              Point2D startPoint, Point2D endPoint, Poly startPoly, Poly endPoly,
615
 
                                              ArcProto startArc, ArcProto endArc) {
 
623
                                              ArcProto startArc, ArcProto endArc, Dimension2D alignment, boolean fatWiringMode) {
616
624
 
 
625
        if (alignment == null) alignment = new Dimension2D.Double(0, 0);
617
626
/*        Point2D[] points = startPoly.getPoints();
618
627
        System.out.print("StartPoly: ");
619
628
        for (int i=0; i<points.length; i++) {
640
649
            return;
641
650
        }
642
651
 
643
 
        // just go by bounds for now
644
 
        Rectangle2D startBounds = startPoly.getBounds2D();
645
 
        // default is center point
646
 
        startPoint.setLocation(startBounds.getCenterX(), startBounds.getCenterY());
 
652
        // default is center point, aligned to grid
 
653
        Rectangle2D startBounds = new Rectangle2D.Double(startPoly.getBounds2D().getX(), startPoly.getBounds2D().getY(),
 
654
                                                         startPoly.getBounds2D().getWidth(), startPoly.getBounds2D().getHeight());
 
655
        getAlignedCenter(startBounds, alignment, startPoint);
647
656
 
648
657
        // if startObj is arc inst
649
658
        if (startObj instanceof ArcInst) {
650
659
            double x, y;
651
660
            // if nothing to connect to, clicked will determine connecting point on startPoly
652
661
            // endPoint will be location of new pin
653
 
            x = getClosestValue(startBounds.getMinX(), startBounds.getMaxX(), clicked.getX());
654
 
            y = getClosestValue(startBounds.getMinY(), startBounds.getMaxY(), clicked.getY());
 
662
            x = getClosestValue(startBounds.getMinX(), startBounds.getMaxX(), clicked.getX(), alignment.getWidth());
 
663
            y = getClosestValue(startBounds.getMinY(), startBounds.getMaxY(), clicked.getY(), alignment.getHeight());
655
664
            startPoint.setLocation(x, y);
656
665
        }
657
666
 
667
676
            return;
668
677
        }
669
678
 
670
 
        Rectangle2D endBounds = endPoly.getBounds2D();
671
 
        endPoint.setLocation(endBounds.getCenterX(), endBounds.getCenterY());
 
679
        Rectangle2D endBounds = new Rectangle2D.Double(endPoly.getBounds2D().getX(), endPoly.getBounds2D().getY(),
 
680
                                                       endPoly.getBounds2D().getWidth(), endPoly.getBounds2D().getHeight());
 
681
        getAlignedCenter(endBounds, alignment, endPoint);
672
682
 
673
683
        if (endObj instanceof ArcInst) {
674
684
            double x, y;
675
685
            // if nothing to connect to, clicked will determine connecting point on startPoly
676
686
            // endPoint will be location of new pin
677
 
            x = getClosestValue(endBounds.getMinX(), endBounds.getMaxX(), clicked.getX());
678
 
            y = getClosestValue(endBounds.getMinY(), endBounds.getMaxY(), clicked.getY());
 
687
            x = getClosestValue(endBounds.getMinX(), endBounds.getMaxX(), clicked.getX(), alignment.getWidth());
 
688
            y = getClosestValue(endBounds.getMinY(), endBounds.getMaxY(), clicked.getY(), alignment.getHeight());
679
689
            endPoint.setLocation(x, y);
680
690
        }
681
691
 
686
696
        double upperBoundY = Math.min(startBounds.getMaxY(), endBounds.getMaxY());
687
697
        boolean overlapY = lowerBoundY <= upperBoundY;
688
698
 
689
 
        if (ClickZoomWireListener.theOne.getUseFatWiringMode()) {
 
699
        if (fatWiringMode) {
690
700
            Rectangle2D startObjBounds = getBounds(startObj);
691
701
            Rectangle2D endObjBounds = getBounds(endObj);
692
702
            boolean objsOverlap = false;
694
704
                if (startArc == endArc && startObjBounds.intersects(endObjBounds))
695
705
                    objsOverlap = true;
696
706
            }
 
707
            // grid align if needed
 
708
            Point2D startCenter = new Point2D.Double(startBounds.getCenterX(), startBounds.getCenterY());
 
709
            Point2D endCenter = new Point2D.Double(endBounds.getCenterX(), endBounds.getCenterY());
 
710
            gridAlignWithinBounds(startCenter, startBounds, alignment);
 
711
            gridAlignWithinBounds(endCenter, endBounds, alignment);
 
712
 
697
713
            // normally we route center to center (for PortInsts) in fat wiring mode,
698
714
            // but if the objects overlap (both ports and objects themselves, then we will route directly
699
715
            if (!objsOverlap || !overlapX) {
700
716
                // center X on both objects (if they are port insts)
701
717
                if (startObj instanceof PortInst) {
702
 
                    startBounds.setRect(startBounds.getCenterX(), startBounds.getY(), 0, startBounds.getHeight());
 
718
                    startBounds.setRect(startCenter.getX(), startBounds.getY(), 0, startBounds.getHeight());
703
719
                }
704
720
                if (endObj instanceof PortInst) {
705
 
                    endBounds.setRect(endBounds.getCenterX(), endBounds.getY(), 0, endBounds.getHeight());
 
721
                    endBounds.setRect(endCenter.getX(), endBounds.getY(), 0, endBounds.getHeight());
706
722
                }
707
723
            }
708
724
            if (!objsOverlap || !overlapY) {
709
725
                // center Y on both objects (if they are port insts)
710
726
                if (startObj instanceof PortInst) {
711
 
                    startBounds.setRect(startBounds.getX(), startBounds.getCenterY(), startBounds.getWidth(), 0);
 
727
                    startBounds.setRect(startBounds.getX(), startCenter.getY(), startBounds.getWidth(), 0);
712
728
                }
713
729
                if (endObj instanceof PortInst) {
714
 
                    endBounds.setRect(endBounds.getX(), endBounds.getCenterY(), endBounds.getWidth(), 0);
 
730
                    endBounds.setRect(endBounds.getX(), endCenter.getY(), endBounds.getWidth(), 0);
715
731
                }
716
732
            }
717
733
            // recalculate overlaps in case bounds have changed
727
743
            // lines, allow special case where lines can be non-manhatten
728
744
            Point2D [] points1 = startPoly.getPoints();
729
745
            Point2D [] points2 = endPoly.getPoints();
730
 
            Point2D intersection = getIntersection(new Line2D.Double(points1[0], points1[1]),
731
 
                                                   new Line2D.Double(points2[0], points2[1]));
 
746
            Point2D intersection = getIntersection(points1, points2);
732
747
            if (intersection != null)
733
748
            {
734
749
                if (Job.getDebug())
747
762
 
748
763
        // check if bounds share X and Y space (manhatten rectangular polygons only)
749
764
        if (lowerBoundX <= upperBoundX) {
750
 
            double x = getClosestValue(lowerBoundX, upperBoundX, clicked.getX());
 
765
            double x = getClosestValue(lowerBoundX, upperBoundX, clicked.getX(), alignment.getWidth());
751
766
            startPoint.setLocation(x, startPoint.getY());
752
767
            endPoint.setLocation(x, endPoint.getY());
753
768
        } else {
763
778
        }
764
779
        // if bounds share y-space, use closest y within that space to clicked point
765
780
        if (lowerBoundY <= upperBoundY) {
766
 
            double y = getClosestValue(lowerBoundY, upperBoundY, clicked.getY());
 
781
            double y = getClosestValue(lowerBoundY, upperBoundY, clicked.getY(), alignment.getHeight());
767
782
            startPoint.setLocation(startPoint.getX(), y);
768
783
            endPoint.setLocation(endPoint.getX(), y);
769
784
        } else {
777
792
                endPoint.setLocation(endPoint.getX(), endBounds.getMinY());
778
793
            }
779
794
        }
780
 
    }
 
795
        if (alignment.getWidth() > 0 && alignment.getHeight() > 0) {
 
796
            if (startPoint.getX() % alignment.getWidth() != 0 || endPoint.getX() % alignment.getWidth() != 0 ||
 
797
                startPoint.getY() % alignment.getHeight() != 0 || endPoint.getY() % alignment.getHeight() != 0) {
 
798
                System.out.println("start and end points not aligned");
 
799
            }
 
800
        }
 
801
    }
 
802
 
 
803
    /**
 
804
     * Grid align the point within the confine of bounds. This assumes the point is already within the bounds.
 
805
     * @param pt the point to align
 
806
     * @param bounds the bounds within to align
 
807
     * @param alignment the alignment
 
808
     */
 
809
    private static void gridAlignWithinBounds(Point2D pt, Rectangle2D bounds, Dimension2D alignment)
 
810
    {
 
811
        if (alignment == null) return;
 
812
        double x = pt.getX();
 
813
        double y = pt.getY();
 
814
        if (alignment.getWidth() > 0) {
 
815
            double xfloor = Math.floor(x/alignment.getWidth()) * alignment.getWidth();
 
816
            double xceil = Math.ceil(x/alignment.getWidth()) * alignment.getWidth();
 
817
            if (xfloor >= bounds.getMinX() && xfloor <= bounds.getMaxX()) {
 
818
                x = xfloor;
 
819
            } else if (xceil >= bounds.getMinX() && xceil <= bounds.getMaxX()) {
 
820
                x = xceil;
 
821
            }
 
822
        }
 
823
        if (alignment.getHeight() > 0) {
 
824
            double yfloor = Math.floor(y/alignment.getHeight()) * alignment.getHeight();
 
825
            double yceil = Math.ceil(y/alignment.getHeight()) * alignment.getHeight();
 
826
            if (yfloor >= bounds.getMinY() && yfloor <= bounds.getMaxY()) {
 
827
                y = yfloor;
 
828
            } else if (yceil >= bounds.getMinY() && yceil <= bounds.getMaxY()) {
 
829
                y = yceil;
 
830
            }
 
831
        }
 
832
        pt.setLocation(x, y);
 
833
    }
 
834
 
 
835
    /**
 
836
     * Method to find the center of a Rectangle, grid aligned, and to grid-align the rectangle.
 
837
     * @param bounds the rectangle to evaluate and align.
 
838
     * @param alignment the alignment in X and Y.
 
839
     * @param ctr the center point is stored here.
 
840
     */
 
841
        private static void getAlignedCenter(Rectangle2D bounds, Dimension2D alignment, Point2D ctr)
 
842
        {
 
843
                double cX = bounds.getCenterX();
 
844
                double cY = bounds.getCenterY();
 
845
                if (alignment != null)
 
846
                {
 
847
                        if (alignment.getWidth() > 0)
 
848
                        {
 
849
                                double xx = cX / alignment.getWidth();
 
850
                                long xxL = Math.round(xx);
 
851
                                if (xx != xxL)
 
852
                                {
 
853
                                        double newX = xxL * alignment.getWidth();
 
854
                                        if (newX >= bounds.getMinX() && newX <= bounds.getMaxX()) cX = newX;
 
855
                                }
 
856
                                double lX = Math.ceil(bounds.getMinX() / alignment.getWidth()) * alignment.getWidth();
 
857
                                double hX = Math.floor(bounds.getMaxX() / alignment.getWidth()) * alignment.getWidth();
 
858
                                if (lX <= bounds.getMaxX() && hX >= bounds.getMinX())
 
859
                                        bounds.setRect(lX, bounds.getMinY(), hX-lX, bounds.getHeight());
 
860
                        }
 
861
                        if (alignment.getHeight() > 0)
 
862
                        {
 
863
                                double yy = cY / alignment.getHeight();
 
864
                                long yyL = Math.round(yy);
 
865
                                if (yy != yyL)
 
866
                                {
 
867
                                        double newY = yyL * alignment.getHeight();
 
868
                                        if (newY >= bounds.getMinY() && newY <= bounds.getMaxY()) cY = newY;
 
869
                                }
 
870
                                double lY = Math.ceil(bounds.getMinY() / alignment.getHeight()) * alignment.getHeight();
 
871
                                double hY = Math.floor(bounds.getMaxY() / alignment.getHeight()) * alignment.getHeight();
 
872
                                if (lY <= bounds.getMaxY() && hY >= bounds.getMinY())
 
873
                                        bounds.setRect(bounds.getMinX(), lY, bounds.getWidth(), hY-lY);
 
874
                        }
 
875
                }
 
876
                ctr.setLocation(cX, cY);
 
877
        }
781
878
 
782
879
    /**
783
880
     * Get the intersection point of the two line segments, or null if none
784
 
     * @param line1 line 1
785
 
     * @param line2 line 2
 
881
     * @param points1 An array of two points that define line 1
 
882
     * @param points2 An array of two points that define line 2
786
883
     * @return the intersection point, or null if none
787
884
     */
788
 
    public static Point2D getIntersection(Line2D line1, Line2D line2) {
 
885
    public static Point2D getIntersection(Point2D [] points1, Point2D [] points2) {
 
886
        // Checking if line1 is not a singular point
 
887
        if (DBMath.areEquals(points1[0], points1[1]) || DBMath.areEquals(points2[0], points2[1]))
 
888
        {
 
889
            if (Job.getDebug())
 
890
                System.out.println("Line is a singular point in InteractiveRouter.getIntersection");
 
891
            return null;
 
892
        }
 
893
        Line2D line1 = new Line2D.Double(points1[0], points1[1]);
 
894
        Line2D line2 = new Line2D.Double(points2[0], points2[1]);
 
895
 
789
896
        if (!line1.intersectsLine(line2))
790
897
            return null;
791
898
        double [] co1 = getLineCoeffs(line1);
792
899
        double [] co2 = getLineCoeffs(line2);
793
900
        // det = A1*B2 - A2*B1
 
901
 
794
902
        double det = co1[0]*co2[1] - co2[0]*co1[1];
795
 
        // if det == 0, lines are parallel, but already checked by intersection check above
 
903
        if (det == 0)
 
904
        {
 
905
                // lines are parallel.  Since they already passed the "intersection" test, they must meet at an end
 
906
                if (points1[0].getX() == points2[0].getX() && points1[0].getY() == points2[0].getY()) return points1[0];
 
907
                if (points1[0].getX() == points2[1].getX() && points1[0].getY() == points2[1].getY()) return points1[0];
 
908
                if (points1[1].getX() == points2[0].getX() && points1[1].getY() == points2[0].getY()) return points1[1];
 
909
                if (points1[1].getX() == points2[1].getX() && points1[1].getY() == points2[1].getY()) return points1[1];
 
910
                return null;
 
911
        }
 
912
 
796
913
        // x = (B2*C1 - B1*C2)/det
797
914
        double x = (co2[1]*co1[2] - co1[1]*co2[2])/det;
 
915
 
798
916
        // y = (A1*C2 - A2*C1)/det
799
917
        double y = (co1[0]*co2[2] - co2[0]*co1[2])/det;
800
918
        return new Point2D.Double(x, y);
899
1017
                PrimitiveNode pn = (PrimitiveNode)np;
900
1018
 
901
1019
                // if pin, use area of arcs connected to it
902
 
                if (pn.getFunction() == PrimitiveNode.Function.PIN) {
 
1020
                if (pn.getFunction().isPin()) {
903
1021
                    // determine size by arcs connected to it
904
1022
                    Rectangle2D horiz = null;
905
1023
                    Rectangle2D vert = null;
925
1043
                }
926
1044
 
927
1045
                // if contact, use size of contact
928
 
                if (pn.getFunction() == PrimitiveNode.Function.CONTACT) {
 
1046
                if (pn.getFunction().isContact()) {
929
1047
                    Poly p = ni.getBaseShape();
930
1048
                    return p.getBounds2D();
931
1049
                }
954
1072
     * @param arc the arc to draw from/to
955
1073
     * @param connectingPoint point on or near arc
956
1074
     * @param stayInside the area in which to route (null if not applicable).
 
1075
     * @param alignment if non-null, alignment to align to
957
1076
     * @return a RouteElement holding the new pin at the bisection
958
1077
     * point, or a RouteElement holding an existingPortInst if
959
1078
     * drawing from either end of the ArcInst.
960
1079
     */
961
 
    protected RouteElementPort findArcConnectingPoint(Route route, ArcInst arc, Point2D connectingPoint, PolyMerge stayInside) {
 
1080
    protected RouteElementPort findArcConnectingPoint(Route route, ArcInst arc, Point2D connectingPoint, PolyMerge stayInside, Dimension2D alignment) {
962
1081
 
963
1082
        EPoint head = arc.getHeadLocation();
964
1083
        EPoint tail = arc.getTailLocation();
969
1088
        if (tail.equals(connectingPoint)) return tailRE;
970
1089
 
971
1090
        // otherwise, we must be bisecting the arc
972
 
        return bisectArc(route, arc, connectingPoint, stayInside);
 
1091
        return bisectArc(route, arc, connectingPoint, stayInside, alignment);
973
1092
    }
974
1093
 
975
1094
    /**
980
1099
     * @param arc the arc to split
981
1100
     * @param bisectPoint point on arc from which to split it
982
1101
     * @param stayInside the area in which to route (null if not applicable).
 
1102
     * @param alignment alignment to align to, if non-null
983
1103
     * @return the RouteElement from which to continue the route
984
1104
     */
985
 
    protected RouteElementPort bisectArc(Route route, ArcInst arc, Point2D bisectPoint, PolyMerge stayInside) {
 
1105
    protected RouteElementPort bisectArc(Route route, ArcInst arc, Point2D bisectPoint, PolyMerge stayInside, Dimension2D alignment) {
986
1106
 
987
1107
        Cell cell = arc.getParent();
988
1108
        EPoint head = arc.getHeadLocation();
1015
1135
                name2 = nameToUse;
1016
1136
 
1017
1137
        // add two arcs to rebuild old startArc
 
1138
        boolean extendArcFromHeadSide = getExtendArcEnd(newPinRE, bisectPoint, arc.getLambdaBaseWidth(), arc.getProto(),
 
1139
                arc.getAngle(), arc.isTailExtended(), alignment);
 
1140
        boolean extendArcFromTailSide = getExtendArcEnd(newPinRE, bisectPoint, arc.getLambdaBaseWidth(), arc.getProto(),
 
1141
                arc.getAngle(), arc.isHeadExtended(), alignment);
1018
1142
        RouteElement newHeadArcRE = RouteElementArc.newArc(cell, arc.getProto(), arc.getLambdaBaseWidth(), headRE, newPinRE,
1019
 
            head, bisectPoint, name1, arc.getTextDescriptor(ArcInst.ARC_NAME), arc, arc.isHeadExtended(), arc.isTailExtended(), stayInside);
 
1143
            head, bisectPoint, name1, arc.getTextDescriptor(ArcInst.ARC_NAME), arc, arc.isHeadExtended(), extendArcFromHeadSide, stayInside);
1020
1144
        RouteElement newTailArcRE = RouteElementArc.newArc(cell, arc.getProto(), arc.getLambdaBaseWidth(), newPinRE, tailRE,
1021
 
            bisectPoint, tail, name2, arc.getTextDescriptor(ArcInst.ARC_NAME), arc, arc.isHeadExtended(), arc.isTailExtended(), stayInside);
 
1145
            bisectPoint, tail, name2, arc.getTextDescriptor(ArcInst.ARC_NAME), arc, extendArcFromTailSide, arc.isTailExtended(), stayInside);
1022
1146
        newHeadArcRE.setShowHighlight(false);
1023
1147
        newTailArcRE.setShowHighlight(false);
1024
1148
        // delete old arc
1036
1160
    protected static Point2D getCornerLocation(Point2D startLoc, Point2D endLoc, Point2D clicked, ArcProto startArc, ArcProto endArc,
1037
1161
                                               boolean contactsOnEndObj, PolyMerge stayInside, Rectangle2D contactArea,
1038
1162
                                               Poly startPolyFull, Poly endPolyFull, EditingPreferences ep) {
 
1163
        // connection point specified by contactArea
 
1164
        if (contactArea != null) {
 
1165
            return new Point2D.Double(contactArea.getCenterX(), contactArea.getCenterY());
 
1166
        }
 
1167
 
1039
1168
        // if startArc and endArc are the same, see if we can connect directly with whatever angle increment is on the arc
1040
1169
        boolean singleArc = false;
1041
1170
        if (startArc == endArc) {
1048
1177
        }
1049
1178
        else {
1050
1179
            // see if start and end line up in X or Y
1051
 
            if (startLoc.getX() == endLoc.getX() || startLoc.getY() == endLoc.getY()) singleArc = true;
 
1180
            if (DBMath.areEquals(startLoc.getX(), endLoc.getX()) || DBMath.areEquals(startLoc.getY(), endLoc.getY())) singleArc = true;
1052
1181
        }
1053
1182
 
1054
1183
        // if single arc, corner loc is either start or end loc
1059
1188
                return new Point2D.Double(startLoc.getX(), startLoc.getY());
1060
1189
        }
1061
1190
 
1062
 
        // connection point specified by contactArea
1063
 
        if (contactArea != null) {
1064
 
            return new Point2D.Double(contactArea.getCenterX(), contactArea.getCenterY());
1065
 
        }
1066
 
 
1067
1191
        Point2D cornerLoc = null;
1068
1192
 
1069
1193
        Point2D pin1 = new Point2D.Double(startLoc.getX(), endLoc.getY());
1129
1253
    protected static void addConnectingArc(Route route, Cell cell, RouteElementPort startRE, RouteElementPort endRE,
1130
1254
                                           Point2D startPoint, Point2D endPoint,
1131
1255
                                           ArcProto arc, double width, int arcAngle, boolean extendArcHead,
1132
 
                                           boolean extendArcTail, PolyMerge stayInside) {
 
1256
                                           boolean extendArcTail, PolyMerge stayInside, Dimension2D alignment) {
1133
1257
 
1134
 
        if (extendArcHead) extendArcHead = getExtendArcEnd(startRE, width, arc, arcAngle, extendArcHead);
1135
 
        if (extendArcTail) extendArcTail = getExtendArcEnd(endRE, width, arc, arcAngle, extendArcTail);
 
1258
        if (extendArcHead) extendArcHead = getExtendArcEnd(startRE, startPoint, width, arc, arcAngle, extendArcHead, alignment);
 
1259
        if (extendArcTail) extendArcTail = getExtendArcEnd(endRE, endPoint, width, arc, arcAngle, extendArcTail, alignment);
1136
1260
        RouteElementArc reArc = RouteElementArc.newArc(cell, arc, width, startRE, endRE, startPoint, endPoint,
1137
1261
                null, null, null, extendArcHead, extendArcTail, stayInside);
1138
1262
        reArc.setArcAngle(arcAngle);
1139
1263
        route.add(reArc);
1140
1264
    }
1141
1265
 
1142
 
    protected static boolean getExtendArcEnd(RouteElementPort re, double arcWidth, ArcProto arc, int arcAngle, boolean defExtends) {
 
1266
    protected static boolean getExtendArcEnd(RouteElementPort re, Point2D point, double arcWidth, ArcProto arc, int arcAngle, boolean defExtends, Dimension2D alignment) {
1143
1267
        NodeProto np = re.getNodeProto();
1144
1268
        if (np == null) return defExtends;
1145
1269
 
1152
1276
//            if (pn.getFunction() == PrimitiveNode.Function.PIN) {
1153
1277
//                checkAttachedArcs = true;
1154
1278
//            }
1155
 
            if (pn.getFunction() == PrimitiveNode.Function.CONTACT) {
 
1279
            if (pn.getFunction().isContact()) {
1156
1280
                Dimension2D size = re.getNodeSize();
1157
1281
                if (arcAngle % 1800 == 0) {
 
1282
                    if (arcWidth > size.getWidth()) return false;
 
1283
                }
 
1284
                if ((arcAngle+900) % 1800 == 0) {
1158
1285
                    if (arcWidth > size.getHeight()) return false;
1159
1286
                }
1160
 
                if ((arcAngle+900) % 1800 == 0) {
1161
 
                    if (arcWidth > size.getWidth()) return false;
1162
 
                }
1163
 
            }
1164
 
        }
 
1287
            }
 
1288
        }
 
1289
        if (alignment != null) {
 
1290
            if (arcAngle % 1800 == 0) {
 
1291
                // horizontal
 
1292
                if (isNumberAligned(point.getX(), alignment.getWidth()) &&
 
1293
                    !isNumberAligned(point.getX() + arcWidth/2, alignment.getWidth()))
 
1294
                    return false;
 
1295
                if (!isNumberAligned(point.getX(), alignment.getWidth()) &&
 
1296
                    isNumberAligned(point.getX() + arcWidth/2, alignment.getWidth()))
 
1297
                    return true;
 
1298
            }
 
1299
            if ((arcAngle+900) % 1800 == 0) {
 
1300
                // vertical
 
1301
                if (isNumberAligned(point.getY(), alignment.getHeight()) &&
 
1302
                    !isNumberAligned(point.getY() + arcWidth/2, alignment.getHeight()))
 
1303
                    return false;
 
1304
                if (!isNumberAligned(point.getY(), alignment.getHeight()) &&
 
1305
                    isNumberAligned(point.getY() + arcWidth/2, alignment.getHeight()))
 
1306
                    return true;
 
1307
            }
 
1308
        }
 
1309
 
1165
1310
/*
1166
1311
        if (checkAttachedArcs && re.getPortInst() != null) {
1167
1312
            double attachedWidth = getArcWidthToUse(re.getPortInst(), arc, arcAngle);
1171
1316
        return defExtends;
1172
1317
    }
1173
1318
 
 
1319
    private static boolean isNumberAligned(double number, double alignment) {
 
1320
        if (number % alignment == 0) return true;
 
1321
        return false;
 
1322
    }
1174
1323
 
1175
1324
    // ------------------------- Spatial Dimension Calculations -------------------------
1176
1325
 
1177
1326
    /**
1178
1327
     * Get closest value to clicked within a range from min to max
1179
1328
     */
1180
 
    protected static double getClosestValue(double min, double max, double clicked) {
 
1329
    protected static double getClosestValue(double min, double max, double clicked, double alignment) {
 
1330
        if (alignment > 0) {
 
1331
            max = Math.floor(max / alignment) * alignment;
 
1332
            min = Math.ceil(max / alignment) * alignment;
 
1333
            clicked = Math.round(max / alignment) * alignment;
 
1334
        }
1181
1335
        if (clicked >= max) {
1182
1336
            return max;
1183
1337
        } else if (clicked <= min) {