📄 layercoveragetool.java
字号:
HierarchyEnumerator.enumerateCell(curCell, VarContext.globalContext, visitor, shortResistors); tree.postProcess(true); switch (function) { case MERGE: case IMPLANT: { // With polygons collected, new geometries are calculated boolean noNewNodes = true; boolean isMerge = (function == LCMode.MERGE); Rectangle2D rect; Point2D [] points; // Need to detect if geometry was really modified for (Layer layer : tree.getKeySet()) { Collection<PolyBase> set = tree.getObjects(layer, !isMerge, true); Set<PolyBase> polySet = (function == LCMode.IMPLANT) ? originalPolygons.get(layer) : null; List<Rectangle2D> newImplants = new ArrayList<Rectangle2D>(); // Ready to create new implants. for (PolyBase polyB : set) { points = polyB.getPoints(); rect = polyB.getBounds2D(); // One of the original elements if (polySet != null) { Object[] array = polySet.toArray(); boolean foundOrigPoly = false; for (Object poly : array) { foundOrigPoly = polyB.polySame((PolyBase)poly); if (foundOrigPoly) break; } if (foundOrigPoly) continue; } if (isMerge) { // Adding the new implant. New implant not assigned to any local variable Point2D center = new Point2D.Double(rect.getCenterX(), rect.getCenterY()); PrimitiveNode priNode = layer.getPureLayerNode(); NodeInst node = NodeInst.makeInstance(priNode, center, rect.getWidth(), rect.getHeight(), curCell); nodesToExamine.add(node); EPoint [] ePoints = new EPoint[points.length]; for(int j=0; j<points.length; j++) ePoints[j] = new EPoint(points[j].getX(), points[j].getY()); node.setTrace(ePoints); } else { newImplants.add(rect); } noNewNodes = false; } if (function == LCMode.IMPLANT) { // merge when close to avoid notch errors DRCTemplate rule = DRC.getSpacingRule(layer, null, layer, null, false, -1, 10, 100); if (rule != null) { double dist = rule.getValue(0); for(int i=0; i<newImplants.size(); i++) { Rectangle2D r = newImplants.get(i); boolean merged = false; for(int j=i+1; j<newImplants.size(); j++) { Rectangle2D oR = newImplants.get(j); if (r.getMinX()-dist > oR.getMaxX() || oR.getMinX()-dist > r.getMaxX() || r.getMinY()-dist > oR.getMaxY() || oR.getMinY()-dist > r.getMaxY()) continue; // they are too close: merge them double lx = Math.min(r.getMinX(), oR.getMinX()); double hx = Math.max(r.getMaxX(), oR.getMaxX()); double ly = Math.min(r.getMinY(), oR.getMinY()); double hy = Math.max(r.getMaxY(), oR.getMaxY()); r.setRect(lx, ly, hx-lx, hy-ly); newImplants.remove(j); merged = true; break; } if (merged) i--; } } PrimitiveNode priNode = layer.getPureLayerNode(); for(Rectangle2D r : newImplants) { // TODO Do not create if it is covered by original geometry Point2D center = new Point2D.Double(r.getCenterX(), r.getCenterY()); NodeInst node = NodeInst.makeInstance(priNode, center, r.getWidth(), r.getHeight(), curCell); nodesToExamine.add(node); node.setHardSelect(); } } } curCell.killNodes(nodesToDelete); if (noNewNodes) System.out.println("No new areas added"); } break; case AREA: case NETWORK: { double lambdaSqr = 1; // lambdaofcell(np); Rectangle2D bbox = curCell.getBounds(); double totalArea = (bbox.getHeight()*bbox.getWidth())/lambdaSqr; // Traversing tree with merged geometry and sorting layers per name first List<Layer> list = new ArrayList<Layer>(tree.getKeySet()); Collections.sort(list, Layer.layerSortByName); for (Layer layer : list) { Collection<PolyBase> set = tree.getObjects(layer, false, true); if (geoms != null && geoms.onlyThisLayer != null) { if (layer != geoms.onlyThisLayer) continue; // ignore this layer // Add all elements if (overlapPoint == null) nodesToExamine.addAll(set); else { // they must be connected for (PolyBase p : set) { if (p.contains(overlapPoint)) nodesToExamine.add(p); } } } double layerArea = 0; double perimeter = 0; // Get all objects and sum the area for (PolyBase poly : set) { layerArea += poly.getArea(); perimeter += poly.getPerimeter(); } layerArea /= lambdaSqr; perimeter /= 2; if (geoms != null) geoms.addLayer(layer, layerArea, perimeter); else System.out.println("Layer " + layer.getName() + " covers " + TextUtils.formatDouble(layerArea) + " square lambda (" + TextUtils.formatDouble((layerArea/totalArea)*100, 2) + "%)"); } geoms.setTotalArea(totalArea); if (geoms != null) geoms.print(); else System.out.println("Cell is " + TextUtils.formatDouble(totalArea, 2) + " square lambda"); } break; default: System.out.println("Error in LayerCoverage: function not implemented"); } return true; } } /************************************************************************ * LayerCoverageJob Class ************************************************************************/ private static class LayerCoverageJob extends Job { private Cell cell; private LCMode func; private GeometryHandler.GHMode mode; private GeometryOnNetwork geoms; private List<Object> nodesAdded; private Point2D overlapPoint; // to get to crop the search if a given bbox is not null public LayerCoverageJob(Cell cell, Job.Type jobType, LCMode func, GeometryHandler.GHMode mode, GeometryOnNetwork geoms, Point2D overlapPoint) { super("Layer Coverage on " + cell, User.getUserTool(), jobType, null, null, Priority.USER); this.cell = cell; this.func = func; this.mode = mode; this.geoms = geoms; this.overlapPoint = overlapPoint; setReportExecutionFlag(true); } public boolean doIt() throws JobException { LayerCoverageData data = new LayerCoverageData(this, cell, func, mode, geoms, null, overlapPoint); boolean done = data.doIt(); if (func == LCMode.IMPLANT || (func == LCMode.NETWORK && geoms != null)) { nodesAdded = new ArrayList<Object>(); nodesAdded.addAll(data.getNodesToHighlight()); if (func == LCMode.IMPLANT) fieldVariableChanged("nodesAdded"); } return done; } public void terminateOK() { // For implant highlight the new nodes if (func == LCMode.IMPLANT) { EditWindow_ wnd = Job.getUserInterface().getCurrentEditWindow_(); if (wnd == null) return; // no GUI present if (nodesAdded == null) return; // nothing to show for (Object node : nodesAdded) { wnd.addElectricObject((NodeInst)node, cell); } } } } /************************************************************************ * AreaCoverageJob Class ************************************************************************/ private static class AreaCoverageJob extends Job { private Cell curCell; private double deltaX, deltaY; private double width, height; private GeometryHandler.GHMode mode; private Map<Layer,Double> internalMap; public AreaCoverageJob(Cell cell, GeometryHandler.GHMode mode, double width, double height, double deltaX, double deltaY) { super("Layer Coverage", User.getUserTool(), Type.EXAMINE, null, null, Priority.USER); this.curCell = cell; this.mode = mode; this.width = width; this.height = height; this.deltaX = deltaX; this.deltaY = deltaY; setReportExecutionFlag(true); // Want to report statistics } public boolean doIt() throws JobException { ErrorLogger errorLogger = ErrorLogger.newInstance("Area Coverage"); Rectangle2D bBoxOrig = curCell.getBounds(); double maxY = bBoxOrig.getMaxY(); double maxX = bBoxOrig.getMaxX(); // if negative or zero values -> only once if (deltaX <= 0) deltaX = bBoxOrig.getWidth(); if (deltaY <= 0) deltaY = bBoxOrig.getHeight(); if (width <= 0) width = bBoxOrig.getWidth(); if (height <= 0) height = bBoxOrig.getHeight(); internalMap = new HashMap<Layer,Double>();// fieldVariableChanged("internalMap"); for (double posY = bBoxOrig.getMinY(); posY < maxY; posY += deltaY) { for (double posX = bBoxOrig.getMinX(); posX < maxX; posX += deltaX) { Rectangle2D box = new Rectangle2D.Double(posX, posY, width, height); GeometryOnNetwork geoms = new GeometryOnNetwork(curCell, null, 1, true, null); System.out.println("Calculating Coverage on cell '" + curCell.getName() + "' for area (" + DBMath.round(posX) + "," + DBMath.round(posY) + ") (" + DBMath.round(box.getMaxX()) + "," + DBMath.round(box.getMaxY()) + ")"); LayerCoverageData data = new LayerCoverageData(this, curCell, LCMode.AREA, mode, geoms, box, null); if (!data.doIt()) // aborted by user { return false; // didn't finish } geoms.analyzeCoverage(box, errorLogger); for (int i = 0; i < geoms.layers.size(); i++) { Layer layer = geoms.layers.get(i); Double area = geoms.areas.get(i); Double oldV = internalMap.get(layer); double newV = area.doubleValue(); if (oldV != null) newV += oldV.doubleValue(); internalMap.put(layer, new Double(newV)); } } } errorLogger.termLogging(true); return true; } public Map<Layer,Double> getDataInfo() { return internalMap; } } public enum LCMode // LC = LayerCoverageTool mode { AREA, // function Layer Coverage MERGE, // Generic merge polygons function IMPLANT, // Coverage implants NETWORK // List Geometry on Network function } /************************************************************************ * LayerVisitor Class ************************************************************************/ public static class LayerVisitor extends HierarchyEnumerator.Visitor { private Job parentJob; private GeometryHandler tree; private Set<NodeInst> deleteList; // Only used for coverage Implants. New coverage implants are pure primitive nodes private final LCMode function; private Map<Layer,Set<PolyBase>> originalPolygons; private Set<Network> netSet; // For network type, rest is null private Rectangle2D origBBox; private Area origBBoxArea; // Area is always in coordinates of top cell private Layer onlyThisLayer; private GeometryOnNetwork geoms; public LayerVisitor(Job job, GeometryHandler t, Set<NodeInst> delList, LCMode func, Map<Layer, Set<PolyBase>> original, Set<Network> netSet, Rectangle2D bBox, Layer onlyThisLayer, GeometryOnNetwork geoms) { this.parentJob = job; this.tree = t; this.deleteList = delList; this.function = func; this.originalPolygons = original; this.netSet = netSet; this.origBBox = bBox; origBBoxArea = (bBox != null) ? new Area(origBBox) : null; this.onlyThisLayer = onlyThisLayer; this.geoms = geoms; } /** * Determines if function of given layer is applicable for the corresponding operation */ private boolean isValidFunction(Layer layer, LCMode function) { if (onlyThisLayer != null && layer != onlyThisLayer) return false; Layer.Function func = layer.getFunction(); switch (function) { case MERGE: case NETWORK: return (true); case IMPLANT: return (func.isSubstrate()); case AREA: return (func.isPoly() || func.isMetal()); default: return (false); } } /** * In case of non null bounding box, it will undo the * transformation * @param info */ public void exitCell(HierarchyEnumerator.CellInfo info) { } private boolean doesIntersectBoundingBox(Rectangle2D rect, HierarchyEnumerator.CellInfo info) { // Default case when no bounding box is used to crop the geometry if (origBBox == null) return true; // only because I need to transform the points. PolyBase polyRect = new PolyBase(rect); // To avoid transformation while traversing the hierarchy polyRect.transform(info.getTransformToRoot()); rect = polyRect.getBounds2D(); return rect.intersects(origBBox); } private boolean isJobAborted() { return (parentJob != null && parentJob.checkAbort()); } public boolean enterCell(HierarchyEnumerator.CellInfo info) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -