~ubuntu-branches/ubuntu/natty/electric/natty

« back to all changes in this revision

Viewing changes to com/sun/electric/tool/extract/Connectivity.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:
47
47
import com.sun.electric.database.prototype.PortProto;
48
48
import com.sun.electric.database.text.Name;
49
49
import com.sun.electric.database.text.TextUtils;
50
 
import com.sun.electric.database.topology.ArcInst;
51
 
import com.sun.electric.database.topology.NodeInst;
52
 
import com.sun.electric.database.topology.PortInst;
53
 
import com.sun.electric.database.topology.RTBounds;
54
 
import com.sun.electric.database.topology.RTNode;
 
50
import com.sun.electric.database.topology.*;
55
51
import com.sun.electric.database.variable.DisplayedText;
56
52
import com.sun.electric.database.variable.EditWindow_;
57
53
import com.sun.electric.database.variable.ElectricObject;
71
67
import com.sun.electric.tool.routing.AutoStitch;
72
68
import com.sun.electric.tool.routing.AutoStitch.AutoOptions;
73
69
import com.sun.electric.tool.user.ErrorLogger;
74
 
import com.sun.electric.tool.user.Highlight2;
 
70
import com.sun.electric.tool.user.Highlight;
 
71
import com.sun.electric.tool.user.User;
75
72
import com.sun.electric.tool.user.dialogs.EDialog;
76
73
import com.sun.electric.tool.user.ui.TopLevel;
77
74
 
83
80
import java.awt.event.ActionListener;
84
81
import java.awt.event.WindowAdapter;
85
82
import java.awt.event.WindowEvent;
86
 
import java.awt.geom.AffineTransform;
87
 
import java.awt.geom.Point2D;
88
 
import java.awt.geom.Rectangle2D;
89
 
import java.util.ArrayList;
90
 
import java.util.Collection;
91
 
import java.util.Collections;
92
 
import java.util.Comparator;
93
 
import java.util.HashMap;
94
 
import java.util.HashSet;
95
 
import java.util.Iterator;
96
 
import java.util.List;
97
 
import java.util.Map;
98
 
import java.util.Set;
99
 
import java.util.TreeMap;
100
 
import java.util.TreeSet;
 
83
import java.awt.geom.*;
 
84
import java.util.*;
101
85
import java.util.regex.Matcher;
102
86
import java.util.regex.Pattern;
103
87
import java.util.regex.PatternSyntaxException;
123
107
        /** layers to use for given arc functions */                            private Map<Layer.Function,Layer> layerForFunction;
124
108
        /** the layer to use for "polysilicon" geometry */                      private Layer polyLayer;
125
109
        /** temporary layers to use for geometric manipulation */       private Layer tempLayer1;
126
 
        /** the layers to use for "active" geometry */                          private Layer pActiveLayer, nActiveLayer;
 
110
        /** the layers to use for "active" geometry */                          private Layer activeLayer, pActiveLayer, nActiveLayer;
 
111
        /** the layers to use for "select" geometry */                          private Layer pSelectLayer, nSelectLayer;
127
112
        /** the real "active" layers */                                                         private Layer realPActiveLayer, realNActiveLayer;
128
 
        /** associates arc prototypes with layers */                            private Map<Layer,ArcProto> arcsForLayer;
 
113
    /** the well and substrate layers */                        private Layer wellLayer, substrateLayer;
 
114
    /** associates arc prototypes with layers */                                private Map<Layer,ArcProto> arcsForLayer;
129
115
        /** map of extracted cells */                                                           private Map<Cell,Cell> convertedCells;
130
116
        /** map of cut layers to lists of polygons on that layer */     private Map<Layer,CutInfo> allCutLayers;
131
117
        /** set of pure-layer nodes that are not processed */           private Set<PrimitiveNode> ignoreNodes;
132
118
        /** set of contacts that are not used for extraction */         private Set<PrimitiveNode> bogusContacts;
133
 
        /** list of Exports to restore after extraction */                      private List<Export> exportsToRestore;
 
119
    /** PrimitiveNodes for pdiff and ndiff */                   private PrimitiveNode diffNode, pDiffNode, nDiffNode;
 
120
    /** list of Exports to restore after extraction */                  private List<Export> exportsToRestore;
134
121
        /** auto-generated exports that may need better names */        private List<Export> generatedExports;
135
 
        /** true if this is a P-well process (presume P-well) */        private boolean pWellProcess;
136
 
        /** true if this is a N-well process (presume N-well) */        private boolean nWellProcess;
 
122
        /** true if this is a P-well process (presume P-well) */        private boolean pSubstrateProcess;
 
123
        /** true if this is a N-well process (presume N-well) */        private boolean nSubstrateProcess;
137
124
        /** helper variables for computing N/P process factors */       private boolean hasWell, hasPWell, hasNWell;
138
125
        /** true to unify N and P active layers */                                      private boolean unifyActive;
139
126
        /** helper variables for computing N and P active unify */      private boolean haveNActive, havePActive;
149
136
        /** total number of cells to extract when recursing */          private int totalCells;
150
137
        /** total number of cells extracted when recursing */           private int cellsExtracted;
151
138
        /** Job that is holding the process */                                          private Job job;
 
139
        /** Grid alignment for edges */                                                         private Dimension2D alignment;
152
140
 
153
141
        /**
154
142
         * Method to examine the current cell and extract it's connectivity in a new one.
269
257
                }
270
258
        }
271
259
 
272
 
        /**
273
 
         * Constructor to initialize connectivity extraction.
274
 
         * @param tech the Technology to extract to.
275
 
         */
 
260
    /**
 
261
     * Constructor to initialize connectivity extraction.
 
262
     * @param cell the cell
 
263
     * @param j the job
 
264
     * @param eLog the errorlongger
 
265
     * @param smallestPolygonSize the smallest polygon size
 
266
     * @param activeHandling ?
 
267
     * @param gridAlignExtraction true to align extraction to some the technology grid
 
268
     * @param approximateCuts approximate cuts
 
269
     * @param recursive run recursively
 
270
     * @param pat ?
 
271
     */
276
272
        private Connectivity(Cell cell, Job j, ErrorLogger eLog, double smallestPolygonSize, int activeHandling,
277
273
                boolean gridAlignExtraction, boolean approximateCuts, boolean recursive, Pattern pat)
278
274
        {
279
 
                this.gridAlignExtraction = gridAlignExtraction;
280
 
                this.approximateCuts = approximateCuts;
 
275
            this.approximateCuts = approximateCuts;
281
276
                this.recursive = recursive;
282
277
                tech = cell.getTechnology();
283
278
                convertedCells = new HashMap<Cell,Cell>();
286
281
                errorLogger = eLog;
287
282
                job = j;
288
283
 
289
 
                // find pure-layer nodes that are never involved in higher-level components, and should be ignored
 
284
        this.gridAlignExtraction = gridAlignExtraction;
 
285
            double scaledResolution = tech.getFactoryScaledResolution();
 
286
            alignment = new Dimension2D.Double(scaledResolution, scaledResolution);
 
287
 
 
288
        diffNode = pDiffNode = nDiffNode = null;
 
289
        // find pure-layer nodes that are never involved in higher-level components, and should be ignored
290
290
                ignoreNodes = new HashSet<PrimitiveNode>();
291
291
                for(Iterator<PrimitiveNode> pIt = tech.getNodes(); pIt.hasNext(); )
292
292
                {
305
305
                                validLayers = true;
306
306
                        }
307
307
                        if (!validLayers) ignoreNodes.add(np);
308
 
                }
 
308
 
 
309
            // determine diffusion nodes
 
310
            Layer layer = np.getLayerIterator().next();
 
311
            if (layer.getFunction() == Layer.Function.DIFF)
 
312
                diffNode = np;
 
313
            if (layer.getFunction() == Layer.Function.DIFFN)
 
314
                nDiffNode = np;
 
315
            if (layer.getFunction() == Layer.Function.DIFFP)
 
316
                pDiffNode = np;
 
317
        }
309
318
 
310
319
                // determine if this is a "P-well" or "N-well" process
311
320
                findMissingWells(cell, recursive, pat, activeHandling);
312
321
 
313
322
                // find important layers
314
323
                polyLayer = null;
315
 
                pActiveLayer = nActiveLayer = null;
 
324
                activeLayer = pActiveLayer = nActiveLayer = null;
316
325
                realPActiveLayer = realNActiveLayer = null;
317
 
                for(Iterator<Layer> it = tech.getLayers(); it.hasNext(); )
 
326
        pSelectLayer = nSelectLayer = null;
 
327
        wellLayer = substrateLayer = null;
 
328
        for(Iterator<Layer> it = tech.getLayers(); it.hasNext(); )
318
329
                {
319
330
                        Layer layer = it.next();
320
331
                        Layer.Function fun = layer.getFunction();
321
332
                        if (polyLayer == null && fun == Layer.Function.POLY1) polyLayer = layer;
322
 
                        if (unifyActive)
323
 
                        {
324
 
                                if (pActiveLayer == null && fun.isDiff()) pActiveLayer = layer;
325
 
                        } else
326
 
                        {
327
 
                                if (pActiveLayer == null && fun == Layer.Function.DIFFP) pActiveLayer = layer;
328
 
                                if (nActiveLayer == null && fun == Layer.Function.DIFFN) nActiveLayer = layer;
329
 
                        }
 
333
            if (activeLayer == null && fun == Layer.Function.DIFF) activeLayer = layer;
 
334
            if (pActiveLayer == null && fun == Layer.Function.DIFFP) pActiveLayer = layer;
 
335
            if (nActiveLayer == null && fun == Layer.Function.DIFFN) nActiveLayer = layer;
330
336
                        if (realPActiveLayer == null && fun == Layer.Function.DIFFP) realPActiveLayer = layer;
331
337
                        if (realNActiveLayer == null && fun == Layer.Function.DIFFN) realNActiveLayer = layer;
332
 
                }
 
338
            if (pSelectLayer == null && fun == Layer.Function.IMPLANTP) pSelectLayer = layer;
 
339
            if (nSelectLayer == null && fun == Layer.Function.IMPLANTN) nSelectLayer = layer;
 
340
            if (pSubstrateProcess) // psubstrate
 
341
            {
 
342
                if (wellLayer == null && fun == Layer.Function.WELLN) wellLayer = layer;
 
343
                if (substrateLayer == null && fun == Layer.Function.WELLP) substrateLayer = layer;
 
344
            }
 
345
            if (nSubstrateProcess) // nsubstrate
 
346
            {
 
347
                if (wellLayer == null && fun == Layer.Function.WELLP) wellLayer = layer;
 
348
                if (substrateLayer == null && fun == Layer.Function.WELLN) substrateLayer = layer;
 
349
            }
 
350
        }
333
351
                polyLayer = polyLayer.getNonPseudoLayer();
334
352
                if (polyLayer != null)
335
353
                        tempLayer1 = polyLayer.getPseudoLayer();
336
 
                pActiveLayer = pActiveLayer.getNonPseudoLayer();
337
 
                if (unifyActive) nActiveLayer = pActiveLayer; else
338
 
                        nActiveLayer = nActiveLayer.getNonPseudoLayer();
 
354
        if (pActiveLayer == null || nActiveLayer == null && activeLayer != null) {
 
355
            unifyActive = true;
 
356
            pActiveLayer = nActiveLayer = activeLayer;
 
357
        } else {
 
358
            unifyActive = false;
 
359
            pActiveLayer = pActiveLayer.getNonPseudoLayer();
 
360
            nActiveLayer = nActiveLayer.getNonPseudoLayer();
 
361
        }
339
362
 
340
363
                // figure out which arcs to use for a layer
341
364
                arcsForLayer = new HashMap<Layer,ArcProto>();
489
512
 
490
513
                // create a merge for the geometry in the cell
491
514
                PolyMerge merge = new PolyMerge();
 
515
        PolyMerge selectMerge = new PolyMerge();
492
516
 
493
 
                // convert the nodes
 
517
        // convert the nodes
494
518
                if (!startSection(oldCell, "Gathering geometry in " + oldCell + "..."))         // HAS PROGRESS IN IT
495
519
                        return null; // aborted
496
520
                Set<Cell> expandedCells = new HashSet<Cell>();
498
522
                generatedExports = new ArrayList<Export>();
499
523
                pinsForLater = new ArrayList<ExportedPin>();
500
524
                allCutLayers = new TreeMap<Layer,CutInfo>();
501
 
                extractCell(oldCell, newCell, pat, flattenPcells, expandedCells, merge, GenMath.MATID, Orientation.IDENT);
 
525
                extractCell(oldCell, newCell, pat, flattenPcells, expandedCells, merge, selectMerge, GenMath.MATID, Orientation.IDENT);
502
526
                if (expandedCells.size() > 0)
503
527
                {
504
528
                        System.out.print("These cells were expanded:");
523
547
                extractTransistors(merge, originalMerge, newCell);
524
548
                termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Transistors");
525
549
 
526
 
                // extend geometry that sticks out in space
527
 
                initDebugging();
528
 
                if (!startSection(oldCell, "Extracting extensions...")) return null; // aborted
529
 
                extendGeometry(merge, originalMerge, newCell, true);
530
 
                termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "StickOuts");
531
 
 
532
 
                // look for wires and pins
533
 
                initDebugging();
534
 
                if (!startSection(oldCell, "Extracting wires...")) return null; // aborted
535
 
                if (makeWires(merge, originalMerge, newCell)) return newCell;
536
 
                termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Wires");
537
 
 
538
 
                // convert any geometry that connects two networks
539
 
                initDebugging();
540
 
                if (!startSection(oldCell, "Extracting connections...")) return null; // aborted
541
 
                extendGeometry(merge, originalMerge, newCell, false);
542
 
                termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Bridges");
543
 
 
544
 
                // dump any remaining layers back in as extra pure layer nodes
545
 
                initDebugging();
546
 
                if (!startSection(oldCell, "Extracting leftover geometry...")) return null; // aborted
547
 
                convertAllGeometry(merge, originalMerge, newCell);
548
 
                termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Pures");
549
 
 
550
 
                // reexport any that were there before
 
550
        if (Extract.isUsePureLayerNodes()) {
 
551
            // dump back in original routing layers
 
552
            if (!startSection(oldCell, "Adding in original routing layers...")) return null;
 
553
            addInRoutingLayers(oldCell, newCell, merge, originalMerge);
 
554
 
 
555
        } else {
 
556
 
 
557
            // extend geometry that sticks out in space
 
558
    /*
 
559
            initDebugging();
 
560
            if (!startSection(oldCell, "Extracting extensions...")) return null; // aborted
 
561
            extendGeometry(merge, originalMerge, newCell, true);
 
562
            termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "StickOuts");
 
563
    */
 
564
 
 
565
            // look for wires and pins
 
566
            initDebugging();
 
567
            if (!startSection(oldCell, "Extracting wires...")) return null; // aborted
 
568
            if (makeWires(merge, originalMerge, newCell)) return newCell;
 
569
            termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Wires");
 
570
 
 
571
            // convert any geometry that connects two networks
 
572
            initDebugging();
 
573
            if (!startSection(oldCell, "Extracting connections...")) return null; // aborted
 
574
            extendGeometry(merge, originalMerge, newCell, false);
 
575
            termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Bridges");
 
576
        }
 
577
 
 
578
        // dump any remaining layers back in as extra pure layer nodes
 
579
        initDebugging();
 
580
        if (!startSection(oldCell, "Extracting leftover geometry...")) return null; // aborted
 
581
        convertAllGeometry(merge, originalMerge, newCell);
 
582
        termDebugging(addedBatchRectangles, addedBatchLines, addedBatchNames, "Pures");
 
583
 
 
584
        // reexport any that were there before
551
585
                if (!startSection(oldCell, "Adding connecting wires...")) return null; // aborted
552
586
                cleanupExports(oldCell, newCell);
553
587
 
557
591
                AffineTransform shrink = new AffineTransform(shrinkage, 0, 0, shrinkage, 0, 0);
558
592
                originalUnscaledMerge.addMerge(originalMerge, shrink);
559
593
                Set<ArcInst> allArcs = null;
560
 
                if (DEBUGSTEPS)
561
 
                {
562
 
                        allArcs = new HashSet<ArcInst>();
563
 
                        for(Iterator<ArcInst> it = newCell.getArcs(); it.hasNext(); )
564
 
                                allArcs.add(it.next());
565
 
                }
566
 
                AutoOptions prefs = new AutoOptions();
 
594
 
 
595
        allArcs = new HashSet<ArcInst>();
 
596
        for(Iterator<ArcInst> it = newCell.getArcs(); it.hasNext(); )
 
597
            allArcs.add(it.next());
 
598
 
 
599
        // make sure current arc is not universal arc, otherwise it makes the InteractiveRouter (used by AutoStitch) prefer that arc
 
600
        if (User.getUserTool().getCurrentArcProto() == Generic.tech().universal_arc) {
 
601
            User.getUserTool().setCurrentArcProto(newCell.getTechnology().getArcs().next());
 
602
        }
 
603
 
 
604
        // TODO: originalMerge passed to auto stitcher really needs to include subcell geometry too, in order
 
605
        // for the auto-stitcher to know where it can place arcs. However, building and maintaining such a hashmap
 
606
        // might take up a lot of memory.
 
607
        AutoOptions prefs = new AutoOptions();
567
608
                prefs.createExports = true;
568
 
                AutoStitch.runAutoStitch(newCell, null, null, job, originalUnscaledMerge, null, false, prefs, !recursive);
569
 
                if (DEBUGSTEPS)
 
609
                AutoStitch.runAutoStitch(newCell, null, null, job, originalUnscaledMerge, null, false, true, prefs, !recursive, alignment);
 
610
 
 
611
        // check all the arcs that auto-stitching added, and replace them by universal arcs if they are off-grid
 
612
        if (alignment != null && (alignment.getWidth() > 0 || alignment.getHeight() > 0)) {
 
613
            for(Iterator<ArcInst> it = newCell.getArcs(); it.hasNext(); ) {
 
614
                ArcInst ai = it.next();
 
615
                if (allArcs.contains(ai)) continue; 
 
616
                Rectangle2D bounds = ai.getBounds();
 
617
                if (bounds.getMinX() % alignment.getWidth() != 0 || bounds.getMinY() % alignment.getHeight() != 0 ||
 
618
                    bounds.getMaxX() % alignment.getWidth() != 0 || bounds.getMaxY() % alignment.getHeight() != 0) {
 
619
                    // replace
 
620
                    Connection head = ai.getHead();
 
621
                    Connection tail = ai.getTail();
 
622
                    ArcInst newAi = ArcInst.makeInstanceBase(Generic.tech().universal_arc, 0, head.getPortInst(), tail.getPortInst(),
 
623
                            head.getLocation(), tail.getLocation(), null);
 
624
                    if (newAi != null) {
 
625
                        newAi.setHeadExtended(false);
 
626
                        newAi.setTailExtended(false);
 
627
                        ai.kill();
 
628
                    }
 
629
                }
 
630
            }
 
631
        }
 
632
 
 
633
        if (DEBUGSTEPS)
570
634
                {
571
635
                        initDebugging();
572
636
                        for(Iterator<ArcInst> it = newCell.getArcs(); it.hasNext(); )
646
710
         * @param prevTrans the transformation coming into this cell.
647
711
         */
648
712
        private void extractCell(Cell oldCell, Cell newCell, Pattern pat, boolean flattenPcells, Set<Cell> expandedCells,
649
 
                PolyMerge merge, AffineTransform prevTrans, Orientation orient)
 
713
                PolyMerge merge, PolyMerge selectMerge, AffineTransform prevTrans, Orientation orient)
650
714
        {
651
715
                Map<NodeInst,NodeInst> newNodes = new HashMap<NodeInst,NodeInst>();
652
716
                int totalNodes = oldCell.getNumNodes();
653
717
        Dimension2D alignementToGrid = newCell.getEditingPreferences().getAlignmentToGrid();
654
 
                int soFar = 0;
 
718
 
 
719
        // first get select, so we can determine proper active type
 
720
        if (!unifyActive && !ignoreActiveSelectWell)
 
721
        {
 
722
            for (Iterator<NodeInst> nIt = oldCell.getNodes(); nIt.hasNext(); )
 
723
            {
 
724
                NodeInst ni = nIt.next();
 
725
                if (ni.isCellInstance()) continue;
 
726
                Poly [] polys = tech.getShapeOfNode(ni);
 
727
                for(int j=0; j<polys.length; j++)
 
728
                {
 
729
                    Poly poly = polys[j];
 
730
 
 
731
                    // get the layer for the geometry
 
732
                    Layer layer = poly.getLayer();
 
733
                    if (layer == null) continue;
 
734
 
 
735
                    // make sure the geometric database is made up of proper layers
 
736
                    layer = geometricLayer(layer);
 
737
                    if (layer.getFunction() != Layer.Function.IMPLANTN && layer.getFunction() != Layer.Function.IMPLANTP) continue;
 
738
 
 
739
                    // selectMerge has non-scaled-up coords, and has all geom coords relative to top level
 
740
                    AffineTransform trans = ni.rotateOut(prevTrans);
 
741
                    poly.transform(trans);
 
742
                    selectMerge.add(layer, poly);
 
743
                }
 
744
            }
 
745
        }
 
746
 
 
747
        int soFar = 0;
655
748
                for(Iterator<NodeInst> nIt = oldCell.getNodes(); nIt.hasNext(); )
656
749
                {
657
750
                        NodeInst ni = nIt.next();
673
766
                                        expandedCells.add(subCell);
674
767
                                        AffineTransform subTrans = ni.translateOut(ni.rotateOut(prevTrans));
675
768
                                        Orientation or = orient.concatenate(ni.getOrient());
676
 
                                        extractCell(subCell, newCell, pat, flattenPcells, expandedCells, merge, subTrans, or);
 
769
                                        extractCell(subCell, newCell, pat, flattenPcells, expandedCells, merge, selectMerge, subTrans, or);
677
770
                                        continue;
678
771
                                }
679
772
 
685
778
                                PrimitiveNode np = (PrimitiveNode)ni.getProto();
686
779
 
687
780
                                // special case for exported but unconnected pins: save for later
688
 
                                if (np.getFunction() == PrimitiveNode.Function.PIN)
 
781
                                if (np.getFunction().isPin())
689
782
                                {
690
783
                                        if (ni.hasExports() && !ni.hasConnections())
691
784
                                        {
786
879
                                                }
787
880
                                        }
788
881
                                }
 
882
 
 
883
                // check overlap with selectMerge here, after poly has been rotated up to top level, but before scaling
 
884
                if (layer.getFunction() == Layer.Function.DIFFN) {
 
885
                    // make sure n-diffusion is in n-select
 
886
                    if (selectMerge.contains(pSelectLayer, poly)) {
 
887
                        // switch it pactive
 
888
                        layer = pActiveLayer;
 
889
                    }
 
890
                }
 
891
                if (layer.getFunction() == Layer.Function.DIFFP) {
 
892
                    // make sure p-diffusion is in p-select
 
893
                    if (selectMerge.contains(nSelectLayer, poly)) {
 
894
                        // switch it nactive
 
895
                        layer = nActiveLayer;
 
896
                    }
 
897
                }
 
898
 
789
899
                                for(int i=0; i<points.length; i++)
790
900
                                        poly.setPoint(i, scaleUp(points[i].getX()), scaleUp(points[i].getY()));
791
901
 
873
983
                recurseMissingWells(cell, recursive, pat);
874
984
                if (!hasPWell)
875
985
                {
876
 
                        pWellProcess = true;
877
 
                        System.out.println("Presuming a P-well process");
 
986
                        pSubstrateProcess = true;
 
987
                        System.out.println("Presuming a P-substrate process");
878
988
                } else if (!hasNWell && !hasWell)
879
989
                {
880
 
                        nWellProcess = true;
881
 
                        System.out.println("Presuming an N-well process");
 
990
                        nSubstrateProcess = true;
 
991
                        System.out.println("Presuming an N-substrate process");
882
992
                }
883
993
 
884
994
                // see how active layers should be handled
885
 
                unifyActive = (activeHandling == 1);
886
995
                ignoreActiveSelectWell = (activeHandling == 2);
887
 
                if (!unifyActive)
888
 
                {
889
 
                        if (!haveNActive || !havePActive)
890
 
                        {
891
 
                                System.out.println("Found only one type of active layer...unifying all active layers");
892
 
                                unifyActive = true;
893
 
                        }
894
 
                }
895
996
        }
896
997
 
897
998
        /**
1012
1113
 
1013
1114
        /********************************************** WIRE EXTRACTION **********************************************/
1014
1115
 
 
1116
        private boolean isOnGrid(double value, double grid)
 
1117
        {
 
1118
                if (grid == 0) return true;
 
1119
                long x = Math.round(value / grid);
 
1120
                return x * grid == value;
 
1121
        }
 
1122
 
1015
1123
        /**
1016
1124
         * Method to extract wires from the merge.
1017
1125
         * @param merge the merged geometry that remains (after contacts and transistors are extracted).
1036
1144
                }
1037
1145
 
1038
1146
                // examine each wire layer, looking for a skeletal structure that approximates it
1039
 
        Dimension2D alignment = newCell.getEditingPreferences().getAlignmentToGrid();
1040
1147
                int soFar = 0;
1041
1148
                Set<Layer> allLayers = geomToWire.keySet();
1042
1149
                for (Layer layer : allLayers)
1060
1167
                                // now realize the wires
1061
1168
                                for(Centerline cl : lines)
1062
1169
                                {
1063
 
                                        Point2D loc1Unscaled = new Point2D.Double();
 
1170
                    ap = findArcProtoForPoly(layer, poly, originalMerge);
 
1171
                    Point2D loc1Unscaled = new Point2D.Double();
 
1172
                                        Point2D loc2Unscaled = new Point2D.Double();
1064
1173
                                        PortInst pi1 = locatePortOnCenterline(cl, loc1Unscaled, layer, ap, true, newCell);
1065
 
                                        Point2D loc2Unscaled = new Point2D.Double();
 
1174
                                        Point2D loc1 = new Point2D.Double(scaleUp(loc1Unscaled.getX()), scaleUp(loc1Unscaled.getY()));
1066
1175
                                        PortInst pi2 = locatePortOnCenterline(cl, loc2Unscaled, layer, ap, false, newCell);
1067
 
                                        Point2D loc1 = new Point2D.Double(scaleUp(loc1Unscaled.getX()), scaleUp(loc1Unscaled.getY()));
1068
1176
                                        Point2D loc2 = new Point2D.Double(scaleUp(loc2Unscaled.getX()), scaleUp(loc2Unscaled.getY()));
1069
1177
 
1070
1178
                                        // make sure the wire fits
1071
1179
                                        MutableBoolean headExtend = new MutableBoolean(true), tailExtend = new MutableBoolean(true);
 
1180
 
 
1181
                                        // adjust extension to get alignment right
 
1182
                                        if (loc1.getX() == loc2.getX())
 
1183
                                        {
 
1184
                                                // vertical arc: adjust extension to make sure top and bottom are on grid
 
1185
                                                double loc1Y = loc1Unscaled.getY();
 
1186
                                                double loc2Y = loc2Unscaled.getY();
 
1187
                                                double halfWidth = cl.width/2/SCALEFACTOR;
 
1188
                                                double loc1YExtend = loc1Y + (loc1Y < loc2Y ? -halfWidth : halfWidth);
 
1189
                                                double loc2YExtend = loc2Y + (loc2Y < loc1Y ? -halfWidth : halfWidth);
 
1190
                                                if (!isOnGrid(loc1YExtend, alignment.getHeight()) && isOnGrid(loc1Y, alignment.getHeight()))
 
1191
                                                        headExtend.setValue(false);
 
1192
                                                if (!isOnGrid(loc2YExtend, alignment.getHeight()) && isOnGrid(loc2Y, alignment.getHeight()))
 
1193
                                                        tailExtend.setValue(false);
 
1194
                                        } else if (loc1.getY() == loc2.getY())
 
1195
                                        {
 
1196
                                                // horizontal arc: adjust extension to make sure left and right are on grid
 
1197
                                                double loc1X = loc1Unscaled.getX();
 
1198
                                                double loc2X = loc2Unscaled.getX();
 
1199
                                                double halfWidth = cl.width/2/SCALEFACTOR;
 
1200
                                                double loc1XExtend = loc1X + (loc1X < loc2X ? -halfWidth : halfWidth);
 
1201
                                                double loc2XExtend = loc2X + (loc2X < loc1X ? -halfWidth : halfWidth);
 
1202
                                                if (!isOnGrid(loc1XExtend, alignment.getWidth()) && isOnGrid(loc1X, alignment.getWidth()))
 
1203
                                                        headExtend.setValue(false);
 
1204
                                                if (!isOnGrid(loc2XExtend, alignment.getWidth()) && isOnGrid(loc2X, alignment.getWidth()))
 
1205
                                                        tailExtend.setValue(false);
 
1206
                                        }
 
1207
 
1072
1208
                                        boolean fits = originalMerge.arcPolyFits(layer, loc1, loc2, cl.width, headExtend, tailExtend);
1073
1209
                                        if (DEBUGCENTERLINES) System.out.println("FIT="+fits+" "+cl);
1074
1210
                                        if (!fits)
1091
1227
                                                        if (DEBUGCENTERLINES) System.out.println("   WID="+(cl.width/SCALEFACTOR)+" FIT="+fits);
1092
1228
                                                }
1093
1229
                                        }
1094
 
                                        if (!fits)
 
1230
                                        while (!fits)
 
1231
                                        {
 
1232
                                                double wid = cl.width - SCALEFACTOR;
 
1233
                                                if (wid < 0) break;
 
1234
                                                cl.width = wid;
 
1235
                                                fits = originalMerge.arcPolyFits(layer, loc1, loc2, cl.width, headExtend, tailExtend);
 
1236
                                                if (DEBUGCENTERLINES) System.out.println("   WID="+(cl.width/SCALEFACTOR)+" FIT="+fits);
 
1237
                                        }
 
1238
                                        if (!fits || (loc1Unscaled.distance(loc2Unscaled) == 0 && !headExtend.booleanValue() && !tailExtend.booleanValue()))
1095
1239
                                        {
1096
1240
                                                cl.width = 0;
1097
 
                                                fits = originalMerge.arcPolyFits(layer, loc1, loc2, cl.width, headExtend, tailExtend);
1098
 
                                                if (DEBUGCENTERLINES) System.out.println("   WID=0 FIT="+fits);
 
1241
                                                ap = Generic.tech().universal_arc;
1099
1242
                                        }
1100
 
                                        if (!fits) continue;
1101
 
 
 
1243
                    if (loc1Unscaled.distance(loc2Unscaled) == 0 && !headExtend.booleanValue() && !tailExtend.booleanValue()) {
 
1244
                        //System.out.println("zero length arc in make wires");
 
1245
                    }
1102
1246
                                        // create the wire
1103
1247
                                        ArcInst ai = realizeArc(ap, pi1, pi2, loc1Unscaled, loc2Unscaled, cl.width / SCALEFACTOR,
1104
1248
                                                !headExtend.booleanValue(), !tailExtend.booleanValue(), merge);
1115
1259
                        }
1116
1260
                }
1117
1261
 
1118
 
                // examine each wire layer, looking for a simple rectangle that covers it
 
1262
        // add in pure layer node for remaining geom
 
1263
        for (Layer layer : allLayers)
 
1264
        {
 
1265
            List<PolyBase> polyList = getMergePolys(merge, layer, null);
 
1266
            for(PolyBase poly : polyList)
 
1267
            {
 
1268
                ArcProto ap = findArcProtoForPoly(layer, poly, originalMerge);
 
1269
                if (ap == null) continue;
 
1270
                PrimitiveNode pin = ap.findPinProto();
 
1271
 
 
1272
                List<NodeInst> niList = makePureLayerNodeFromPoly(poly, newCell, merge);
 
1273
                merge.subtract(layer, poly);
 
1274
                // connect up to enclosed pins
 
1275
                for (NodeInst ni : niList)
 
1276
                {
 
1277
                    PortInst fPi = ni.getOnlyPortInst();
 
1278
                    Rectangle2D polyBounds = ni.getBounds();
 
1279
                    Rectangle2D searchBound = new Rectangle2D.Double(polyBounds.getMinX(), polyBounds.getMinY(),
 
1280
                        polyBounds.getWidth(), polyBounds.getHeight());
 
1281
                    for(Iterator<RTBounds> it = newCell.searchIterator(searchBound); it.hasNext(); )
 
1282
                    {
 
1283
                        RTBounds geom = it.next();
 
1284
                        if (!(geom instanceof NodeInst)) continue;
 
1285
                        NodeInst oNi = (NodeInst)geom;
 
1286
                        if (oNi == ni) continue;
 
1287
                        if (oNi.getProto() != pin) continue;
 
1288
                        // make sure center of pin is in bounds
 
1289
                        if (!DBMath.pointInsideRect(oNi.getAnchorCenter(), searchBound)) continue;
 
1290
                        
 
1291
                        // replace arcs that end on pin to end on pure layer node
 
1292
                        for (Iterator<Connection> cit = oNi.getConnections(); cit.hasNext(); ) {
 
1293
                            Connection conn = cit.next();
 
1294
                            Connection oConn;
 
1295
                            ArcInst ai = conn.getArc();
 
1296
                            if (ai.getProto() == Generic.tech().universal_arc) continue;
 
1297
                            ArcInst newAi;
 
1298
                            if (conn instanceof HeadConnection) {
 
1299
                                oConn = ai.getTail();
 
1300
                                newAi = ArcInst.makeInstanceBase(ap, ai.getLambdaBaseWidth(), fPi, oConn.getPortInst(),
 
1301
                                        conn.getLocation(), oConn.getLocation(), null);
 
1302
                            } else {
 
1303
                                oConn = ai.getHead();
 
1304
                                newAi = ArcInst.makeInstanceBase(ap, ai.getLambdaBaseWidth(), oConn.getPortInst(), fPi,
 
1305
                                        oConn.getLocation(), conn.getLocation(), null);
 
1306
                            }
 
1307
                            if (newAi != null) {
 
1308
                                newAi.setHeadExtended(ai.isHeadExtended());
 
1309
                                newAi.setTailExtended(ai.isTailExtended());
 
1310
                                if (newAi.getLambdaLength() == 0)
 
1311
                                    System.out.println("arc inst of zero length connecting pure layer nodes");
 
1312
                                ai.kill();
 
1313
                            } else {
 
1314
                                String msg = "Cell " + newCell.describe(false) + ": Failed to replace arc " + ap.getName() +
 
1315
                                    " from (" + conn.getLocation().getX() + "," +
 
1316
                                    conn.getLocation().getY() + ") on node " + ni.describe(false) + " to (" +
 
1317
                                    oConn.getLocation().getX() + "," + oConn.getLocation().getY() + ")";
 
1318
                                addErrorLog(newCell, msg, new EPoint(conn.getLocation().getX(), conn.getLocation().getY()),
 
1319
                                    new EPoint(oConn.getLocation().getX(), oConn.getLocation().getY()));
 
1320
                            }
 
1321
                        }
 
1322
                    }
 
1323
                }
 
1324
            }
 
1325
        }
 
1326
        if (true) return false;
 
1327
 
 
1328
        // examine each wire layer, looking for a simple rectangle that covers it
1119
1329
                for(Layer layer : allLayers)
1120
1330
                {
1121
1331
                        // examine the geometry on the layer
1123
1333
                        for(PolyBase poly : polyList)
1124
1334
                        {
1125
1335
                                Rectangle2D bounds = poly.getBounds2D();
 
1336
 
 
1337
                                // make sure polygon is in the merge
1126
1338
                                Poly rectPoly = new Poly(bounds);
1127
1339
                                if (!originalMerge.contains(layer, rectPoly)) continue;
1128
1340
 
 
1341
                                // grid align the edges of this rectangle
 
1342
                                double lX = bounds.getMinX()/SCALEFACTOR, hX = bounds.getMaxX()/SCALEFACTOR;
 
1343
                                double lY = bounds.getMinY()/SCALEFACTOR, hY = bounds.getMaxY()/SCALEFACTOR;
 
1344
                                double alignX = alignment.getWidth();
 
1345
                                double alignY = alignment.getHeight();
 
1346
                                if (!isOnGrid(lX, alignX)) lX = Math.ceil(lX / alignX) * alignX;
 
1347
                                if (!isOnGrid(hX, alignX)) hX = Math.floor(hX / alignX) * alignX;
 
1348
                                if (!isOnGrid(lY, alignY)) lY = Math.ceil(lY / alignY) * alignY;
 
1349
                                if (!isOnGrid(hY, alignY)) hY = Math.floor(hY / alignY) * alignY;
 
1350
                                if (lX >= hX || lY >= hY) continue;
 
1351
 
 
1352
                                // grid align the center of this rectangle
 
1353
/*
 
1354
                                double cX = (lX + hX) / 2, cY = (lY + hY) / 2;
 
1355
                                if (!isOnGrid(cX, alignX))
 
1356
                                {
 
1357
                                        // try expanding to the right so center is aligned
 
1358
                                        double cXright = Math.ceil(cX / alignX) * alignX;
 
1359
                                        Poly testPoly = new Poly(cXright*SCALEFACTOR, cY*SCALEFACTOR, ((cXright-lX) * 2)*SCALEFACTOR, (hY-lY)*SCALEFACTOR);
 
1360
                                        if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
 
1361
                                        {
 
1362
                                                // try expanding to the left so center is aligned
 
1363
                                                double cXleft = Math.floor(cX / alignX) * alignX;
 
1364
                                                testPoly = new Poly(cXleft*SCALEFACTOR, cY*SCALEFACTOR, ((hX-cXleft) * 2)*SCALEFACTOR, (hY-lY)*SCALEFACTOR);
 
1365
                                                if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
 
1366
                                                {
 
1367
                                                        // try contracting on the right so center is aligned
 
1368
                                                        testPoly = new Poly(cXright*SCALEFACTOR, cY*SCALEFACTOR, ((hX-cXright) * 2)*SCALEFACTOR, (hY-lY)*SCALEFACTOR);
 
1369
                                                        if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
 
1370
                                                        {
 
1371
                                                                // try contracting on the left so center is aligned
 
1372
                                                                testPoly = new Poly(cXleft*SCALEFACTOR, cY*SCALEFACTOR, ((cXleft-lX) * 2)*SCALEFACTOR, (hY-lY)*SCALEFACTOR);
 
1373
                                                                if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
 
1374
                                                                        continue;
 
1375
                                                        }
 
1376
                                                }
 
1377
                                        }
 
1378
                                        if (bounds.getWidth() <= 0) continue;
 
1379
                                        lX = bounds.getMinX()/SCALEFACTOR;
 
1380
                                        hX = bounds.getMaxX()/SCALEFACTOR;
 
1381
                                        cX = (lX + hX) / 2;
 
1382
                                }
 
1383
 
 
1384
                                if (!isOnGrid(cY, alignY))
 
1385
                                {
 
1386
                                        // try expanding upward so center is aligned
 
1387
                                        double cYup = Math.ceil(cY / alignY) * alignY;
 
1388
                                        Poly testPoly = new Poly(cX*SCALEFACTOR, cYup*SCALEFACTOR, (hX-lX)*SCALEFACTOR, ((cYup-lY) * 2)*SCALEFACTOR);
 
1389
                                        if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
 
1390
                                        {
 
1391
                                                // try expanding downward so center is aligned
 
1392
                                                double cYdown = Math.floor(cY / alignY) * alignY;
 
1393
                                                testPoly = new Poly(cX*SCALEFACTOR, cYdown*SCALEFACTOR, (hX-lX)*SCALEFACTOR, ((hY-cYdown) * 2)*SCALEFACTOR);
 
1394
                                                if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
 
1395
                                                {
 
1396
                                                        // try contracting upward so center is aligned
 
1397
                                                        testPoly = new Poly(cX*SCALEFACTOR, cYup*SCALEFACTOR, (hX-lX)*SCALEFACTOR, ((hY-cYup) * 2)*SCALEFACTOR);
 
1398
                                                        if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
 
1399
                                                        {
 
1400
                                                                // try contracting downward so center is aligned
 
1401
                                                                testPoly = new Poly(cX*SCALEFACTOR, cYdown*SCALEFACTOR, (hX-lX)*SCALEFACTOR, ((cYdown-lY) * 2)*SCALEFACTOR);
 
1402
                                                                if (originalMerge.contains(layer, testPoly)) bounds = testPoly.getBounds2D(); else
 
1403
                                                                        continue;
 
1404
                                                        }
 
1405
                                                }
 
1406
                                        }
 
1407
                                        if (bounds.getHeight() <= 0) continue;
 
1408
                                }
 
1409
*/
 
1410
 
1129
1411
                                // figure out which arc proto to use for the layer
1130
1412
                                ArcProto ap = findArcProtoForPoly(layer, poly, originalMerge);
1131
1413
                                if (ap == null) continue;
1132
1414
 
1133
1415
                                // determine the endpoints of the arc
1134
1416
                                Point2D loc1, loc2;
1135
 
                                double width = Math.min(bounds.getWidth(), bounds.getHeight());
1136
 
                                if (bounds.getWidth() > bounds.getHeight())
 
1417
                                double width;
 
1418
                if (bounds.getWidth() > bounds.getHeight())
1137
1419
                                {
1138
 
                                        loc1 = new Point2D.Double((bounds.getMinX() + width/2) / SCALEFACTOR, bounds.getCenterY() / SCALEFACTOR);
1139
 
                                        loc2 = new Point2D.Double((bounds.getMaxX() - width/2) / SCALEFACTOR, bounds.getCenterY() / SCALEFACTOR);
 
1420
                    // horizontal arc
 
1421
                    width = bounds.getHeight();
 
1422
                    loc1 = new Point2D.Double((bounds.getMinX()) / SCALEFACTOR, bounds.getCenterY() / SCALEFACTOR);
 
1423
                                        loc2 = new Point2D.Double((bounds.getMaxX()) / SCALEFACTOR, bounds.getCenterY() / SCALEFACTOR);
1140
1424
                                } else
1141
1425
                                {
1142
 
                                        loc1 = new Point2D.Double(bounds.getCenterX() / SCALEFACTOR, (bounds.getMinY() + width/2) / SCALEFACTOR);
1143
 
                                        loc2 = new Point2D.Double(bounds.getCenterX() / SCALEFACTOR, (bounds.getMaxY() - width/2) / SCALEFACTOR);
 
1426
                    // vertical arc
 
1427
                    width = bounds.getWidth();
 
1428
                    loc1 = new Point2D.Double(bounds.getCenterX() / SCALEFACTOR, (bounds.getMinY()) / SCALEFACTOR);
 
1429
                                        loc2 = new Point2D.Double(bounds.getCenterX() / SCALEFACTOR, (bounds.getMaxY()) / SCALEFACTOR);
1144
1430
                                }
1145
1431
                                PortInst pi1 = wantConnectingNodeAt(loc1, ap, width / SCALEFACTOR, newCell);
1146
1432
                                PortInst pi2 = wantConnectingNodeAt(loc2, ap, width / SCALEFACTOR, newCell);
1147
 
                                realizeArc(ap, pi1, pi2, loc1, loc2, width / SCALEFACTOR, false, false, merge);
 
1433
                                realizeArc(ap, pi1, pi2, loc1, loc2, width / SCALEFACTOR, true, true, merge);
1148
1434
                        }
1149
1435
                }
1150
1436
                return false;
1151
1437
        }
1152
1438
 
1153
 
        /**
 
1439
    /**
 
1440
     * Choose the right type of active for the active in the merge (takes into account select)
 
1441
     */
 
1442
    private void fixActiveNodes(Cell cell)
 
1443
    {
 
1444
        if (unifyActive) return; // no need to fix active
 
1445
        if (ignoreActiveSelectWell) return;
 
1446
        // if unifyActive is set, then Electric tech must only have one active
 
1447
        // Otherwise, imported GDS may only have one active, but Electric has two, so
 
1448
        // we need to fix that here.
 
1449
 
 
1450
        PrimitiveNode pDiffNode = null, nDiffNode = null;
 
1451
        for (Iterator<PrimitiveNode> it = cell.getTechnology().getNodes(); it.hasNext(); )
 
1452
        {
 
1453
            PrimitiveNode pn = it.next();
 
1454
            if (pn.getFunction() == PrimitiveNode.Function.NODE) {
 
1455
                Layer layer = pn.getLayerIterator().next();
 
1456
                if (layer.getFunction() == Layer.Function.DIFFN)
 
1457
                    nDiffNode = pn;
 
1458
                if (layer.getFunction() == Layer.Function.DIFFP)
 
1459
                    pDiffNode = pn;
 
1460
            }
 
1461
        }
 
1462
 
 
1463
        // first get all select layers
 
1464
        PolyMerge merge = new PolyMerge();
 
1465
        for (Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) {
 
1466
            NodeInst ni = it.next();
 
1467
            if (ni.isCellInstance()) continue;
 
1468
            Poly [] polys = tech.getShapeOfNode(ni);
 
1469
            for(int j=0; j<polys.length; j++)
 
1470
            {
 
1471
                Poly poly = polys[j];
 
1472
 
 
1473
                // get the layer for the geometry
 
1474
                Layer layer = poly.getLayer();
 
1475
                if (layer == null) continue;
 
1476
 
 
1477
                // make sure the geometric database is made up of proper layers
 
1478
                layer = geometricLayer(layer);
 
1479
                if (layer.getFunction() != Layer.Function.IMPLANTN && layer.getFunction() != Layer.Function.IMPLANTP) continue;
 
1480
 
 
1481
                merge.add(layer, poly);
 
1482
            }
 
1483
        }
 
1484
        // now fix any active nodes
 
1485
        for (Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) {
 
1486
            NodeInst ni = it.next();
 
1487
            if (ni.isCellInstance()) continue;
 
1488
            PrimitiveNode pn = (PrimitiveNode)ni.getProto();
 
1489
            if (pn.getFunction() == PrimitiveNode.Function.NODE) {
 
1490
                Layer nodeLayer = pn.getLayerIterator().next();
 
1491
                PrimitiveNode newType = null;
 
1492
 
 
1493
                if (nodeLayer.getFunction() == Layer.Function.DIFFN) {
 
1494
                    // make sure n-diffusion is in n-select
 
1495
                    Poly [] polys = tech.getShapeOfNode(ni);
 
1496
                    for (Poly poly : polys) {
 
1497
                        if (merge.contains(pSelectLayer, poly)) {
 
1498
                            // switch it pactive
 
1499
                            newType = pDiffNode;
 
1500
                            break;
 
1501
                        }
 
1502
                    }
 
1503
                }
 
1504
                if (nodeLayer.getFunction() == Layer.Function.DIFFP) {
 
1505
                    // make sure p-diffusion is in p-select
 
1506
                    Poly [] polys = tech.getShapeOfNode(ni);
 
1507
                    for (Poly poly : polys) {
 
1508
                        if (merge.contains(nSelectLayer, poly)) {
 
1509
                            // switch it nactive
 
1510
                            newType = nDiffNode;
 
1511
                            break;
 
1512
                        }
 
1513
                    }
 
1514
                }
 
1515
 
 
1516
                if (newType == null) continue;
 
1517
                NodeInst newNi = NodeInst.newInstance(newType, ni.getAnchorCenter(), ni.getXSize(), ni.getYSize(), cell);
 
1518
                if (ni.getTrace() != null && ni.getTrace().length > 0)
 
1519
                {
 
1520
                    EPoint [] origPoints = ni.getTrace();
 
1521
                    Point2D [] points = new Point2D[origPoints.length];
 
1522
                    // for some reason getTrace returns points relative to center, but setTrace expects absolute coords
 
1523
                    for (int i=0; i<origPoints.length; i++) {
 
1524
                        points[i] = new Point2D.Double(origPoints[i].getX()+ni.getAnchorCenterX(), origPoints[i].getY()+ni.getAnchorCenterY());
 
1525
                    }
 
1526
                    newNi.setTrace(points);
 
1527
                }
 
1528
                ni.kill();
 
1529
            }
 
1530
        }
 
1531
    }
 
1532
 
 
1533
    /**
1154
1534
         * Method to figure out which ArcProto to use for a polygon on a layer.
1155
1535
         * In the case of Active layers, it examines the well and select layers to figure out
1156
1536
         * which arctive arc to use.
1161
1541
         */
1162
1542
        private ArcProto findArcProtoForPoly(Layer layer, PolyBase poly, PolyMerge originalMerge)
1163
1543
        {
 
1544
/*
1164
1545
                Layer.Function fun = layer.getFunction();
1165
1546
                if (fun.isPoly() || fun.isMetal()) return arcsForLayer.get(layer);
1166
1547
                if (!fun.isDiff()) return null;
1209
1590
                        if (ap.getFunction() == neededFunction) return ap;
1210
1591
                }
1211
1592
                return null;
 
1593
*/
 
1594
 
 
1595
        Layer.Function fun = layer.getFunction();
 
1596
        if (fun.isPoly() || fun.isMetal()) return arcsForLayer.get(layer);
 
1597
        if (!fun.isDiff()) return null;
 
1598
 
 
1599
        ArrayList<Layer> requiredLayers = new ArrayList<Layer>();
 
1600
        ArrayList<Layer> requiredAbsentLayers = new ArrayList<Layer>();
 
1601
 
 
1602
        // must further differentiate the active arcs...find implants
 
1603
        Layer wellP = null, wellN = null, selectP = null, selectN = null;
 
1604
        for(Layer l : originalMerge.getKeySet())
 
1605
        {
 
1606
            if (l.getFunction() == Layer.Function.WELLP) wellP = l;
 
1607
            if (l.getFunction() == Layer.Function.WELLN) wellN = l;
 
1608
        }
 
1609
 
 
1610
        // Active must have P-Select or N-Select
 
1611
        if (pSelectLayer != null && originalMerge.intersects(pSelectLayer, poly)) {
 
1612
            if (unifyActive)
 
1613
                requiredLayers.add(activeLayer);
 
1614
            else
 
1615
                requiredLayers.add(realPActiveLayer);
 
1616
            requiredLayers.add(pSelectLayer);
 
1617
        }
 
1618
        if (nSelectLayer != null && originalMerge.intersects(nSelectLayer, poly)) {
 
1619
            if (unifyActive)
 
1620
                requiredLayers.add(activeLayer);
 
1621
            else
 
1622
                requiredLayers.add(realNActiveLayer);
 
1623
            requiredLayers.add(nSelectLayer);
 
1624
        }
 
1625
 
 
1626
        // Active could either be an Active arc or a Well arc, depending on well type
 
1627
        if (wellN == null || !originalMerge.intersects(wellN, poly))
 
1628
            requiredAbsentLayers.add(wellN);
 
1629
        if (wellN != null && originalMerge.intersects(wellN, poly))
 
1630
            requiredLayers.add(wellN);
 
1631
 
 
1632
        // Active could either be an Active arc or a Well arc, depending on well type
 
1633
        if (wellP == null || !originalMerge.intersects(wellP, poly))
 
1634
            requiredAbsentLayers.add(wellP);
 
1635
        if (wellP != null && originalMerge.intersects(wellP, poly))
 
1636
            requiredLayers.add(wellP);
 
1637
 
 
1638
        // now find the arc with the desired function
 
1639
        for(Iterator<ArcProto> aIt = tech.getArcs(); aIt.hasNext(); )
 
1640
        {
 
1641
            ArcProto ap = aIt.next();
 
1642
            List<Layer> apLayers = new ArrayList<Layer>();
 
1643
            for (Iterator<Layer> layit = ap.getLayerIterator(); layit.hasNext(); )
 
1644
                apLayers.add(layit.next());
 
1645
            // make sure required layers exist
 
1646
            boolean failed = false;
 
1647
            for (Layer l : requiredLayers) {
 
1648
                if (!apLayers.contains(l)) { failed = true; break; }
 
1649
            }
 
1650
            if (failed) continue;
 
1651
            for (Layer l : requiredAbsentLayers) {
 
1652
                if (apLayers.contains(l)) { failed = true; break; }
 
1653
            }
 
1654
            if (failed) continue;
 
1655
            return ap;
 
1656
        }
 
1657
        return null;
1212
1658
        }
1213
1659
 
1214
1660
        /**
1332
1778
                        endUnscaled = new EPoint(x / SCALEFACTOR, y / SCALEFACTOR);
1333
1779
                }
1334
1780
 
1335
 
                public String toString()
 
1781
        Rectangle2D getBounds() {
 
1782
            if (start.getX() == end.getX()) {
 
1783
                // vertical
 
1784
                double minX = (start.getX() < end.getX() ? start.getX() : end.getX()) - width/2.0;
 
1785
                double minY = start.getY() < end.getY() ? start.getY() : end.getY();
 
1786
                double maxY = start.getY() > end.getY() ? start.getY() : end.getY();
 
1787
                return new Rectangle2D.Double(minX, minY, width, maxY-minY);
 
1788
            }
 
1789
            if (start.getY() == end.getY()) {
 
1790
                // horizontal
 
1791
                double minY = (start.getY() < end.getY() ? start.getY() : end.getY()) - width/2.0;
 
1792
                double minX = start.getX() < end.getX() ? start.getX() : end.getX();
 
1793
                double maxX = start.getX() > end.getX() ? start.getX() : end.getX();
 
1794
                return new Rectangle2D.Double(minX, minY, maxX-minX, width);
 
1795
            }
 
1796
            return null; // non-manhatten
 
1797
        }
 
1798
 
 
1799
        public String toString()
1336
1800
                {
1337
1801
                        return "CENTERLINE from (" + TextUtils.formatDouble(start.getX()/SCALEFACTOR) + "," +
1338
1802
                                TextUtils.formatDouble(start.getY()/SCALEFACTOR) + ") to (" +
1349
1813
         * @param loc1 it's location (values returned through this object!)
1350
1814
         * @param layer the layer associated with the Centerline.
1351
1815
         * @param ap the type of arc to create.
1352
 
         * @param startSide true to
 
1816
         * @param startSide true to consider the "start" end of the Centerline, false for the "end" end.
1353
1817
         * @param newCell the Cell in which to find ports.
1354
1818
         * @return the PortInst on the Centerline.
1355
1819
         */
1356
 
        private PortInst locatePortOnCenterline(Centerline cl, Point2D loc1, Layer layer, ArcProto ap, boolean startSide, Cell newCell)
 
1820
        private PortInst locatePortOnCenterline(Centerline cl, Point2D loc1, Layer layer,
 
1821
                ArcProto ap, boolean startSide, Cell newCell)
1357
1822
        {
1358
1823
                PortInst piRet = null;
1359
1824
                boolean isHub = cl.endHub;
 
1825
                gridAlignCenterline(cl, startSide);
1360
1826
                EPoint startPoint = cl.endUnscaled;
1361
1827
                if (startSide)
1362
1828
                {
1426
1892
                        int ang = GenMath.figureAngle(cl.start, cl.end);
1427
1893
                        double xOff = GenMath.cos(ang) * cl.width/2;
1428
1894
                        double yOff = GenMath.sin(ang) * cl.width/2;
 
1895
//                      double aliX = 1, aliY = 1;
 
1896
//                      if (alignment != null)
 
1897
//                      {
 
1898
//                              if (alignment.getWidth() > 0) aliX = scaleUp(alignment.getWidth());
 
1899
//                              if (alignment.getHeight() > 0) aliY = scaleUp(alignment.getHeight());
 
1900
//                      }
1429
1901
                        if (startSide)
1430
1902
                        {
1431
1903
                                if (!isHub && cl.start.distance(cl.end) > cl.width)
1432
 
                                        cl.setStart(cl.start.getX() + xOff, cl.start.getY() + yOff);
1433
 
                                NodeInst ni = wantNodeAt(cl.startUnscaled, pin, cl.width / SCALEFACTOR, newCell);
 
1904
                                {
 
1905
                                        //xOff = Math.floor(xOff / aliX) * aliX;
 
1906
                                        //yOff = Math.floor(yOff / aliY) * aliY;
 
1907
                    // if shortening to allow ends extend will put the arc offgrid, do not do it
 
1908
                    if (xOff > 0 && (xOff % scaleUp(alignment.getWidth())) != 0) xOff = 0;
 
1909
                    if (yOff > 0 && (yOff % scaleUp(alignment.getHeight())) != 0) yOff = 0;
 
1910
                    cl.setStart(cl.start.getX() + xOff, cl.start.getY() + yOff);
 
1911
                                }
 
1912
                double size = pin.getFactoryDefaultLambdaBaseWidth();
 
1913
                NodeInst ni = wantNodeAt(cl.startUnscaled, pin, size, newCell);
1434
1914
                                loc1.setLocation(cl.startUnscaled.getX(), cl.startUnscaled.getY());
1435
1915
                                piRet = ni.getOnlyPortInst();
1436
1916
                        } else
1437
1917
                        {
1438
1918
                                if (!isHub && cl.start.distance(cl.end) > cl.width)
 
1919
                                {
 
1920
                                        //xOff = Math.ceil(xOff / aliX) * aliX;
 
1921
                                        //yOff = Math.ceil(yOff / aliY) * aliY;
 
1922
                    // if shortening to allow ends extend will put the arc offgrid, do not do it
 
1923
                    if (xOff > 0 && (xOff % scaleUp(alignment.getWidth())) != 0) xOff = 0;
 
1924
                    if (yOff > 0 && (yOff % scaleUp(alignment.getHeight())) != 0) yOff = 0;
1439
1925
                                        cl.setEnd(cl.end.getX() - xOff, cl.end.getY() - yOff);
 
1926
                                }
1440
1927
                                NodeInst ni = wantNodeAt(cl.endUnscaled, pin, cl.width / SCALEFACTOR, newCell);
1441
1928
                                loc1.setLocation(cl.endUnscaled.getX(), cl.endUnscaled.getY());
1442
1929
                                piRet = ni.getOnlyPortInst();
1445
1932
                return piRet;
1446
1933
        }
1447
1934
 
 
1935
        private void gridAlignCenterline(Centerline cl, boolean startSide)
 
1936
        {
 
1937
//              // grid align the edges
 
1938
//              double halfWidth = cl.width / 2;
 
1939
//halfWidth = 0;                // is this right?
 
1940
//              if (cl.start.getX() == cl.end.getX())
 
1941
//              {
 
1942
//                      // vertical arc: make sure ends align in Y
 
1943
//                      int ali = (int)Math.round(alignment.getHeight() * SCALEFACTOR);
 
1944
//                      if (ali == 0) return;
 
1945
//                      if (startSide)
 
1946
//                      {
 
1947
//                              // adjust the "start" end
 
1948
//                              if (cl.start.getY() < cl.end.getY())
 
1949
//                              {
 
1950
//                                      // start on left: compute edge below it
 
1951
//                                      double edge = cl.start.getY() - halfWidth;
 
1952
//                                      cl.setStart(cl.start.getX(), Math.ceil(edge / ali) * ali + halfWidth);
 
1953
//                              } else
 
1954
//                              {
 
1955
//                                      // start on right: compute edge above it
 
1956
//                                      double edge = cl.start.getY() + halfWidth;
 
1957
//                                      cl.setStart(cl.start.getX(), Math.floor(edge / ali) * ali - halfWidth);
 
1958
//                              }
 
1959
//                      } else
 
1960
//                      {
 
1961
//                              // adjust the "end" end
 
1962
//                              if (cl.end.getY() < cl.start.getY())
 
1963
//                              {
 
1964
//                                      // end on left: compute edge below it
 
1965
//                                      double edge = cl.end.getY() - halfWidth;
 
1966
//                                      cl.setEnd(cl.end.getX(), Math.ceil(edge / ali) * ali + halfWidth);
 
1967
//                              } else
 
1968
//                              {
 
1969
//                                      // end on right: compute edge above it
 
1970
//                                      double edge = cl.end.getY() + halfWidth;
 
1971
//                                      cl.setEnd(cl.end.getX(), Math.floor(edge / ali) * ali - halfWidth);
 
1972
//                              }
 
1973
//                      }
 
1974
//              } else if (cl.start.getY() == cl.end.getY())
 
1975
//              {
 
1976
//                      // horizontal arc: make sure ends align in X
 
1977
//                      int ali = (int)Math.round(alignment.getWidth() * SCALEFACTOR);
 
1978
//                      if (ali == 0) return;
 
1979
//                      if (startSide)
 
1980
//                      {
 
1981
//                              // adjust the "start" end
 
1982
//                              if (cl.start.getX() < cl.end.getX())
 
1983
//                              {
 
1984
//                                      // start on left: compute edge below it
 
1985
//                                      double edge = cl.start.getX() - halfWidth;
 
1986
//                                      cl.setStart(Math.ceil(edge / ali) * ali + halfWidth, cl.start.getY());
 
1987
//                              } else
 
1988
//                              {
 
1989
//                                      // start on right: compute edge above it
 
1990
//                                      double edge = cl.start.getX() + halfWidth;
 
1991
//                                      cl.setStart(Math.floor(edge / ali) * ali - halfWidth, cl.start.getY());
 
1992
//                              }
 
1993
//                      } else
 
1994
//                      {
 
1995
//                              // adjust the "end" end
 
1996
//                              if (cl.end.getX() < cl.start.getX())
 
1997
//                              {
 
1998
//                                      // end on left: compute edge below it
 
1999
//                                      double edge = cl.end.getX() - halfWidth;
 
2000
//                                      cl.setEnd(Math.ceil(edge / ali) * ali + halfWidth, cl.end.getY());
 
2001
//                              } else
 
2002
//                              {
 
2003
//                                      // end on right: compute edge above it
 
2004
//                                      double edge = cl.end.getX() + halfWidth;
 
2005
//                                      cl.setEnd(Math.floor(edge / ali) * ali - halfWidth, cl.end.getY());
 
2006
//                              }
 
2007
//                      }
 
2008
//              }
 
2009
        }
 
2010
 
1448
2011
        private List<PortInst> findPortInstsTouchingPoint(Point2D pt, Layer layer, Cell newCell, ArcProto ap)
1449
2012
        {
1450
2013
                List<PortInst> touchingNodes = new ArrayList<PortInst>();
1477
2040
                        }
1478
2041
 
1479
2042
                        // for pins, must be centered over the desired point
1480
 
                        if (ni.getFunction() == PrimitiveNode.Function.PIN)
 
2043
                        if (ni.getFunction().isPin())
1481
2044
                        {
1482
2045
                                if (!ni.getOnlyPortInst().getPortProto().connectsTo(ap)) continue;
1483
2046
                                if (ni.getAnchorCenter().equals(pt))
1534
2097
        private PortInst makePort(Cell cell, Layer layer, Point2D pt)
1535
2098
        {
1536
2099
                Rectangle2D checkBounds = new Rectangle2D.Double(pt.getX(), pt.getY(), 0, 0);
1537
 
                for(Iterator<RTBounds> it = cell.searchIterator(checkBounds); it.hasNext(); )
 
2100
        // first look for port on primitive geometry in cell
 
2101
        for (Iterator<RTBounds> it = cell.searchIterator(checkBounds); it.hasNext();)
 
2102
        {
 
2103
            RTBounds geom = it.next();
 
2104
            if (!(geom instanceof NodeInst)) continue;
 
2105
            NodeInst subNi = (NodeInst)geom;
 
2106
            if (subNi.isCellInstance()) continue;
 
2107
 
 
2108
            Technology tech = subNi.getProto().getTechnology();
 
2109
            AffineTransform trans = subNi.rotateOut();
 
2110
            Poly [] polyList = tech.getShapeOfNode(subNi, true, true, null);
 
2111
            for(int i=0; i<polyList.length; i++)
 
2112
            {
 
2113
                Poly poly = polyList[i];
 
2114
                if (poly.getPort() == null) continue;
 
2115
                if (geometricLayer(poly.getLayer()) != layer) continue;
 
2116
                poly.transform(trans);
 
2117
                if (poly.contains(pt))
 
2118
                {
 
2119
                    // found polygon that touches the point.  Make the export
 
2120
                    PortInst foundPi = findPortInstClosestToPoly(subNi, (PrimitivePort)poly.getPort(), pt);
 
2121
                    if (foundPi != null) return foundPi;
 
2122
                }
 
2123
            }
 
2124
        }
 
2125
        // nothing found, now push down into subcells
 
2126
        for(Iterator<RTBounds> it = cell.searchIterator(checkBounds); it.hasNext(); )
1538
2127
                {
1539
2128
                        RTBounds geom = it.next();
1540
2129
                        if (!(geom instanceof NodeInst)) continue;
1582
2171
                                                }
1583
2172
                                                boolean genFakeName = (exportName == null);
1584
2173
                                                if (genFakeName) exportName = "E";
1585
 
                                                exportName = ElectricObject.uniqueObjectName(exportName, subCell, PortProto.class, true);
 
2174
                                                exportName = ElectricObject.uniqueObjectName(exportName, subCell, PortProto.class, true, true);
1586
2175
                                                Export e = Export.newInstance(subCell, pi, exportName);
1587
 
                                                if (genFakeName) generatedExports.add(e);
 
2176
                                                if (genFakeName)
 
2177
                            generatedExports.add(e);
1588
2178
                                                foundPi = subNi.findPortInstFromProto(e);
1589
2179
                                                return foundPi;
1590
2180
                                        }
1591
2181
                                }
1592
 
                        } else
1593
 
                        {
1594
 
                                Technology tech = subNi.getProto().getTechnology();
1595
 
                                AffineTransform trans = subNi.rotateOut();
1596
 
                                Poly [] polyList = tech.getShapeOfNode(subNi, true, true, null);
1597
 
                                for(int i=0; i<polyList.length; i++)
1598
 
                                {
1599
 
                                        Poly poly = polyList[i];
1600
 
                                        if (poly.getPort() == null) continue;
1601
 
                                        if (geometricLayer(poly.getLayer()) != layer) continue;
1602
 
                                        poly.transform(trans);
1603
 
                                        if (poly.contains(pt))
1604
 
                                        {
1605
 
                                                // found polygon that touches the point.  Make the export
1606
 
                                                foundPi = findPortInstClosestToPoly(subNi, (PrimitivePort)poly.getPort(), pt);
1607
 
                                                return foundPi;
1608
 
                                        }
1609
 
                                }
1610
2182
                        }
1611
2183
                }
1612
2184
                return null;
1708
2280
                                        if (layerAtPoint) layersPresent.add(geometricLayer(l));
1709
2281
                                }
1710
2282
                                boolean ignorePWell = false, ignoreNWell = false;
1711
 
                                if (pWellProcess)
 
2283
                                if (pSubstrateProcess)
1712
2284
                                {
1713
 
                                        // P-Well process (P-well is presumed where there is no N-Well)
 
2285
                                        // P-substrate process (P-well is presumed where there is no N-Well)
1714
2286
                                        boolean foundNWell = false;
1715
2287
                                        for(Layer l : layersPresent)
1716
2288
                                        {
1718
2290
                                        }
1719
2291
                                        if (!foundNWell) ignorePWell = true;
1720
2292
                                }
1721
 
                                if (nWellProcess)
 
2293
                                if (nSubstrateProcess)
1722
2294
                                {
1723
 
                                        // N-Well process (N-well is presumed where there is no P-Well)
 
2295
                                        // N-Substrate process (N-well is presumed where there is no P-Well)
1724
2296
                                        boolean foundPWell = false;
1725
2297
                                        for(Layer l : layersPresent)
1726
2298
                                        {
1774
2346
                                        double cutLimit = Math.ceil(Math.max(pv.multicutSep1D, pv.multicutSep2D) +
1775
2347
                                                Math.max(pv.multicutSizeX, pv.multicutSizeY)) * SCALEFACTOR;
1776
2348
                                        boolean foundMore = true;
1777
 
                                        while (foundMore)
 
2349
                    double xspacing = 0, yspacing = 0;
 
2350
                    while (foundMore)
1778
2351
                                        {
1779
2352
                                                foundMore = false;
1780
 
                                                Rectangle2D searchArea = new Rectangle2D.Double(multiCutBounds.getMinX()-cutLimit, multiCutBounds.getMinY()-cutLimit,
 
2353
                        Rectangle2D searchArea = new Rectangle2D.Double(multiCutBounds.getMinX()-cutLimit, multiCutBounds.getMinY()-cutLimit,
1781
2354
                                                        multiCutBounds.getWidth() + cutLimit*2, multiCutBounds.getHeight() + cutLimit*2);
1782
 
                                                for(RTNode.Search sea = new RTNode.Search(searchArea, cInfo.getRTree(), true); sea.hasNext(); )
 
2355
/*
 
2356
                        Rectangle2D searchArea2 = new Rectangle2D.Double(searchArea.getMinX()/SCALEFACTOR, searchArea.getMinY()/SCALEFACTOR,
 
2357
                                searchArea.getWidth()/SCALEFACTOR, searchArea.getHeight()/SCALEFACTOR);
 
2358
                        System.out.println("Checking search area "+searchArea2);
 
2359
*/
 
2360
                        for(RTNode.Search sea = new RTNode.Search(searchArea, cInfo.getRTree(), true); sea.hasNext(); )
1783
2361
                                                {
1784
2362
                                                        CutBound cBound = (CutBound)sea.next();
1785
2363
                                                        if (cutsInArea.contains(cBound.cut)) continue;
1786
2364
                                                        Rectangle2D bound = cBound.getBounds();
1787
2365
                                                        if (!searchArea.contains(bound.getCenterX(), bound.getCenterY())) continue;
1788
2366
 
1789
 
                                                        double lX = Math.min(multiCutBounds.getMinX(), bound.getMinX());
 
2367
                            // use only cuts at a spacing that matches (a multiple of) the nearest contact spacing
 
2368
                            double distX = cut.getCenterX() - bound.getCenterX();
 
2369
                            double distY = cut.getCenterY() - bound.getCenterY();
 
2370
 
 
2371
                            if (xspacing == 0) xspacing = distX;
 
2372
                            else if (distX % xspacing != 0) continue;
 
2373
                            if (yspacing == 0) yspacing = distY;
 
2374
                            else if (distY % yspacing != 0) continue;
 
2375
 
 
2376
/*
 
2377
                            // make sure cuts are in a contiguous array at the initial spacing
 
2378
                            if (furthestX == 0) furthestX = distX;
 
2379
                            if (furthestY == 0) furthestY = distY;
 
2380
                            if (distX > furthestX) {
 
2381
                                if (distX == furthestX + xspacing)
 
2382
                                    furthestX = distX; // this is the next one on grid
 
2383
                                else
 
2384
                                    continue; // on grid, but not contiguous
 
2385
                            }
 
2386
                            if (distY > furthestY) {
 
2387
                                if (distY == furthestY + yspacing)
 
2388
                                    furthestY = distY; // this is the next one on grid
 
2389
                                else
 
2390
                                    continue; // on grid, but not contiguous
 
2391
                            }
 
2392
 
 
2393
                            // record height of first column
 
2394
                            if (maxColumnHeight == 0 && distX != 0) {
 
2395
                                // first contact of the second column
 
2396
                                maxColumnHeight = furthestY;
 
2397
                            }
 
2398
*/
 
2399
 
 
2400
                            double lX = Math.min(multiCutBounds.getMinX(), bound.getMinX());
1790
2401
                                                        double hX = Math.max(multiCutBounds.getMaxX(), bound.getMaxX());
1791
2402
                                                        double lY = Math.min(multiCutBounds.getMinY(), bound.getMinY());
1792
2403
                                                        double hY = Math.max(multiCutBounds.getMaxY(), bound.getMaxY());
1812
2423
                                                }
1813
2424
                                        }
1814
2425
 
1815
 
                                        if (DEBUGCONTACTS) System.out.println("   FOUND LARGE CONTACT WITH "+cutsInArea.size()+" CUTS, IN "+
 
2426
                    // reduce via array to rectangle
 
2427
                    if (xspacing == 0) xspacing = cutLimit;
 
2428
                    if (yspacing == 0) yspacing = cutLimit;
 
2429
                    Set<PolyBase> rectVias = getLargestRectangleOfVias(cutsInArea, cut, xspacing, yspacing, multiCutBounds);
 
2430
                    cutsInArea.clear();
 
2431
                    cutsInArea.addAll(rectVias);
 
2432
                    multiCutBounds = (Rectangle2D)cutBox.clone();
 
2433
                    for (PolyBase via : rectVias) {
 
2434
                        Rectangle2D bound = via.getBounds2D();
 
2435
                        double lX = Math.min(multiCutBounds.getMinX(), bound.getMinX());
 
2436
                        double hX = Math.max(multiCutBounds.getMaxX(), bound.getMaxX());
 
2437
                        double lY = Math.min(multiCutBounds.getMinY(), bound.getMinY());
 
2438
                        double hY = Math.max(multiCutBounds.getMaxY(), bound.getMaxY());
 
2439
                        multiCutBounds = new Rectangle2D.Double(lX, lY, hX-lX, hY-lY);
 
2440
                    }
 
2441
 
 
2442
                    if (DEBUGCONTACTS) System.out.println("   FOUND LARGE CONTACT WITH "+cutsInArea.size()+" CUTS, IN "+
1816
2443
                                                TextUtils.formatDouble(multiCutBounds.getMinX()/SCALEFACTOR)+"<=X<="+TextUtils.formatDouble(multiCutBounds.getMaxX()/SCALEFACTOR)+" AND "+
1817
2444
                                                TextUtils.formatDouble(multiCutBounds.getMinY()/SCALEFACTOR)+"<=Y<="+TextUtils.formatDouble(multiCutBounds.getMaxY()/SCALEFACTOR));
1818
2445
 
1938
2565
                        root = RTNode.linkGeom(null, root, ni);
1939
2566
 
1940
2567
                // recursively scan the R-Tree, merging geometry on created nodes and removing them from the main merge
1941
 
                PolyMerge subtractMerge = new PolyMerge();
1942
 
                extractContactNodes(root, merge, subtractMerge, 0, contactNodes.size());
1943
 
                merge.subtractMerge(subtractMerge);
1944
 
                return true;
 
2568
        if (!Extract.isUsePureLayerNodes())
 
2569
        {
 
2570
            PolyMerge subtractMerge = new PolyMerge();
 
2571
                    extractContactNodes(root, merge, subtractMerge, 0, contactNodes.size());
 
2572
            merge.subtractMerge(subtractMerge);
 
2573
        }
 
2574
        return true;
1945
2575
        }
1946
2576
 
1947
 
        /**
 
2577
    /**
 
2578
     * Multi-cut vias must be rectangular - get the largest rectangle that fits in the set of vias,
 
2579
     * that includes the initial via
 
2580
     * @param vias set of vias
 
2581
     * @param initialVia the initial via
 
2582
     * @param xspacing x spacing between vias
 
2583
     * @param yspacing y spacing between vias
 
2584
     * @param bounds bounds of all the vias
 
2585
     * @return the subset of vias that form a contiguous rectangle, containing the initial via
 
2586
     */
 
2587
    private Set<PolyBase> getLargestRectangleOfVias(Set<PolyBase> vias, PolyBase initialVia, double xspacing, double yspacing, Rectangle2D bounds)
 
2588
    {
 
2589
        xspacing = Math.abs(xspacing);
 
2590
        yspacing = Math.abs(yspacing);
 
2591
        if (xspacing == 0) xspacing = SCALEFACTOR;
 
2592
        if (yspacing == 0) yspacing = SCALEFACTOR;
 
2593
        int numViasWide = (int)Math.ceil(bounds.getWidth() / xspacing);
 
2594
        int numViasHigh = (int)Math.ceil(bounds.getHeight() / yspacing);
 
2595
        PolyBase [][] viaMap = new PolyBase[numViasWide][numViasHigh];
 
2596
        int nomX = 0, nomY = 0;
 
2597
 
 
2598
        for (int x=0; x<numViasWide; x++) {
 
2599
            Arrays.fill(viaMap[x], null);
 
2600
        }
 
2601
 
 
2602
        // populate map
 
2603
        for (PolyBase via : vias) {
 
2604
            int x = (int)((via.getCenterX() - bounds.getMinX()) / xspacing);
 
2605
            int y = (int)((via.getCenterY() - bounds.getMinY()) / yspacing);
 
2606
            viaMap[x][y] = via;
 
2607
            if (via == initialVia) {
 
2608
                nomX = x; nomY = y;
 
2609
            }
 
2610
        }
 
2611
        // find maxY and minY from initial via
 
2612
        int maxY = nomY, minY = nomY;
 
2613
        boolean initial = true;
 
2614
        for (int x=0; x<numViasWide; x++) {
 
2615
            if (viaMap[x][nomY] == null) continue; // skip this column, will be taken into account in X max/min
 
2616
            // max
 
2617
            int colMaxY = nomY;
 
2618
            for (int y=nomY; y<numViasHigh; y++) {
 
2619
                if (viaMap[x][y] == null) break;
 
2620
                colMaxY = y;
 
2621
            }
 
2622
            if (initial) maxY = colMaxY; // initial column
 
2623
            else if (colMaxY < maxY) maxY = colMaxY;
 
2624
            // min
 
2625
            int colMinY = nomY;
 
2626
            for (int y=nomY; y>=0; y--) {
 
2627
                if (viaMap[x][y] == null) break;
 
2628
                colMinY = y;
 
2629
            }
 
2630
            if (initial) minY = colMinY; // initial column
 
2631
            else if (colMinY > minY) minY = colMinY;
 
2632
            initial = false;
 
2633
        }
 
2634
 
 
2635
        // find maxX and minX from initial via
 
2636
        int maxX = nomX, minX = nomX;
 
2637
        initial = true;
 
2638
        for (int y=0; y<numViasHigh; y++) {
 
2639
            if (viaMap[nomX][y] == null) continue; // skip this row, will be taken into account in Y max/min
 
2640
            // max
 
2641
            int colMaxX = nomX;
 
2642
            for (int x=nomX; x<numViasWide; x++) {
 
2643
                if (viaMap[x][y] == null) break;
 
2644
                colMaxX = x;
 
2645
            }
 
2646
            if (initial) maxX = colMaxX; // initial row
 
2647
            else if (colMaxX < maxX) maxX = colMaxX;
 
2648
            // min
 
2649
            int colMinX = nomX;
 
2650
            for (int x=nomX; x>=0; x--) {
 
2651
                if (viaMap[x][y] == null) break;
 
2652
                colMinX = x;
 
2653
            }
 
2654
            if (initial) minX = colMinX; // initial row
 
2655
            else if (colMinX > minX) minX = colMinX;
 
2656
            initial = false;
 
2657
        }
 
2658
 
 
2659
        // get rectangle
 
2660
        Set<PolyBase> rectVias = new HashSet<PolyBase>();
 
2661
        for (int x=minX; x<=maxX; x++) {
 
2662
            for (int y=minY; y<=maxY; y++) {
 
2663
                rectVias.add(viaMap[x][y]);
 
2664
            }
 
2665
        }
 
2666
        return rectVias;
 
2667
    }
 
2668
 
 
2669
    /**
1948
2670
         * Method to create the biggest contact node in a given location.
1949
2671
         * @param pNp the type of node to create.
1950
2672
         * @param cutVariation the contact cut spacing rule.
1967
2689
//boolean debug = pNp.getName().equals("Z-Metal-1-N-Diff-Con");
1968
2690
//if (debug) System.out.println("LOOKING FOR LARGEST CUT...");
1969
2691
                Orientation orient = Orientation.fromAngle(rot);
 
2692
                if (alignment != null)
 
2693
                {
 
2694
                        if (alignment.getWidth() > 0)
 
2695
                        {
 
2696
                                double scale = scaleUp(alignment.getWidth());
 
2697
                                x = Math.round(x / scale) * scale;
 
2698
                        }
 
2699
                        if (alignment.getHeight() > 0)
 
2700
                        {
 
2701
                                double scale = scaleUp(alignment.getHeight());
 
2702
                                y = Math.round(y / scale) * scale;
 
2703
                        }
 
2704
                }
1970
2705
                EPoint ctr = new EPoint(x / SCALEFACTOR, y / SCALEFACTOR);
1971
2706
 
1972
2707
                // first find an X size that does not fit
2043
2778
                        } else { sX += lowXInc;   sY += lowYInc; }
2044
2779
                        if (error != null) return error.getLayer();
2045
2780
                }
 
2781
                if (alignment != null)
 
2782
                {
 
2783
                        if (alignment.getWidth() > 0)
 
2784
                        {
 
2785
                                double scale = scaleUp(alignment.getWidth()) * 2;
 
2786
                                sX = Math.floor(sX / scale) * scale;
 
2787
                        }
 
2788
                        if (alignment.getHeight() > 0)
 
2789
                        {
 
2790
                                double scale = scaleUp(alignment.getHeight()) * 2;
 
2791
                                sY = Math.floor(sY / scale) * scale;
 
2792
                        }
 
2793
                }
2046
2794
                realizeNode(pNp, cutVariation, x, y, sX, sY, rot, null, merge, newCell, contactNodes);
2047
2795
                return null;
2048
2796
        }
2065
2813
                Poly biggestPoly = null;
2066
2814
                List<PolyBase> cutsFound = null;
2067
2815
                if (!approximateCuts) cutsFound = new ArrayList<PolyBase>();
2068
 
                for(Poly poly : polys)
 
2816
        boolean hasPplus = false;
 
2817
        boolean hasNplus = false;
 
2818
        boolean hasActive = false;
 
2819
        for(Poly poly : polys)
2069
2820
                {
2070
2821
                        Layer l = poly.getLayer();
2071
2822
                        if (l == null) continue;
2072
2823
                        l = geometricLayer(l);
2073
 
                        if (l.getFunction().isSubstrate()) continue;
2074
 
                        poly.setLayer(l);
 
2824
 
 
2825
            // ignore well layers if the process doesn't have them (in this case they are substrate layers)
 
2826
            if (l.getFunction() == Layer.Function.WELLP && pSubstrateProcess) continue;
 
2827
            if (l.getFunction() == Layer.Function.WELLN && nSubstrateProcess) continue;
 
2828
 
 
2829
            if (l.isDiffusionLayer()) hasActive = true;
 
2830
            if (l.getFunction() == Layer.Function.IMPLANTN) hasNplus = true;
 
2831
            if (l.getFunction() == Layer.Function.IMPLANTP) hasPplus = true;
 
2832
 
 
2833
            poly.setLayer(l);
2075
2834
                        poly.transform(trans);
2076
2835
                        if (l.getFunction().isContact())
2077
2836
                        {
2091
2850
                                return poly;
2092
2851
                }
2093
2852
 
2094
 
                if (!approximateCuts && cutsInArea != null)
 
2853
        // special case: some substrate contacts in some techs do not have the substrate layer (since often the original geom
 
2854
        // also does not have the substrate layer). To prevent these from being used as regular contacts,
 
2855
        // do an extra check here
 
2856
        PrimitiveNode pn = (PrimitiveNode)ni.getProto();
 
2857
        PolyBase testPoly = new PolyBase(new Point2D[]{
 
2858
                new Point2D.Double(scaleUp(ni.getAnchorCenterX())-1, scaleUp(ni.getAnchorCenterY())-1),
 
2859
                new Point2D.Double(scaleUp(ni.getAnchorCenterX())-1, scaleUp(ni.getAnchorCenterY())+1),
 
2860
                new Point2D.Double(scaleUp(ni.getAnchorCenterX())+1, scaleUp(ni.getAnchorCenterY())+1),
 
2861
                new Point2D.Double(scaleUp(ni.getAnchorCenterX())+1, scaleUp(ni.getAnchorCenterY())-1)
 
2862
        });
 
2863
        testPoly.setLayer(wellLayer);
 
2864
        if (pn.getFunction() == PrimitiveNode.Function.SUBSTRATE) // defines a substrate contact
 
2865
        {
 
2866
            // make sure that substrate contact is not being placed on top of Well (Nwell for P-substrate process)
 
2867
            if (wellLayer != null)
 
2868
            {
 
2869
                if (merge.contains(wellLayer, testPoly))
 
2870
                    return testPoly;
 
2871
            }
 
2872
        }
 
2873
        // special case: active contact without substrate layer looks the same as a well/substrate tap.
 
2874
        // Make sure we are using the correct one.
 
2875
        if (pn.getFunction() == PrimitiveNode.Function.CONTACT && hasActive)
 
2876
        {
 
2877
            // active contact. If Psubstrate process, make sure Ndiff contact is not being placed on top of Nwell
 
2878
            // for Nsubstrate process, make sure Pdiff contact is not being placed on top of Pwell
 
2879
            if ((pSubstrateProcess && hasNplus) || (nSubstrateProcess && hasPplus))
 
2880
            {
 
2881
                if (merge.contains(wellLayer, testPoly))
 
2882
                    return testPoly;
 
2883
            }
 
2884
        }
 
2885
 
 
2886
        if (!approximateCuts && cutsInArea != null)
2095
2887
                {
2096
2888
                        // make sure all cuts in area are found in the node
2097
2889
                        for(PolyBase pb : cutsInArea)
2238
3030
                                        // make sure the geometric database is made up of proper layers
2239
3031
                                        layer = geometricLayer(layer);
2240
3032
                                        if (layer.getFunction().isContact()) continue;
 
3033
                    if (layer.getFunction().isMetal()) continue;
 
3034
                    if (layer.getFunction().isPoly()) continue;
2241
3035
 
2242
 
                                        poly.transform(trans);
 
3036
                    poly.transform(trans);
2243
3037
                                        Point2D [] points = poly.getPoints();
2244
3038
                                        for(int k=0; k<points.length; k++)
2245
3039
                                                poly.setPoint(k, scaleUp(points[k].getX()), scaleUp(points[k].getY()));
2277
3071
                {
2278
3072
                        PrimitiveNode pNp = nIt.next();
2279
3073
                        PrimitiveNode.Function fun = pNp.getFunction();
2280
 
                        if (fun != PrimitiveNode.Function.CONTACT && fun != PrimitiveNode.Function.WELL &&
 
3074
                        if (!fun.isContact() && fun != PrimitiveNode.Function.WELL &&
2281
3075
                                fun != PrimitiveNode.Function.SUBSTRATE) continue;
2282
3076
 
2283
3077
                        // TODO do we really need to vet each contact?
2318
3112
                                } else if (lFun.isDiff() || lFun.isPoly()) hasPolyActive = true;
2319
3113
 
2320
3114
                                // ignore well/select layers if requested
2321
 
                                if (ignoreActiveSelectWell && fun == PrimitiveNode.Function.CONTACT)
 
3115
                                if (ignoreActiveSelectWell && fun.isContact())
2322
3116
                                {
2323
3117
                                        if (lFun.isImplant() || lFun.isSubstrate() || lFun.isWell()) continue;
2324
3118
                                }
2325
3119
 
2326
3120
                                // ignore well layers if the process doesn't have them
2327
 
//                              if (lFun == Layer.Function.WELLP && pWellProcess) continue;
2328
 
//                              if (lFun == Layer.Function.WELLN && nWellProcess) continue;
 
3121
//                              if (lFun == Layer.Function.WELLP && pSubstrateProcess) continue;
 
3122
//                              if (lFun == Layer.Function.WELLN && nSubstrateProcess) continue;
2329
3123
 
2330
3124
                                boolean cutLayer = false;
2331
3125
                                if (nLayer == lay)
2345
3139
                        if (cutNodeLayer < 0) continue;
2346
3140
 
2347
3141
                        // make sure via contacts connect exactly two layers of metal, next to each other
2348
 
                        if (!hasPolyActive && fun == PrimitiveNode.Function.CONTACT)
 
3142
                        if (!hasPolyActive && fun.isContact())
2349
3143
                        {
2350
3144
                                boolean badContact = false;
2351
3145
                                if (m1Layer < 0 || m2Layer < 0) badContact = true; else
2538
3332
        private Layer doesNodeFit(PossibleVia pv, Rectangle2D cutBox, PolyMerge originalMerge,
2539
3333
                boolean ignorePWell, boolean ignoreNWell)
2540
3334
        {
 
3335
        boolean hasPplus = false;
 
3336
        boolean hasNplus = false;
 
3337
        boolean hasActive = false;
2541
3338
                for(int i=0; i<pv.layers.length; i++)
2542
3339
                {
2543
3340
                        Layer l = pv.layers[i];
2544
3341
                        if (ignorePWell && l.getFunction() == Layer.Function.WELLP) continue;
2545
3342
                        if (ignoreNWell && l.getFunction() == Layer.Function.WELLN) continue;
 
3343
            if (l.isDiffusionLayer()) hasActive = true;
 
3344
            if (l.getFunction() == Layer.Function.IMPLANTN) hasNplus = true;
 
3345
            if (l.getFunction() == Layer.Function.IMPLANTP) hasPplus = true;
 
3346
 
2546
3347
                        double lX = cutBox.getMinX() - pv.shrinkL[i];
2547
3348
                        double hX = cutBox.getMaxX() + pv.shrinkR[i];
2548
3349
                        double lY = cutBox.getMinY() - pv.shrinkB[i];
2558
3359
                                return l;
2559
3360
                        }
2560
3361
                }
2561
 
 
2562
 
                // all layers fit: can create the node
 
3362
        // special case: some substrate contacts in some techs do not have the substrate layer (since often the original geom
 
3363
        // also does not have the substrate layer). To prevent these from being used as regular contacts,
 
3364
        // do an extra check here
 
3365
        PolyBase testPoly = new PolyBase(new Point2D[]{
 
3366
                new Point2D.Double(cutBox.getCenterX()-1, cutBox.getCenterY()-1),
 
3367
                new Point2D.Double(cutBox.getCenterX()-1, cutBox.getCenterY()+1),
 
3368
                new Point2D.Double(cutBox.getCenterX()+1, cutBox.getCenterY()+1),
 
3369
                new Point2D.Double(cutBox.getCenterX()+1, cutBox.getCenterY()-1)
 
3370
        });
 
3371
        testPoly.setLayer(wellLayer);
 
3372
        if (pv.pNp.getFunction() == PrimitiveNode.Function.SUBSTRATE) // defines a substrate contact
 
3373
        {
 
3374
            // make sure that substrate contact is not being placed on top of Well (Nwell for psubstrate process)
 
3375
            if (wellLayer != null)
 
3376
            {
 
3377
                if (originalMerge.contains(wellLayer, testPoly)) {
 
3378
                    if (DEBUGCONTACTS) System.out.println("      CONTACT FAILS ON LAYER "+wellLayer.getName()+" WHICH MUST NOT BE PRESENT AT "+
 
3379
                        TextUtils.formatDouble(cutBox.getCenterX()/SCALEFACTOR)+","+TextUtils.formatDouble(cutBox.getCenterY()/SCALEFACTOR));
 
3380
                    return wellLayer;
 
3381
                }
 
3382
            }
 
3383
        }
 
3384
        // special case: active contact without substrate layer looks the same as a well/substrate tap.
 
3385
        // Make sure we are using the correct one.
 
3386
        if (pv.pNp.getFunction() == PrimitiveNode.Function.CONTACT && hasActive)
 
3387
        {
 
3388
            // active contact. If Psubstrate process, make sure Ndiff contact is not being placed on top of Nwell
 
3389
            // for Nsubstrate process, make sure Pdiff contact is not being placed on top of Pwell
 
3390
            if ((pSubstrateProcess && hasNplus) || (nSubstrateProcess && hasPplus))
 
3391
            {
 
3392
                if (originalMerge.contains(wellLayer, testPoly)) {
 
3393
                    if (DEBUGCONTACTS) System.out.println("      CONTACT FAILS ON LAYER "+wellLayer.getName()+" WHICH MUST NOT BE PRESENT AT "+
 
3394
                        TextUtils.formatDouble(cutBox.getCenterX()/SCALEFACTOR)+","+TextUtils.formatDouble(cutBox.getCenterY()/SCALEFACTOR));
 
3395
                    return wellLayer;
 
3396
                }
 
3397
            }
 
3398
        }
 
3399
        // all layers fit: can create the node
2563
3400
                return null;
2564
3401
        }
2565
3402
 
2582
3419
                                if (pNp.getFunction().isNTypeTransistor()) listToUse = nTransistors;
2583
3420
 
2584
3421
                                boolean same = true;
 
3422
/*
 
3423
                // JKG: took out this code because it either drops all the "special transistors"
 
3424
                // that have an extra layer (OD18, VTH, VTL), or drops all the regular transistors -
 
3425
                // which one it does is dependent on the order of nodes returned by tech, which is
 
3426
                // apparently not consistent.
 
3427
                // I don't know why this code was needed - optimization?
2585
3428
                                if (listToUse.size() > 0)
2586
3429
                                {
2587
3430
                                        // make sure additional transistors have the same overall structure
2615
3458
                                                if (mi1 == null || mi2 == null || mi1.intValue() != mi2.intValue()) { same = false; break; }
2616
3459
                                        }
2617
3460
                                }
 
3461
*/
2618
3462
                                if (same) listToUse.add(pNp);
2619
3463
                        }
2620
3464
                }
2645
3489
                        {
2646
3490
                                // look at all of the pieces of this layer
2647
3491
                                Rectangle2D transBox = poly.getBox();
 
3492
                                double cX = poly.getCenterX(), cY = poly.getCenterY();
 
3493
                                if (alignment != null)
 
3494
                                {
 
3495
                    // centers can be offgrid by a factor of 2, because only the edges matter for offgrid
 
3496
                    if (alignment.getWidth() > 0)
 
3497
                                                cX = Math.round(cX / scaleUp(alignment.getWidth()/2)) * scaleUp(alignment.getWidth()/2);
 
3498
                                        if (alignment.getHeight() > 0)
 
3499
                                                cY = Math.round(cY / scaleUp(alignment.getHeight()/2)) * scaleUp(alignment.getHeight()/2);
 
3500
                                }
2648
3501
//System.out.println("EXAMINING TRANSISTOR AT ("+TextUtils.formatDistance(poly.getCenterX()/SCALEFACTOR)+","+
2649
3502
//      TextUtils.formatDistance(poly.getCenterY()/SCALEFACTOR)+")");
2650
3503
                                if (transBox == null)
2694
3547
                                                {
2695
3548
                                                        addErrorLog(newCell, "Transistor at (" + TextUtils.formatDistance(transBox.getCenterX()/SCALEFACTOR) +
2696
3549
                                                                "," + TextUtils.formatDistance(transBox.getCenterY()/SCALEFACTOR) +
2697
 
                                                                ") doesn't have proper tabs...not extracted", poly.getCenter());
 
3550
                                                                ") doesn't have proper tabs...not extracted at ("+cX+","+cY+")");
2698
3551
                                                        continue;
2699
3552
                                                }
2700
3553
                                                SizeOffset so = transistor.getProtoSizeOffset();
2702
3555
                                                double height = hei + scaleUp(so.getLowYOffset() + so.getHighYOffset());
2703
3556
 
2704
3557
                                                // make sure all layers fit
2705
 
                                                EPoint ctr = new EPoint(poly.getCenterX()/SCALEFACTOR, poly.getCenterY()/SCALEFACTOR);
 
3558
                                                EPoint ctr = new EPoint(cX/SCALEFACTOR, cY/SCALEFACTOR);
2706
3559
                                                NodeInst ni = makeDummyNodeInst(transistor, ctr, width, height,
2707
3560
                                                        Orientation.fromAngle(angle), Technology.NodeLayer.MULTICUT_CENTERED);
2708
3561
                                                String msg = dummyTransistorFits(ni, originalMerge, newCell);
2709
3562
                                                if (msg != null) { errors.add(msg);   continue; }
2710
3563
 
2711
 
                                                realizeNode(transistor, Technology.NodeLayer.MULTICUT_CENTERED, poly.getCenterX(), poly.getCenterY(),
 
3564
                                                realizeNode(transistor, Technology.NodeLayer.MULTICUT_CENTERED, cX, cY,
2712
3565
                                                        width, height, angle, null, merge, newCell, null);
2713
3566
                                                errors.clear();
2714
3567
                                                break;
2715
3568
                                        }
2716
3569
                                        if (errors.size() > 0)
2717
3570
                                        {
2718
 
                                                addErrorLog(newCell, errors.get(0), new EPoint(poly.getCenterX()/SCALEFACTOR, poly.getCenterY()/SCALEFACTOR));
 
3571
                        for (String msg : errors)
 
3572
                            addErrorLog(newCell, msg, new EPoint(cX/SCALEFACTOR, cY/SCALEFACTOR));
2719
3573
                                        }
2720
3574
                                }
2721
3575
                        }
2740
3594
                        if (l == null) continue;
2741
3595
                        l = geometricLayer(l);
2742
3596
                        Layer.Function fun = l.getFunction();
2743
 
                        if (fun == Layer.Function.WELLP && pWellProcess) continue;
2744
 
                        if (fun == Layer.Function.WELLN && nWellProcess) continue;
 
3597
                        if (fun == Layer.Function.WELLP && pSubstrateProcess) continue;
 
3598
                        if (fun == Layer.Function.WELLN && nSubstrateProcess) continue;
2745
3599
                        poly.setLayer(l);
2746
3600
                        poly.transform(trans);
2747
3601
                        Point2D[] points = poly.getPoints();
2986
3840
                                                double xpos = polyBounds1.getCenterX();
2987
3841
                                                if (xpos < polyBounds2.getMinX()) xpos = polyBounds2.getMinX();
2988
3842
                                                if (xpos > polyBounds2.getMaxX()) xpos = polyBounds2.getMaxX();
 
3843
                                                if (alignment != null && alignment.getWidth() > 0)
 
3844
                                                {
 
3845
                                                        xpos = Math.round(xpos / scaleUp(alignment.getWidth())) * scaleUp(alignment.getWidth());
 
3846
                                                        if (xpos < polyBounds2.getMinX() || xpos > polyBounds2.getMaxX()) continue;
 
3847
                                                }
2989
3848
                                                Point2D pt1 = new Point2D.Double(xpos, polyBounds1.getCenterY());
2990
3849
                                                Point2D pt2 = new Point2D.Double(xpos, polyBounds2.getCenterY());
2991
3850
 
3000
3859
                                                double ypos = polyBounds1.getCenterY();
3001
3860
                                                if (ypos < polyBounds2.getMinY()) ypos = polyBounds2.getMinY();
3002
3861
                                                if (ypos > polyBounds2.getMaxY()) ypos = polyBounds2.getMaxY();
 
3862
                                                if (alignment != null && alignment.getHeight() > 0)
 
3863
                                                {
 
3864
                                                        ypos = Math.round(ypos / scaleUp(alignment.getHeight())) * scaleUp(alignment.getHeight());
 
3865
                                                        if (ypos < polyBounds2.getMinY() || ypos > polyBounds2.getMaxY()) continue;
 
3866
                                                }
3003
3867
                                                Point2D pt1 = new Point2D.Double(polyBounds1.getCenterX(), ypos);
3004
3868
                                                Point2D pt2 = new Point2D.Double(polyBounds2.getCenterX(), ypos);
3005
3869
 
3062
3926
 
3063
3927
                // find the port that is being extended
3064
3928
                Point2D polyCtr = new Point2D.Double(polyBounds.getCenterX(), polyBounds.getCenterY());
 
3929
                if (alignment != null)
 
3930
                {
 
3931
                        double x = polyCtr.getX();
 
3932
                        double y = polyCtr.getY();
 
3933
                        if (alignment.getWidth() > 0)
 
3934
                                x = Math.round(x / scaleUp(alignment.getWidth())) * scaleUp(alignment.getWidth());
 
3935
                        if (alignment.getHeight() > 0)
 
3936
                                y = Math.round(y / scaleUp(alignment.getHeight())) * scaleUp(alignment.getHeight());
 
3937
                        polyCtr.setLocation(x, y);
 
3938
                }
3065
3939
                if (obj instanceof ArcInst)
3066
3940
                {
3067
3941
                        ArcInst ai = (ArcInst)obj;
3391
4265
                                {
3392
4266
                                        if (cl.width < minWidth) continue;
3393
4267
 
 
4268
                                        if (alignment != null)
 
4269
                                        {
 
4270
/*
 
4271
                        if (cl.start.getX() == cl.end.getX())
 
4272
                                                {
 
4273
                                                        // vertical line: align in X
 
4274
                                                        if (alignment.getWidth() > 0)
 
4275
                                                        {
 
4276
                                                                double aliX = scaleUp(alignment.getWidth());
 
4277
                                                                double newX = Math.round(cl.start.getX() / aliX) * aliX;
 
4278
                                                                cl.width -= Math.abs(newX - cl.start.getX());
 
4279
                                                                cl.width = Math.floor(cl.width / aliX) * aliX;
 
4280
                                                                cl.setStart(newX, cl.start.getY());
 
4281
                                                                cl.setEnd(newX, cl.end.getY());
 
4282
                                                        }
 
4283
                                                } else if (cl.start.getY() == cl.end.getY())
 
4284
                                                {
 
4285
                                                        // horizontal line: align in Y
 
4286
                                                        if (alignment.getHeight() > 0)
 
4287
                                                        {
 
4288
                                                                double aliY = scaleUp(alignment.getHeight());
 
4289
                                                                double newY = Math.round(cl.start.getY() / aliY) * aliY;
 
4290
                                                                cl.width -= Math.abs(newY - cl.start.getY());
 
4291
                                                                cl.width = Math.floor(cl.width / aliY) * aliY;
 
4292
                                                                cl.setStart(cl.start.getX(), newY);
 
4293
                                                                cl.setEnd(cl.end.getX(), newY);
 
4294
                                                        }
 
4295
                                                }
 
4296
*/
 
4297
                                        }
 
4298
 
3394
4299
                                        // make the polygon to describe the centerline
3395
4300
                                        double length = cl.start.distance(cl.end);
3396
4301
                                        if (length < DBMath.getEpsilon()) continue;
3403
4308
                                        // if wider than long, this cannot be the first centerline
3404
4309
                                        if (validCenterlines.size() == 0)
3405
4310
                                        {
3406
 
                                                double len = cl.start.distance(cl.end);
3407
 
                                                if (cl.width > len) continue;
 
4311
                                                //double len = cl.start.distance(cl.end);
 
4312
                                                //if (cl.width > len) continue;
3408
4313
                                        }
3409
4314
 
3410
4315
                                        // for nonmanhattan centerlines, do extra work to ensure uniqueness
3462
4367
                                System.out.println("    "+validCenterlines.get(i));
3463
4368
                }
3464
4369
 
3465
 
                // now extend centerlines so they meet
 
4370
        List<Centerline> extraCenterlines = new ArrayList<Centerline>();
 
4371
 
 
4372
        // now extend centerlines so they meet
3466
4373
                Centerline [] both = new Centerline[2];
3467
4374
                for(int i=0; i<validCenterlines.size(); i++)
3468
4375
                {
3500
4407
                                                if (minDistToEnd <= both[b].width/2) makeT = false;
3501
4408
                                        }
3502
4409
 
 
4410
                    boolean internalIntersect = false;
 
4411
                    Line2D lineSeg = new Line2D.Double(newStart, newEnd);
 
4412
                    if (lineSeg.ptSegDist(intersect) == 0)
 
4413
                        internalIntersect = true;
 
4414
 
 
4415
                    // if intersection is off-grid, rather than having two arcs join at this point,
 
4416
                    // which can cause off-grid errors, make a pure layer node that is the intersection area,
 
4417
                    // and connect to that on the edges. The important difference is a pure-layer node has
 
4418
                    // the entire node as the port, rather than an arc pin, so the connection points can be on grid.
 
4419
                    boolean offgrid = false;
 
4420
                    if (alignment != null && alignment.getWidth() > 0 && (intersect.getX() % scaleUp(alignment.getWidth()) != 0)) offgrid = true;
 
4421
                    if (alignment != null && alignment.getHeight() > 0 && (intersect.getY() % scaleUp(alignment.getHeight()) != 0)) offgrid = true;
 
4422
 
3503
4423
                                        // adjust the centerline to end at the intersection point
3504
4424
                                        double extendStart = 0, extendEnd = 0, extendAltStart = 0, extendAltEnd = 0, betterExtension = 0;
3505
4425
                                        Point2D altNewStart = new Point2D.Double(0,0), altNewEnd = new Point2D.Double(0,0);
3509
4429
                                                altNewStart.setLocation(newStart);   altNewEnd.setLocation(intersect);
3510
4430
                                                newStart = intersect;
3511
4431
                                                extendAltEnd = extendStart = both[b].width / 2;
3512
 
                                        } else
 
4432
                        if (offgrid && !makeT) {
 
4433
                            if (internalIntersect) {
 
4434
                                // adjust closer end point out of intersection area
 
4435
                                double diffX = altNewStart.getX() - intersect.getX();
 
4436
                                double diffY = altNewStart.getY() - intersect.getY();
 
4437
                                newStart = new Point2D.Double(intersect.getX() - diffX, intersect.getY() - diffY);
 
4438
                                altNewEnd.setLocation(intersect.getX() + diffX, intersect.getY() + diffY);
 
4439
                            } else {
 
4440
                                newStart.setLocation(altNewStart);
 
4441
                            }
 
4442
                            extendAltEnd = extendStart = Math.abs(betterExtension);
 
4443
                        }
 
4444
                        else if (!makeT && betterExtension < extendStart) {
 
4445
                            // wire will not have ends extended, add in extra wire to account for non-end extension
 
4446
                            Centerline newCl = new Centerline(both[b].width, altNewStart, intersect);
 
4447
                            newCl.startHub = false;
 
4448
                            newCl.endHub = true;
 
4449
                            if (newCl.start.distance(newCl.end) > 0)
 
4450
                                extraCenterlines.add(newCl);
 
4451
                        }
 
4452
                    } else // case: distToEnd <= distToStart
3513
4453
                                        {
3514
4454
                                                betterExtension = newEnd.distance(intersect);
3515
4455
                                                altNewStart.setLocation(intersect);   altNewEnd.setLocation(newEnd);
3516
4456
                                                newEnd = intersect;
3517
4457
                                                extendAltStart = extendEnd = both[b].width / 2;
 
4458
                        if (offgrid && !makeT) {
 
4459
                            if (internalIntersect) {
 
4460
                                double diffX = altNewEnd.getX() - intersect.getX();
 
4461
                                double diffY = altNewEnd.getY() - intersect.getY();
 
4462
                                newEnd = new Point2D.Double(intersect.getX() - diffX, intersect.getY() - diffY);
 
4463
                                altNewStart.setLocation(intersect.getX() + diffX, intersect.getY() + diffY);
 
4464
                            } else {
 
4465
                                newEnd.setLocation(altNewEnd);
 
4466
                            }
 
4467
                            extendAltStart = extendEnd = Math.abs(betterExtension);
 
4468
                        }
 
4469
                        else if (!makeT && betterExtension < extendEnd) {
 
4470
                            // wire will not have ends extended, add in extra wire to account for non-end extension
 
4471
                            Centerline newCl = new Centerline(both[b].width, intersect, altNewEnd);
 
4472
                            newCl.startHub = true;
 
4473
                            newCl.endHub = false;
 
4474
                            if (newCl.start.distance(newCl.end) > 0)
 
4475
                                extraCenterlines.add(newCl);
 
4476
                        }
3518
4477
                                        }
3519
4478
                                        Poly extended = Poly.makeEndPointPoly(newStart.distance(newEnd), both[b].width, both[b].angle,
3520
4479
                                                newStart, extendStart, newEnd, extendEnd, Poly.Type.FILLED);
3524
4483
                                                if (extendEnd > 0) extendEnd = betterExtension;
3525
4484
                                                extended = Poly.makeEndPointPoly(newStart.distance(newEnd), both[b].width, both[b].angle,
3526
4485
                                                        newStart, extendStart, newEnd, extendEnd, Poly.Type.FILLED);
3527
 
                                        }
 
4486
                    }
3528
4487
                                        if (originalMerge.contains(layer, extended))
3529
4488
                                        {
3530
4489
                                                both[b].setStart(newStart.getX(), newStart.getY());
3540
4499
                                                        validCenterlines.add(newCL);
3541
4500
                                                        continue;
3542
4501
                                                }
3543
 
                                        }
 
4502
                                        } else {
 
4503
                        //System.out.println("Merge does not contain arc");
 
4504
                    }
3544
4505
                                }
3545
4506
                        }
3546
 
                }
3547
 
                if (DEBUGCENTERLINES)
 
4507
        }
 
4508
        validCenterlines.addAll(extraCenterlines);
 
4509
 
 
4510
        if (DEBUGCENTERLINES)
3548
4511
                {
3549
4512
                        System.out.println("FINAL: ");
3550
4513
                        for(Centerline cl : validCenterlines) System.out.println("    "+cl);
3768
4731
                                                if (originalMerge.contains(poly.getLayer(), clPoly))
3769
4732
                                                {
3770
4733
                                                        // if the width is much greater than the length, rotate the centerline 90 degrees
 
4734
/*
3771
4735
                                                        if (width > length*2)
3772
4736
                                                        {
3773
4737
                                                                Point2D [] pts = clPoly.getPoints();
3790
4754
                                                                possibleEnd[p] = edgeCtrs[endPt];
3791
4755
                                                                length = edgeCtrs[startPt].distance(edgeCtrs[endPt]);
3792
4756
                                                        }
 
4757
*/
 
4758
 
 
4759
                                                        // get the centerline points
 
4760
                                                        double psX = possibleStart[p].getX();
 
4761
                                                        double psY = possibleStart[p].getY();
 
4762
                                                        double peX = possibleEnd[p].getX();
 
4763
                                                        double peY = possibleEnd[p].getY();
 
4764
 
 
4765
/*
 
4766
                                                        // grid-align the centerline points
 
4767
                                                        double xGrid = scaleUp(alignment.getWidth());
 
4768
                                                        double yGrid = scaleUp(alignment.getHeight());
 
4769
                                                        if (!isOnGrid(psX, xGrid))
 
4770
                                                        {
 
4771
                                                                if (psX > peX) psX = Math.floor(psX / xGrid) * xGrid; else
 
4772
                                                                        psX = Math.ceil(psX / xGrid) * xGrid;
 
4773
                                                        }
 
4774
                                                        if (!isOnGrid(psY, yGrid))
 
4775
                                                        {
 
4776
                                                                if (psY > peY) psY = Math.floor(psY / yGrid) * yGrid; else
 
4777
                                                                        psY = Math.ceil(psY / yGrid) * yGrid;
 
4778
                                                        }
 
4779
                                                        if (!isOnGrid(peX, xGrid))
 
4780
                                                        {
 
4781
                                                                if (peX > psX) peX = Math.floor(peX / xGrid) * xGrid; else
 
4782
                                                                        peX = Math.ceil(peX / xGrid) * xGrid;
 
4783
                                                        }
 
4784
                                                        if (!isOnGrid(peY, yGrid))
 
4785
                                                        {
 
4786
                                                                if (peY > psY) peY = Math.floor(peY / yGrid) * yGrid; else
 
4787
                                                                        peY = Math.ceil(peY / yGrid) * yGrid;
 
4788
                                                        }
 
4789
*/
3793
4790
 
3794
4791
                                                        // create the centerline
3795
 
                                                        Centerline newCL = new Centerline(width, possibleStart[p], possibleEnd[p]);
3796
 
                                                        if (newCL.angle >= 0) centerlines.add(newCL);
3797
 
                                                        if (DEBUGCENTERLINES) System.out.println("  MAKE "+newCL.toString());
 
4792
                                                        Point2D ps = new Point2D.Double(psX, psY);
 
4793
                                                        Point2D pe = new Point2D.Double(peX, peY);
 
4794
                                                        Centerline newCL = new Centerline(width, ps, pe);
 
4795
                            if (newCL.angle >= 0) {
 
4796
                                // check for redundant centerlines, favor centerlines that extend to external geometry
 
4797
                                boolean comparisonDone = false;
 
4798
                                for (int ci=0; ci < centerlines.size(); ci++) {
 
4799
                                    Centerline acl = centerlines.get(ci);
 
4800
                                    // same bounds
 
4801
                                    if (acl.getBounds().equals(newCL.getBounds())) {
 
4802
 
 
4803
                                        // check if they are perpendicular - if not, they are exactly redundant
 
4804
                                        Centerline horCL = null, verCL = null;
 
4805
                                        if (acl.start.getX() == acl.end.getX()) verCL = acl;
 
4806
                                        if (acl.start.getY() == acl.end.getY()) horCL = acl;
 
4807
                                        if (newCL.start.getX() == newCL.end.getX()) verCL = newCL;
 
4808
                                        if (newCL.start.getY() == newCL.end.getY()) horCL = newCL;
 
4809
                                        if (horCL == null || verCL == null) {
 
4810
                                            comparisonDone = true;
 
4811
                                            break; // not perpendicular
 
4812
                                        }
 
4813
 
 
4814
                                        Rectangle2D bounds = acl.getBounds();
 
4815
                                        int favorHor = 0, favorVer = 0;
 
4816
 
 
4817
                                        // check horizontal extensions
 
4818
                                        Rectangle2D boundsE = new Rectangle2D.Double(bounds.getX(), bounds.getY(),
 
4819
                                                bounds.getWidth()+1.0/SCALEFACTOR, bounds.getHeight());
 
4820
                                        Rectangle2D boundsW = new Rectangle2D.Double(bounds.getX()-1.0/SCALEFACTOR, bounds.getY(),
 
4821
                                                bounds.getWidth()+1.0/SCALEFACTOR, bounds.getHeight());
 
4822
                                        if (originalMerge.contains(poly.getLayer(), new PolyBase(boundsE)))
 
4823
                                            favorHor++;
 
4824
                                        if (originalMerge.contains(poly.getLayer(), new PolyBase(boundsW)))
 
4825
                                            favorHor++;
 
4826
 
 
4827
                                        // check vertical extensions
 
4828
                                        Rectangle2D boundsN = new Rectangle2D.Double(bounds.getX(), bounds.getY(),
 
4829
                                                bounds.getWidth(), bounds.getHeight()+1.0/SCALEFACTOR);
 
4830
                                        Rectangle2D boundsS = new Rectangle2D.Double(bounds.getX(), bounds.getY()-1.0/SCALEFACTOR,
 
4831
                                                bounds.getWidth(), bounds.getHeight()+1.0/SCALEFACTOR);
 
4832
                                        if (originalMerge.contains(poly.getLayer(), new PolyBase(boundsN)))
 
4833
                                            favorVer++;
 
4834
                                        if (originalMerge.contains(poly.getLayer(), new PolyBase(boundsS)))
 
4835
                                            favorVer++;
 
4836
 
 
4837
                                        if (favorHor > favorVer) {
 
4838
                                            if (centerlines.contains(verCL)) {
 
4839
                                                if (DEBUGCENTERLINES)
 
4840
                                                    System.out.println("***REMOVE "+verCL.toString()+" WHICH IS SUBOPTIMAL");
 
4841
                                                centerlines.remove(verCL);
 
4842
                                            }
 
4843
                                            if (!centerlines.contains(horCL)) {
 
4844
                                                if (DEBUGCENTERLINES) System.out.println("  MAKE "+newCL.toString());
 
4845
                                                centerlines.add(horCL);
 
4846
                                            }
 
4847
                                            comparisonDone = true;
 
4848
                                        }
 
4849
                                        if (favorVer > favorHor) {
 
4850
                                            if (centerlines.contains(horCL)) {
 
4851
                                                if (DEBUGCENTERLINES)
 
4852
                                                    System.out.println("***REMOVE "+horCL.toString()+" WHICH IS SUBOPTIMAL");
 
4853
                                                centerlines.remove(horCL);
 
4854
                                            }
 
4855
                                            if (!centerlines.contains(verCL)) {
 
4856
                                                if (DEBUGCENTERLINES) System.out.println("  MAKE "+newCL.toString());
 
4857
                                                centerlines.add(verCL);
 
4858
                                            }
 
4859
                                            comparisonDone = true;
 
4860
                                        }
 
4861
                                        break;
 
4862
                                    }
 
4863
                                }
 
4864
                                if (!comparisonDone) {
 
4865
                                    centerlines.add(newCL);
 
4866
                                    if (DEBUGCENTERLINES) System.out.println("  MAKE "+newCL.toString());
 
4867
                                }
 
4868
                            }
3798
4869
                                                        break;
3799
4870
                                                }
3800
4871
                                        }
3886
4957
                        ArcProto ap = arcsForLayer.get(layer);
3887
4958
                        List<PolyBase> polyList = getMergePolys(merge, layer, numIgnored);
3888
4959
 
3889
 
                        // implant layers may be large rectangles
3890
 
                        if (layer.getFunction().isSubstrate())
 
4960
            if (layer.getFunction().isSubstrate() || layer.getFunction().isImplant()) {
 
4961
                // just dump back in original layer, as it doesn't connect to anything anyway
 
4962
                polyList = new ArrayList<PolyBase>(originalMerge.getObjects(layer, false, false));
 
4963
            }
 
4964
 
 
4965
            // implant layers may be large rectangles
 
4966
            /*
 
4967
            if (layer.getFunction().isSubstrate())
3891
4968
                        {
3892
4969
                                // make a list of rectangles that are proper approximations of polygons
3893
4970
                                List<Rectangle2D> rectangleList = new ArrayList<Rectangle2D>();
3931
5008
                                                rectangleList.remove(polyBounds);
3932
5009
                                }
3933
5010
                        }
3934
 
 
3935
 
                        for(PolyBase poly : polyList)
 
5011
                        */
 
5012
            
 
5013
            for(PolyBase poly : polyList)
3936
5014
                        {
 
5015
                if (Extract.isUsePureLayerNodes()) ap = null;
3937
5016
                                // special case: a rectangle on a routable layer: make it an arc
3938
 
                                if (ap != null)
 
5017
                if (ap != null)
3939
5018
                                {
3940
5019
                                        Rectangle2D polyBounds = poly.getBox();
3941
5020
                                        if (polyBounds == null)
3946
5025
                                        }
3947
5026
                                        if (polyBounds != null)
3948
5027
                                        {
3949
 
                                                double width = polyBounds.getWidth() / SCALEFACTOR;
3950
 
                                                double height = polyBounds.getHeight() / SCALEFACTOR;
 
5028
                                                double width = polyBounds.getWidth();
 
5029
                                                double height = polyBounds.getHeight();
3951
5030
                                                double actualWidth = 0;
3952
 
                                                if (ENFORCEMINIMUMSIZE) actualWidth = ap.getDefaultLambdaBaseWidth();
 
5031
                                                if (ENFORCEMINIMUMSIZE) actualWidth = ap.getDefaultLambdaBaseWidth() * SCALEFACTOR;
3953
5032
                                                if (width >= actualWidth && height >= actualWidth)
3954
5033
                                                {
3955
5034
                                                        PrimitiveNode np = ap.findPinProto();
3958
5037
                                                        if (width > height)
3959
5038
                                                        {
3960
5039
                                                                // make a horizontal arc
3961
 
                                                                end1 = new Point2D.Double((polyBounds.getMinX()+height/2) / SCALEFACTOR, polyBounds.getCenterY() / SCALEFACTOR);
3962
 
                                                                end2 = new Point2D.Double((polyBounds.getMaxX()-height/2) / SCALEFACTOR, polyBounds.getCenterY() / SCALEFACTOR);
 
5040
                                                                end1 = new Point2D.Double((polyBounds.getMinX()), polyBounds.getCenterY());
 
5041
                                                                end2 = new Point2D.Double((polyBounds.getMaxX()), polyBounds.getCenterY());
3963
5042
                                                                size = height;
3964
5043
                                                        } else
3965
5044
                                                        {
3966
5045
                                                                // make a vertical arc
3967
 
                                                                end1 = new Point2D.Double(polyBounds.getCenterX() / SCALEFACTOR, (polyBounds.getMinY()+width/2) / SCALEFACTOR);
3968
 
                                                                end2 = new Point2D.Double(polyBounds.getCenterX() / SCALEFACTOR, (polyBounds.getMaxY()-width/2) / SCALEFACTOR);
 
5046
                                                                end1 = new Point2D.Double(polyBounds.getCenterX(), (polyBounds.getMinY()));
 
5047
                                                                end2 = new Point2D.Double(polyBounds.getCenterX(), (polyBounds.getMaxY()));
3969
5048
                                                                size = width;
3970
5049
                                                        }
3971
 
                                                        NodeInst ni1 = createNode(np, end1, size, size, null, newCell);
3972
 
                                                        NodeInst ni2 = createNode(np, end2, size, size, null, newCell);
3973
 
                                                        MutableBoolean headExtend = new MutableBoolean(true), tailExtend = new MutableBoolean(true);
 
5050
                                                        MutableBoolean headExtend = new MutableBoolean(false), tailExtend = new MutableBoolean(false);
3974
5051
                                                        if (originalMerge.arcPolyFits(layer, end1, end2, size, headExtend, tailExtend))
3975
5052
                                                        {
 
5053
                                // scale everything
 
5054
                                end1 = new Point2D.Double(end1.getX() / SCALEFACTOR, end1.getY() / SCALEFACTOR);
 
5055
                                end2 = new Point2D.Double(end2.getX() / SCALEFACTOR, end2.getY() / SCALEFACTOR);
 
5056
                                size = size / SCALEFACTOR;
 
5057
                                // make arc
 
5058
                                NodeInst ni1 = createNode(np, end1, size, size, null, newCell);
 
5059
                                                                NodeInst ni2 = createNode(np, end2, size, size, null, newCell);
3976
5060
                                                                realizeArc(ap, ni1.getOnlyPortInst(), ni2.getOnlyPortInst(), end1, end2,
3977
5061
                                                                        size, !headExtend.booleanValue(), !tailExtend.booleanValue(), merge);
3978
 
                                                        }
 
5062
                                                        } else {
 
5063
                                System.out.println("Arc "+layer.getName()+" did not fit at "+polyBounds.getMinX()/SCALEFACTOR+","+polyBounds.getMinY()/SCALEFACTOR);
 
5064
                            }
3979
5065
                                                        continue;
3980
5066
                                                }
3981
5067
                                        }
3982
5068
                                }
3983
5069
 
3984
5070
                                // just generate a pure-layer node
3985
 
                                List<NodeInst> niList = makePureLayerNodeFromPoly(poly, newCell);
3986
 
                                if (niList == null) continue;
 
5071
                                List<NodeInst> niList = makePureLayerNodeFromPoly(poly, newCell, originalMerge);
 
5072
                // make well or implant hard to select
 
5073
                if (poly.getLayer().getFunction().isSubstrate() || poly.getLayer().getFunction().isImplant()) {
 
5074
                    for (NodeInst ni : niList) ni.setHardSelect();
 
5075
                }
 
5076
 
 
5077
                if (niList == null) continue;
3987
5078
 
3988
5079
                                // connect to the rest if possible
3989
5080
                                if (ap != null) for(NodeInst ni : niList)
4048
5139
                {
4049
5140
                        CutInfo cInfo = allCutLayers.get(layer);
4050
5141
                        for(PolyBase poly : cInfo.getCuts())
4051
 
                                makePureLayerNodeFromPoly(poly, newCell);
 
5142
                                makePureLayerNodeFromPoly(poly, newCell, originalMerge);
4052
5143
                }
4053
5144
 
4054
5145
                if (numIgnored.intValue() > 0)
4056
5147
                                " tiny polygons (use Network Preferences to control tiny polygon limit)");
4057
5148
        }
4058
5149
 
4059
 
        /**
 
5150
    /**
 
5151
     * Method to add back in original routing layers as pure layer nodes
 
5152
     * @param oldCell the original imported cell
 
5153
     * @param newCell the new cell
 
5154
     * @param merge the remaining layers to create
 
5155
     * @param originalMerge the original set of layers
 
5156
     */
 
5157
    private void addInRoutingLayers(Cell oldCell, Cell newCell, PolyMerge merge, PolyMerge originalMerge)
 
5158
    {
 
5159
        Map<Layer,List<NodeInst>> newNodes = new HashMap<Layer,List<NodeInst>>();
 
5160
 
 
5161
        // create new nodes as copy of old nodes
 
5162
        for (Iterator<NodeInst> nit = oldCell.getNodes(); nit.hasNext(); )
 
5163
        {
 
5164
            NodeInst ni = nit.next();
 
5165
            NodeProto np = ni.getProto();
 
5166
            if (!(np instanceof PrimitiveNode)) continue;
 
5167
            PrimitiveNode pn = (PrimitiveNode)np;
 
5168
            if (pn.getFunction() == PrimitiveNode.Function.NODE)
 
5169
            {
 
5170
                Layer layer = pn.getLayerIterator().next();
 
5171
                Layer.Function fun = layer.getFunction();
 
5172
                if (fun.isPoly() || fun.isMetal() || fun.isDiff())
 
5173
                {
 
5174
                    List<NodeInst> newNis = new ArrayList<NodeInst>();
 
5175
                    // create same node in new cell
 
5176
                    if (ni.getTrace() != null && ni.getTrace().length > 0)
 
5177
                    {
 
5178
                        EPoint [] origPoints = ni.getTrace();
 
5179
                        Point2D [] points = new Point2D[origPoints.length];
 
5180
                        // for some reason getTrace returns points relative to center, but setTrace expects absolute coords
 
5181
                        for (int i=0; i<origPoints.length; i++) {
 
5182
                            points[i] = new Point2D.Double(origPoints[i].getX()+ni.getAnchorCenterX(), origPoints[i].getY()+ni.getAnchorCenterY());
 
5183
                        }
 
5184
 
 
5185
                        boolean BREAKUPTRACE = true;
 
5186
 
 
5187
                        PolyBase poly = new PolyBase(points);
 
5188
                        poly.setLayer(layer);
 
5189
 
 
5190
                        if (BREAKUPTRACE)
 
5191
                        {
 
5192
                            // irregular shape: break it up with simpler polygon merging algorithm
 
5193
                            GeometryHandler thisMerge = GeometryHandler.createGeometryHandler(GeometryHandler.GHMode.ALGO_SWEEP, 1);
 
5194
                            thisMerge.add(layer, poly);
 
5195
                            thisMerge.postProcess(true);
 
5196
    
 
5197
                            Collection<PolyBase> set = ((PolySweepMerge)thisMerge).getPolyPartition(layer);
 
5198
                            for(PolyBase simplePoly : set)
 
5199
                            {
 
5200
                                PolyBase simplePolyScaledUp = scaleUpPoly(simplePoly);
 
5201
                                pn = getActiveNodeType(layer, simplePolyScaledUp, originalMerge, pn);
 
5202
                                layer = pn.getLayerIterator().next();Rectangle2D polyBounds = simplePoly.getBounds2D();
 
5203
                                NodeInst newNi = NodeInst.makeInstance(pn, simplePoly.getCenter(), polyBounds.getWidth(), polyBounds.getHeight(),
 
5204
                                                                       newCell);
 
5205
                                if (newNi == null) continue;
 
5206
                                newNis.add(newNi);
 
5207
                            }
 
5208
                        } else {
 
5209
                            PolyBase polyScaledUp = scaleUpPoly(poly);
 
5210
                            pn = getActiveNodeType(layer, polyScaledUp, originalMerge, pn);
 
5211
                            NodeInst newNi = NodeInst.makeInstance(pn, ni.getAnchorCenter(), ni.getXSize(), ni.getYSize(), newCell);
 
5212
                            if (newNi != null) {
 
5213
                                newNis.add(newNi);
 
5214
                                newNi.setTrace(points);
 
5215
                            }
 
5216
                        }
 
5217
                    } else {
 
5218
                        PolyBase poly = new PolyBase(ni.getBounds());
 
5219
                        PolyBase polyScaledUp = scaleUpPoly(poly);
 
5220
                        pn = getActiveNodeType(layer, polyScaledUp, originalMerge, pn);
 
5221
                        NodeInst newNi = NodeInst.makeInstance(pn, ni.getAnchorCenter(), ni.getXSize(), ni.getYSize(),
 
5222
                                                               newCell, ni.getOrient(), null);
 
5223
                        if (newNi != null)
 
5224
                            newNis.add(newNi);
 
5225
                    }
 
5226
                    // substract out layers
 
5227
                    layer = pn.getLayerIterator().next();
 
5228
                    for (NodeInst newNi : newNis) {
 
5229
                        Poly [] polys = tech.getShapeOfNode(newNi);
 
5230
                        for (Poly p : polys)
 
5231
                        {
 
5232
                            if (p.getLayer() == layer)
 
5233
                                removePolyFromMerge(merge, layer, p);
 
5234
                        }
 
5235
                    }
 
5236
                    // add to map of created nodeinsts
 
5237
                    List<NodeInst> list = newNodes.get(layer);
 
5238
                    if (list == null)
 
5239
                    {
 
5240
                        list = new ArrayList<NodeInst>();
 
5241
                        newNodes.put(layer, list);
 
5242
                    }
 
5243
                    list.addAll(newNis);
 
5244
                }
 
5245
            }
 
5246
        }
 
5247
        // now stitch new nodes together
 
5248
        for (Layer layer : newNodes.keySet())
 
5249
        {
 
5250
            Layer.Function fun = layer.getFunction();
 
5251
            ArcProto ap = Generic.tech().universal_arc;
 
5252
            if (fun.isPoly() || fun.isMetal() || fun.isDiff()) ap = arcsForLayer.get(layer);
 
5253
 
 
5254
            List<NodeInst> nodes = newNodes.get(layer);
 
5255
            int i=0, j=1;
 
5256
            // check nodes against each other
 
5257
            for (i=0; i<nodes.size(); i++)
 
5258
            {
 
5259
                NodeInst ni1 = nodes.get(i);
 
5260
                for (j=i+1; j<nodes.size(); j++)
 
5261
                {
 
5262
                    NodeInst ni2 = nodes.get(j);
 
5263
                    if (ni1 == ni2) continue;
 
5264
                    // see if shapes intersect. If so, connect them
 
5265
                    Poly poly1 = tech.getShapeOfNode(ni1)[0];
 
5266
                    Poly poly2 = tech.getShapeOfNode(ni2)[0];
 
5267
                    List<Line2D> overlappingEdges = new ArrayList<Line2D>();
 
5268
                    List<PolyBase> intersection = poly1.getIntersection(poly2, overlappingEdges);
 
5269
 
 
5270
                    Point2D connectionPoint = null;
 
5271
                    if (intersection.size() > 0)
 
5272
                    {
 
5273
                        // areas intersect, use center point of first common area
 
5274
                        PolyBase pint = intersection.get(0);
 
5275
                        connectionPoint = pint.getCenter();
 
5276
                        // round center point
 
5277
                        if (alignment != null)
 
5278
                        {
 
5279
                            double x = connectionPoint.getX();
 
5280
                            double y = connectionPoint.getY();
 
5281
                            if (alignment.getWidth() > 0) x = Math.round(x/alignment.getWidth()) * alignment.getWidth();
 
5282
                            if (alignment.getHeight() > 0) y = Math.round(y/alignment.getHeight()) * alignment.getHeight();
 
5283
                            if (pint.contains(x, y))
 
5284
                                connectionPoint = new Point2D.Double(x, y);
 
5285
                        }
 
5286
                    }
 
5287
                    else if (overlappingEdges.size() > 0)
 
5288
                    {
 
5289
                        // areas do not intersect, but share common edges. Use center point of first edge
 
5290
                        Line2D line = overlappingEdges.get(0);
 
5291
                        double x = (line.getX1()+line.getX2())/2.0;
 
5292
                        double y = (line.getY1()+line.getY2())/2.0;
 
5293
                        if (alignment != null) {
 
5294
                            double newx = x, newy = y;
 
5295
                            if ((line.getY1() == line.getY2()) && !isOnGrid(x, alignment.getWidth())) {
 
5296
                                newx = Math.round(x/alignment.getWidth()) * alignment.getWidth();
 
5297
                            }
 
5298
                            if ((line.getX1() == line.getX2()) && !isOnGrid(y, alignment.getHeight())) {
 
5299
                                newy = Math.round(y/alignment.getHeight()) * alignment.getHeight();
 
5300
                            }
 
5301
                            if (line.ptSegDist(newx, newy) == 0) {
 
5302
                                x = newx;
 
5303
                                y = newy;
 
5304
                            }
 
5305
                        }
 
5306
                        connectionPoint = new Point2D.Double(x, y);
 
5307
                    }
 
5308
                    if (connectionPoint != null)
 
5309
                    {
 
5310
                        // check on ap, we need to decide if diff arc is really diff arc or well arc
 
5311
                        // scale up poly so units match originalMerge units
 
5312
                        PolyBase poly1Scaled = scaleUpPoly(poly1);
 
5313
 
 
5314
                        if (fun.isDiff()) {
 
5315
                            ap = findArcProtoForPoly(layer, poly1Scaled, originalMerge);
 
5316
                        }
 
5317
                        if (ap == null) ap = Generic.tech().universal_arc;
 
5318
                        
 
5319
                        double width = ap.getDefaultLambdaBaseWidth();
 
5320
                        ArcProto arcProto = ap;
 
5321
                        if (arcProto != Generic.tech().universal_arc)
 
5322
                        {
 
5323
                            // scale up to check merge
 
5324
                            Point2D connPointScaled = new Point2D.Double(scaleUp(connectionPoint.getX()), scaleUp(connectionPoint.getY()));
 
5325
                            Poly test1 = Poly.makeEndPointPoly(0.0, scaleUp(width), 0, connPointScaled, scaleUp(width/2.0), connPointScaled,
 
5326
                                    scaleUp(width/2.0), Poly.Type.FILLED);
 
5327
                            // if on grid and merge contains, make arc
 
5328
                            if (isOnGrid(test1) && originalMerge.contains(layer, test1))
 
5329
                            {
 
5330
                                realizeArc(arcProto, ni1.getOnlyPortInst(), ni2.getOnlyPortInst(), connectionPoint,
 
5331
                                        connectionPoint, width, false, false, merge);
 
5332
                                continue;
 
5333
                            }
 
5334
                            arcProto = Generic.tech().universal_arc;
 
5335
                            width = 0;
 
5336
                            //System.out.println("Using universal arc to connect "+ni1.describe(false)+" at "+connectionPoint+" to "+ni2.describe(false));
 
5337
                        }
 
5338
                        realizeArc(arcProto, ni1.getOnlyPortInst(), ni2.getOnlyPortInst(), connectionPoint,
 
5339
                                connectionPoint, width, false, false, merge);
 
5340
                    }
 
5341
                }
 
5342
            }
 
5343
        }
 
5344
    }
 
5345
 
 
5346
    private PrimitiveNode getActiveNodeType(Layer activeLayer, PolyBase poly, PolyMerge merge, PrimitiveNode defaultNode)
 
5347
    {
 
5348
        if (unifyActive || ignoreActiveSelectWell) return defaultNode;
 
5349
        if (defaultNode != pDiffNode && defaultNode != nDiffNode && defaultNode != diffNode) return defaultNode;
 
5350
 
 
5351
        if (activeLayer.getFunction() == Layer.Function.DIFFN) {
 
5352
            // make sure n-diffusion is in n-select
 
5353
            if (merge.contains(pSelectLayer, poly)) {
 
5354
                // switch it pactive
 
5355
                return pDiffNode;
 
5356
            }
 
5357
        }
 
5358
        if (activeLayer.getFunction() == Layer.Function.DIFFP) {
 
5359
            // make sure p-diffusion is in p-select
 
5360
            if (merge.contains(nSelectLayer, poly)) {
 
5361
                // switch it nactive
 
5362
                return nDiffNode;
 
5363
            }
 
5364
        }
 
5365
        return defaultNode;
 
5366
    }
 
5367
 
 
5368
    private boolean isOnGrid(Poly poly)
 
5369
    {
 
5370
        if (alignment != null)
 
5371
        {
 
5372
            for (Point2D p : poly.getPoints())
 
5373
            {
 
5374
                if (alignment.getWidth() > 0)
 
5375
                    if (!isOnGrid(p.getX(), alignment.getWidth())) return false;
 
5376
                if (alignment.getHeight() > 0)
 
5377
                    if (!isOnGrid(p.getY(), alignment.getHeight())) return false;
 
5378
            }
 
5379
        }
 
5380
        return true;
 
5381
    }
 
5382
 
 
5383
    /**
 
5384
     * Returns a new poly that is a scaled up version of the given poly
 
5385
     * @param poly the poly
 
5386
     * @return a new, scaled up poly
 
5387
     */
 
5388
    private PolyBase scaleUpPoly(PolyBase poly) {
 
5389
        Point2D [] points = new Point2D.Double[poly.getPoints().length];
 
5390
        for(int p=0; p<points.length; p++)
 
5391
            points[p] = new Point2D.Double(scaleUp(poly.getPoints()[p].getX()), scaleUp(poly.getPoints()[p].getY()));
 
5392
        PolyBase newpoly = new PolyBase(points);
 
5393
        newpoly.setStyle(poly.getStyle());
 
5394
        return newpoly;
 
5395
    }
 
5396
 
 
5397
 
 
5398
    /**
4060
5399
         * Method to convert a Poly to one or more pure-layer nodes.
4061
5400
         * @param poly the PolyBase to convert.
4062
5401
         * @param cell the Cell in which to place the node.
 
5402
     * @param originalMerge the original set of layers in the unextracted cell
4063
5403
         * @return a List of NodeInsts that were created (null on error).
4064
5404
         */
4065
 
        private List<NodeInst> makePureLayerNodeFromPoly(PolyBase poly, Cell cell)
 
5405
        private List<NodeInst> makePureLayerNodeFromPoly(PolyBase poly, Cell cell, PolyMerge originalMerge)
4066
5406
        {
4067
5407
                Layer layer = poly.getLayer();
4068
5408
 
4124
5464
                        for(PolyBase simplePoly : set)
4125
5465
                        {
4126
5466
                                Rectangle2D polyBounds = simplePoly.getBounds2D();
4127
 
                                double centerX = polyBounds.getCenterX() / SCALEFACTOR;
4128
 
                                double centerY = polyBounds.getCenterY() / SCALEFACTOR;
4129
 
                                Point2D center = new Point2D.Double(centerX, centerY);
4130
 
                                NodeInst ni = createNode(pNp, center, polyBounds.getWidth() / SCALEFACTOR,
4131
 
                                        polyBounds.getHeight() / SCALEFACTOR, null, cell);
 
5467
                                NodeInst ni = makeAlignedPoly(polyBounds, layer, originalMerge, pNp, cell);
 
5468
                                if (ni == null) continue;
4132
5469
                                createdNodes.add(ni);
4133
5470
                        }
4134
5471
                        return createdNodes;
4135
5472
                }
4136
5473
                Rectangle2D polyBounds = poly.getBounds2D();
 
5474
                NodeInst ni = makeAlignedPoly(polyBounds, layer, originalMerge, pNp, cell);
 
5475
                if (ni != null)
 
5476
                        createdNodes.add(ni);
 
5477
//              double centerX = polyBounds.getCenterX() / SCALEFACTOR;
 
5478
//              double centerY = polyBounds.getCenterY() / SCALEFACTOR;
 
5479
//              Point2D center = new Point2D.Double(centerX, centerY);
 
5480
//
 
5481
//              // compute any trace information if the shape is nonmanhattan
 
5482
//              EPoint [] newPoints = null;
 
5483
////            if (poly.getBox() == null)
 
5484
////            {
 
5485
////                    // store the trace
 
5486
////                    Point2D [] points = poly.getPoints();
 
5487
////                    newPoints = new EPoint[points.length];
 
5488
////                    for(int i=0; i<points.length; i++)
 
5489
////                            newPoints[i] = new EPoint(points[i].getX() / SCALEFACTOR, points[i].getY() / SCALEFACTOR);
 
5490
////            }
 
5491
//              NodeInst ni = createNode(pNp, center, polyBounds.getWidth() / SCALEFACTOR,
 
5492
//                      polyBounds.getHeight() / SCALEFACTOR, newPoints, cell);
 
5493
//              createdNodes.add(ni);
 
5494
                return createdNodes;
 
5495
        }
 
5496
 
 
5497
        private NodeInst makeAlignedPoly(Rectangle2D polyBounds, Layer layer, PolyMerge originalMerge, PrimitiveNode pNp, Cell cell)
 
5498
        {
4137
5499
                double centerX = polyBounds.getCenterX() / SCALEFACTOR;
4138
5500
                double centerY = polyBounds.getCenterY() / SCALEFACTOR;
 
5501
                double width = polyBounds.getWidth() / SCALEFACTOR;
 
5502
                double height = polyBounds.getHeight() / SCALEFACTOR;
 
5503
                if (alignment != null)
 
5504
                {
 
5505
                        if (alignment.getWidth() > 0)
 
5506
                        {
 
5507
                // centers can be offgrid, only edges matter
 
5508
                double aliX = Math.round(centerX / (alignment.getWidth()/2)) * (alignment.getWidth()/2);
 
5509
                                if (aliX != centerX)
 
5510
                                {
 
5511
                                        double newWidth = width + Math.abs(aliX-centerX)*2;
 
5512
                                        Poly rectPoly = new Poly(scaleUp(aliX), scaleUp(centerY), scaleUp(newWidth), scaleUp(height));
 
5513
                                        if (!originalMerge.contains(layer, rectPoly))
 
5514
                                        {
 
5515
                                                if (aliX > centerX) aliX -= alignment.getWidth(); else
 
5516
                                                        aliX += alignment.getWidth();
 
5517
                                                newWidth = width + Math.abs(aliX-centerX)*2;
 
5518
                                                rectPoly = new Poly(scaleUp(aliX), scaleUp(centerY), scaleUp(newWidth), scaleUp(height));
 
5519
                                                if (!originalMerge.contains(layer, rectPoly)) return null;
 
5520
                                        }
 
5521
                                        centerX = aliX;
 
5522
                                        width = newWidth;
 
5523
                                }
 
5524
                        }
 
5525
                        if (alignment.getHeight() > 0)
 
5526
                        {
 
5527
                // centers can be offgrid, only edges matter
 
5528
                                double aliY = Math.round(centerY / (alignment.getHeight()/2)) * (alignment.getHeight()/2);
 
5529
                                if (aliY != centerY)
 
5530
                                {
 
5531
                                        double newHeight = height + Math.abs(aliY-centerY)*2;
 
5532
                                        Poly rectPoly = new Poly(scaleUp(centerX), scaleUp(aliY), scaleUp(width), scaleUp(newHeight));
 
5533
                                        if (!originalMerge.contains(layer, rectPoly))
 
5534
                                        {
 
5535
                                                if (aliY > centerY) aliY -= alignment.getHeight(); else
 
5536
                                                        aliY += alignment.getHeight();
 
5537
                                                newHeight = height + Math.abs(aliY-centerY)*2;
 
5538
                                                rectPoly = new Poly(scaleUp(centerX), scaleUp(aliY), scaleUp(width), scaleUp(newHeight));
 
5539
                                                if (!originalMerge.contains(layer, rectPoly)) return null;
 
5540
                                        }
 
5541
                                        centerY = aliY;
 
5542
                                        height = newHeight;
 
5543
                                }
 
5544
                        }
 
5545
                }
4139
5546
                Point2D center = new Point2D.Double(centerX, centerY);
4140
 
 
4141
 
                // compute any trace information if the shape is nonmanhattan
4142
 
                EPoint [] newPoints = null;
4143
 
//              if (poly.getBox() == null)
4144
 
//              {
4145
 
//                      // store the trace
4146
 
//                      Point2D [] points = poly.getPoints();
4147
 
//                      newPoints = new EPoint[points.length];
4148
 
//                      for(int i=0; i<points.length; i++)
4149
 
//                              newPoints[i] = new EPoint(points[i].getX() / SCALEFACTOR, points[i].getY() / SCALEFACTOR);
4150
 
//              }
4151
 
                NodeInst ni = createNode(pNp, center, polyBounds.getWidth() / SCALEFACTOR,
4152
 
                        polyBounds.getHeight() / SCALEFACTOR, newPoints, cell);
4153
 
                createdNodes.add(ni);
4154
 
                return createdNodes;
 
5547
                NodeInst ni = createNode(pNp, center, width, height, null, cell);
 
5548
                return ni;
4155
5549
        }
4156
5550
 
4157
5551
        /**
4158
5552
         * Method to clean-up exports.
 
5553
     * @param oldCell the original cell (unextracted)
 
5554
     * @param newCell the new cell
4159
5555
         */
4160
5556
        private void cleanupExports(Cell oldCell, Cell newCell)
4161
5557
        {
4162
5558
                // first restore original exports (which were on pure-layer nodes and must now be placed back)
4163
5559
                for(Export e : exportsToRestore)
4164
5560
                {
4165
 
                        EPoint loc = e.getOriginalPort().getPoly().getCenter();
 
5561
                        EPoint loc = e.getPoly().getCenter();
4166
5562
                        boolean found = false;
4167
5563
                        Rectangle2D bounds = new Rectangle2D.Double(loc.getX(), loc.getY(), 0, 0);
4168
5564
                        for(Iterator<RTBounds> it = newCell.searchIterator(bounds); it.hasNext(); )
4191
5587
                                for(Iterator<PrimitiveNode> it = tech.getNodes(); it.hasNext(); )
4192
5588
                                {
4193
5589
                                        PrimitiveNode pn = it.next();
4194
 
                                        if (pn.getFunction() != PrimitiveNode.Function.PIN) continue;
 
5590
                                        if (!pn.getFunction().isPin()) continue;
4195
5591
                                        if (!sameConnection(e, pn.getPort(0))) continue;
4196
5592
                                        pnUse = pn;
4197
5593
                                        break;
4260
5656
                        }
4261
5657
                        if (exportName != null)
4262
5658
                        {
4263
 
                                exportName = ElectricObject.uniqueObjectName(exportName, cell, PortProto.class, true);
 
5659
                                exportName = ElectricObject.uniqueObjectName(exportName, cell, PortProto.class, true, true);
4264
5660
                                e.rename(exportName);
4265
5661
                        }
4266
5662
                }
4303
5699
        private NodeInst createNode(NodeProto np, Point2D loc, double wid, double hei, EPoint [] points, Cell cell)
4304
5700
        {
4305
5701
                // pins cannot be smaller than their default size
4306
 
                if (np.getFunction() == PrimitiveNode.Function.PIN)
 
5702
                if (np.getFunction().isPin())
4307
5703
                {
4308
5704
                        if (wid < np.getDefWidth()) wid = np.getDefWidth();
4309
5705
                        if (hei < np.getDefHeight()) hei = np.getDefHeight();
4313
5709
                        ni.setTrace(points);
4314
5710
                if (DEBUGSTEPS)
4315
5711
                {
4316
 
                        if (np.getFunction() != PrimitiveNode.Function.PIN)
 
5712
                        if (!np.getFunction().isPin())
4317
5713
                        {
4318
 
                                Poly niPoly = Highlight2.getNodeInstOutline(ni);
 
5714
                                Poly niPoly = Highlight.getNodeInstOutline(ni);
4319
5715
                                addedRectangles.add(ERectangle.fromLambda(niPoly.getBounds2D()));
4320
5716
                        }
4321
5717
                }
4366
5762
                {
4367
5763
                        if (DEBUGSTEPS)
4368
5764
                        {
4369
 
                                if (pNp.getFunction() != PrimitiveNode.Function.PIN)
 
5765
                                if (!pNp.getFunction().isPin())
4370
5766
                                {
4371
 
                                        Poly niPoly = Highlight2.getNodeInstOutline(ni);
 
5767
                                        Poly niPoly = Highlight.getNodeInstOutline(ni);
4372
5768
                                        addedRectangles.add(ERectangle.fromLambda(niPoly.getBounds2D()));
4373
5769
                                }
4374
5770
                        }
4391
5787
                                layer = geometricLayer(layer);
4392
5788
 
4393
5789
                                poly.transform(trans);
4394
 
                                removePolyFromMerge(merge, layer, poly);
 
5790
                                if (Extract.isUsePureLayerNodes() && (layer.getFunction().isPoly() || layer.getFunction().isMetal())) continue;
 
5791
                removePolyFromMerge(merge, layer, poly);
4395
5792
                        }
4396
5793
                }
4397
5794
        }
4401
5798
         * @param ap the arc to create.
4402
5799
         * @param pi1 the first side of the arc.
4403
5800
         * @param pi2 the second side of the arc
4404
 
         * @param width the width of the arc.
4405
 
         * @param noEndExtend true to NOT extend the arc ends.
 
5801
         * @param pt1 the first connection point
 
5802
     * @param pt2 the second connection point
 
5803
     * @param width the width of the arc
 
5804
     * @param noHeadExtend do not extend the head
 
5805
     * @param noTailExtend do not extend the tail
 
5806
     * @param merge the merge to subtract the new arc from
 
5807
     * @return the arc inst created
4406
5808
         */
4407
5809
        private ArcInst realizeArc(ArcProto ap, PortInst pi1, PortInst pi2, Point2D pt1, Point2D pt2, double width,
4408
5810
                boolean noHeadExtend, boolean noTailExtend, PolyMerge merge)
4409
5811
        {
 
5812
                if (alignment != null)
 
5813
                {
 
5814
                        if (alignment.getWidth() > 0)
 
5815
                                width = Math.floor(width / alignment.getWidth()) * alignment.getWidth();
 
5816
                }
 
5817
                if (width == 0) ap = Generic.tech().universal_arc;
4410
5818
                ArcInst ai = ArcInst.makeInstanceBase(ap, width, pi1, pi2, pt1, pt2, null);
4411
5819
                if (ai == null) return null;
4412
5820
 
4441
5849
                        // make sure the geometric database is made up of proper layers
4442
5850
                        layer = geometricLayer(layer);
4443
5851
 
4444
 
                        removePolyFromMerge(merge, layer, poly);
 
5852
                        if (!Extract.isUsePureLayerNodes())
 
5853
                removePolyFromMerge(merge, layer, poly);
4445
5854
                }
4446
5855
                return ai;
4447
5856
        }
4632
6041
                        List<ERectangle> lines = addedBatchLines.get(batchPosition);
4633
6042
                        for(ERectangle er : lines)
4634
6043
                                wnd.addHighlightLine(new Point2D.Double(er.getMinX(), er.getMinY()),
4635
 
                                        new Point2D.Double(er.getMaxX(), er.getMaxY()), cell, false);
 
6044
                                     new Point2D.Double(er.getMaxX(), er.getMaxY()), cell, false, false);
4636
6045
                        wnd.finishedHighlighting();
4637
6046
                }
4638
6047
        }