1
/* -*- tab-width: 4 -*-
3
* Electric(tm) VLSI Design System
5
* File: VectorDrawing.java
7
* Copyright (c) 2005 Sun Microsystems and Static Free Software
9
* Electric(tm) is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 3 of the License, or
12
* (at your option) any later version.
14
* Electric(tm) is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with Electric(tm); see the file COPYING. If not, write to
21
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22
* Boston, Mass 02111-1307, USA.
24
package com.sun.electric.tool.user.redisplay;
26
import com.sun.electric.database.geometry.DBMath;
27
import com.sun.electric.database.geometry.EGraphics;
28
import com.sun.electric.database.geometry.GenMath;
29
import com.sun.electric.database.geometry.Orientation;
30
import com.sun.electric.database.geometry.Poly;
31
import com.sun.electric.database.geometry.GenMath.MutableDouble;
32
import com.sun.electric.database.hierarchy.Cell;
33
import com.sun.electric.database.hierarchy.Export;
34
import com.sun.electric.database.text.TextUtils;
35
import com.sun.electric.database.topology.NodeInst;
36
import com.sun.electric.database.variable.TextDescriptor;
37
import com.sun.electric.database.variable.VarContext;
38
import com.sun.electric.technology.Layer;
39
import com.sun.electric.technology.Technology;
40
import com.sun.electric.tool.Job;
41
import com.sun.electric.tool.user.User;
42
import com.sun.electric.tool.user.ui.TopLevel;
44
import java.awt.Color;
45
import java.awt.Dimension;
46
import java.awt.Point;
47
import java.awt.Rectangle;
48
import java.awt.geom.AffineTransform;
49
import java.awt.geom.Point2D;
50
import java.awt.geom.Rectangle2D;
51
import java.util.Arrays;
52
import java.util.HashMap;
53
import java.util.Iterator;
54
import java.util.List;
59
* Class to do rapid redraw by caching the vector coordinates of all objects.
63
private static final boolean TAKE_STATS = false;
64
private static final boolean DEBUGIMAGES = false;
65
private static final int MAXGREEKSIZE = 25;
66
private static final int SCALE_SH = 20;
68
/** the rendering object */ private PixelDrawing offscreen;
69
/** the window scale */ private float scale;
70
/** the window scale */ private float scale_;
71
/** the window scale and pan factor */ private float factorX, factorY;
72
private int factorX_, factorY_;
73
private int scale_int;
74
/** true if "peeking" and expanding to the bottom */ private boolean fullInstantiate;
75
/** A List of NodeInsts to the cell being in-place edited. */private List<NodeInst> inPlaceNodePath;
76
/** The current cell being in-place edited. */ private Cell inPlaceCurrent;
77
/** time that rendering started */ private long startTime;
78
/** true if the user has been told of delays */ private boolean takingLongTime;
79
/** true to stop rendering */ private boolean stopRendering;
80
/** the half-sizes of the window (in pixels) */ private int szHalfWidth, szHalfHeight;
81
/** the screen clipping */ private int screenLX, screenHX, screenLY, screenHY;
82
/** statistics */ private int boxCount, tinyBoxCount, lineBoxCount, lineCount, polygonCount;
83
/** statistics */ private int crossCount, textCount, circleCount, arcCount;
84
/** statistics */ private int subCellCount, tinySubCellCount;
85
/** the threshold of object sizes */ private float maxObjectSize;
86
/** the threshold of text sizes */ private float maxTextSize;
87
/** the maximum cell size above which no greeking */ private float maxCellSize;
89
/** temporary objects (saves allocation) */ private Point tempPt1 = new Point(), tempPt2 = new Point();
90
/** temporary objects (saves allocation) */ private Point tempPt3 = new Point();
91
/** temporary object (saves allocation) */ private Rectangle tempRect = new Rectangle();
92
/** the color of text */ private Color textColor;
94
/** the object that draws the rendered screen */ private static VectorDrawing topVD;
95
/** location for debugging icon displays */ private static int debugXP, debugYP;
97
private static EGraphics textGraphics = new EGraphics(false, false, null, 0, 0,0,0, 1.0,true,
98
new int[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
99
private static EGraphics instanceGraphics = new EGraphics(false, false, null, 0, 0,0,0, 1.0,true,
100
new int[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
101
private static EGraphics portGraphics = new EGraphics(false, false, null, 0, 255,0,0, 1.0,true,
102
new int[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
104
// ************************************* TOP LEVEL *************************************
107
* Constructor creates a VectorDrawing object for a given EditWindow.
108
* @param wnd the EditWindow associated with this VectorDrawing.
110
public VectorDrawing()
115
* Main entry point for drawing a cell.
116
* @param offscreen offscreen buffer
117
* @param scale edit window scale
118
* @param offset the offset factor for this window
119
* @param cell the cell to draw
120
* @param fullInstantiate true to draw all the way to the bottom of the hierarchy.
121
* @param inPlaceNodePath a List of NodeInsts to the cell being in-place edited
122
* @param screenLimit the area in the cell to display (null to show all).
124
public void render(PixelDrawing offscreen, double scale, Point2D offset, Cell cell, boolean fullInstantiate,
125
List<NodeInst> inPlaceNodePath, Cell inPlaceCurrent, Rectangle screenLimit, VarContext context)
128
textGraphics.setColor(new Color(User.getColor(User.ColorPrefType.TEXT)));
129
instanceGraphics.setColor(new Color(User.getColor(User.ColorPrefType.INSTANCE)));
130
textColor = new Color(User.getColor(User.ColorPrefType.TEXT) & 0xFFFFFF);
132
// see if any layers are being highlighted/dimmed
133
this.offscreen = offscreen;
134
offscreen.highlightingLayers = false;
135
for(Iterator<Layer> it = Technology.getCurrent().getLayers(); it.hasNext(); )
137
Layer layer = it.next();
138
if (layer.isDimmed())
140
offscreen.highlightingLayers = true;
146
Dimension sz = offscreen.getSize();
147
this.scale = (float)scale;
148
scale_ = (float)(scale/DBMath.GRID);
149
maxObjectSize = (float)User.getGreekSizeLimit() / this.scale;
150
maxTextSize = maxObjectSize / (float)User.getGlobalTextScale();
151
double screenArea = sz.getWidth()/scale * sz.getHeight()/scale;
152
maxCellSize = (float)(User.getGreekCellSizeLimit() * screenArea);
155
startTime = System.currentTimeMillis();
156
long initialUsed = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
157
takingLongTime = false;
158
boxCount = tinyBoxCount = lineBoxCount = lineCount = polygonCount = 0;
159
crossCount = textCount = circleCount = arcCount = 0;
160
subCellCount = tinySubCellCount = 0;
163
this.fullInstantiate = fullInstantiate;
164
this.inPlaceNodePath = inPlaceNodePath;
165
this.inPlaceCurrent = inPlaceCurrent;
166
szHalfWidth = sz.width / 2;
167
szHalfHeight = sz.height / 2;
168
screenLX = 0; screenHX = sz.width;
169
screenLY = 0; screenHY = sz.height;
170
factorX = (float)(offset.getX()*DBMath.GRID - szHalfWidth/scale_);
171
factorY = (float)(offset.getY()*DBMath.GRID + szHalfHeight/scale_);
172
factorX_ = (int)factorX;
173
factorY_ = (int)factorY;
174
scale_int = (int)(scale_ * (1 << SCALE_SH));
175
if (screenLimit != null)
177
screenLX = screenLimit.x;
178
if (screenLX < 0) screenLX = 0;
179
screenHX = screenLimit.x + screenLimit.width;
180
if (screenHX >= sz.width) screenHX = sz.width-1;
181
screenLY = screenLimit.y;
182
if (screenLY < 0) screenLY = 0;
183
screenHY = screenLimit.y + screenLimit.height;
184
if (screenHY >= sz.height) screenHY = sz.height-1;
187
// draw the screen, starting with the top cell
188
stopRendering = false;
191
VectorCache.VectorCell topVC = drawCell(cell, Orientation.IDENT, context);
193
render(topVC, 0, 0, context, 0);
194
drawList(0, 0, topVC.getTopOnlyShapes(), 0, false);
195
} catch (AbortRenderingException e)
202
TopLevel.setBusyCursor(false);
203
System.out.println("Done");
206
if (TAKE_STATS && Job.getDebug())
208
long curUsed = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
209
long memUsed = curUsed - initialUsed;
210
long renderTime = System.currentTimeMillis() - startTime;
211
System.out.println("Time to render: "+TextUtils.getElapsedTime(renderTime) + " Memory Used: "+ memUsed);
212
System.out.println(" Rendered "+boxCount+" boxes ("+tinyBoxCount+" tiny, "+lineBoxCount+" lines), "+
213
lineCount+" lines, "+polygonCount+" polys, "+crossCount+" crosses, "+
214
textCount+" texts, "+circleCount+" circles, "+arcCount+" arcs, "+
215
subCellCount+" subcells ("+tinySubCellCount+" tiny)");
220
* Main entry point for drawing a tech menu entry.
221
* @param offscreen offscreen buffer
222
* @param scale edit window scale
223
* @param offset the offset factor for this window
224
* @param shapes shapes of tech menu
225
* @param forceVisible true to force all layers to be drawn (regardless of user settings)
227
public void render(PixelDrawing offscreen, double scale, Point2D offset, VectorCache.VectorBase[] shapes, boolean forceVisible)
230
textGraphics.setColor(new Color(User.getColor(User.ColorPrefType.TEXT)));
231
textColor = new Color(User.getColor(User.ColorPrefType.TEXT) & 0xFFFFFF);
233
// see if any layers are being highlighted/dimmed
234
this.offscreen = offscreen;
237
Dimension sz = offscreen.getSize();
238
this.scale = (float)scale;
239
scale_ = (float)(scale/DBMath.GRID);
242
szHalfWidth = sz.width / 2;
243
szHalfHeight = sz.height / 2;
244
screenLX = 0; screenHX = sz.width;
245
screenLY = 0; screenHY = sz.height;
246
factorX = (float)(offset.getX()*DBMath.GRID - szHalfWidth/scale_);
247
factorY = (float)(offset.getY()*DBMath.GRID + szHalfHeight/scale_);
248
factorX_ = (int)factorX;
249
factorY_ = (int)factorY;
250
scale_int = (int)(scale_ * (1 << SCALE_SH));
252
// draw the screen, starting with the top cell
255
List<VectorCache.VectorBase> shapeList = Arrays.asList(shapes);
256
drawList(0, 0, shapeList, 0, forceVisible);
257
} catch (AbortRenderingException e)
263
* Class to define a signal to abort rendering.
265
class AbortRenderingException extends Exception {}
268
* Method to request that the current rendering be aborted because it must be restarted.
271
public void abortRendering()
273
stopRendering = true;
277
* Method to recursively render a cached cell.
278
* @param vc the cached cell to render
279
* @param oX the X offset for rendering the cell (in database grid coordinates).
280
* @param oY the Y offset for rendering the cell (in database grid coordinates).
281
* @param context the VarContext for this point in the rendering.
282
* @param level: 0=top-level cell in window; 1=low level cell; -1=greeked cell.
284
private void render(VectorCache.VectorCell vc, int oX, int oY, VarContext context, int level)
285
throws AbortRenderingException
287
// render main list of shapes
288
drawList(oX, oY, vc.filledShapes, level, false);
289
drawList(oX, oY, vc.shapes, level, false);
291
// now render subcells
292
Cell cell = VectorCache.theCache.database.getCell(vc.vcg.cellId);
293
for(VectorCache.VectorSubCell vsc : vc.subCells)
295
if (stopRendering) throw new AbortRenderingException();
296
NodeInst ni = cell.getNodeById(vsc.n.nodeId);
297
Cell subCell = (Cell)ni.getProto();
300
// get instance location
301
int soX = vsc.offsetX + oX;
302
int soY = vsc.offsetY + oY;
303
VectorCache.VectorCell subVC = VectorCache.theCache.findVectorCell(vsc.subCellId, vc.orient.concatenate(vsc.n.orient));
304
gridToScreen(subVC.lX + soX, subVC.hY + soY, tempPt1);
305
gridToScreen(subVC.hX + soX, subVC.lY + soY, tempPt2);
311
// see if the subcell is clipped
312
if (hX < screenLX || lX >= screenHX) continue;
313
if (hY < screenLY || lY >= screenHY) continue;
315
// see if the cell is too tiny to draw
316
if (subVC.vcg.cellMinSize < maxObjectSize)
318
Orientation thisOrient = vsc.n.orient;
319
Orientation recurseTrans = vc.orient.concatenate(thisOrient);
320
VarContext subContext = context.push(ni);
321
VectorCache.VectorCell subVC_ = drawCell(subCell, recurseTrans, subContext);
322
assert subVC_ == subVC;
323
makeGreekedImage(subVC);
325
int fadeColor = getFadeColor(subVC, subContext);
326
drawTinyBox(lX, hX, lY, hY, fadeColor, subVC);
331
// see if drawing "down in place"
332
boolean onPathDown = false;
333
if (inPlaceNodePath != null)
335
for(NodeInst niOnPath : inPlaceNodePath)
337
if (niOnPath.getProto().getId() == vsc.subCellId)
345
// see if cell contents should be drawn
346
boolean expanded = ni.isExpanded() || fullInstantiate;
348
// if not expanded, but viewing this cell in-place, expand it
349
if (!expanded && onPathDown) expanded = true;
353
Orientation thisOrient = vsc.n.orient;
354
Orientation recurseTrans = vc.orient.concatenate(thisOrient);
355
VarContext subContext = context.push(ni);
356
VectorCache.VectorCell subVC_ = drawCell(subCell, recurseTrans, subContext);
357
assert subVC_ == subVC;
359
// expanded cells may be replaced with greeked versions (not icons)
360
if (!subCell.isIcon())
362
// may also be "tiny" if all features in the cell are tiny
363
boolean allFeaturesTiny = subVC.maxFeatureSize > 0 && subVC.maxFeatureSize < maxObjectSize &&
364
subVC.vcg.cellArea < maxCellSize && isContentsTiny(subCell, subVC, recurseTrans, context);
366
// may also be "tiny" if the cell is smaller than the greeked image
367
boolean smallerThanGreek = User.isUseCellGreekingImages() && hX-lX <= MAXGREEKSIZE && hY-lY <= MAXGREEKSIZE;
368
if (allFeaturesTiny || smallerThanGreek)
370
makeGreekedImage(subVC);
371
int fadeColor = getFadeColor(subVC, context);
372
drawTinyBox(lX, hX, lY, hY, fadeColor, subVC);
378
int subLevel = level;
379
if (subLevel == 0) subLevel = 1;
380
render(subVC, soX, soY, subContext, subLevel);
383
// now draw with the proper line type
384
int[] op = subVC.outlinePoints;
385
int p1x = op[0] + soX;
386
int p1y = op[1] + soY;
387
int p2x = op[2] + soX;
388
int p2y = op[3] + soY;
389
int p3x = op[4] + soX;
390
int p3y = op[5] + soY;
391
int p4x = op[6] + soX;
392
int p4y = op[7] + soY;
393
gridToScreen(p1x, p1y, tempPt1); gridToScreen(p2x, p2y, tempPt2);
394
offscreen.drawLine(tempPt1, tempPt2, null, instanceGraphics, 0, false);
395
gridToScreen(p2x, p2y, tempPt1); gridToScreen(p3x, p3y, tempPt2);
396
offscreen.drawLine(tempPt1, tempPt2, null, instanceGraphics, 0, false);
397
gridToScreen(p3x, p3y, tempPt1); gridToScreen(p4x, p4y, tempPt2);
398
offscreen.drawLine(tempPt1, tempPt2, null, instanceGraphics, 0, false);
399
gridToScreen(p1x, p1y, tempPt1); gridToScreen(p4x, p4y, tempPt2);
400
offscreen.drawLine(tempPt1, tempPt2, null, instanceGraphics, 0, false);
402
// draw the instance name
403
if (User.isTextVisibilityOnInstance())
405
tempRect.setBounds(lX, lY, hX-lX, hY-lY);
406
TextDescriptor descript = vsc.n.protoDescriptor;
407
offscreen.drawText(tempRect, Poly.Type.TEXTBOX, descript, subCell.describe(false), null, textGraphics, false);
410
if (level == 0 || onPathDown || inPlaceCurrent == cell)
411
drawPortList(vsc, subVC, soX, soY, ni.isExpanded());
416
* Method to draw a list of cached shapes.
417
* @param oX the X offset to draw the shapes (in database grid coordinates).
418
* @param oY the Y offset to draw the shapes (in database grid coordinates).
419
* @param shapes the List of shapes (VectorBase objects).
420
* @param level: 0=top-level cell in window; 1=low level cell; -1=greeked cell.
421
* @param forceVisible true to force all layers to be drawn (regardless of user settings)
423
private void drawList(int oX, int oY, List<VectorCache.VectorBase> shapes, int level, boolean forceVisible)
424
throws AbortRenderingException
426
// render all shapes in reverse order (because PixelDrawing don't overwrite opaque layers)
427
for (int k = shapes.size() - 1; k >= 0; k--)
429
VectorCache.VectorBase vb = shapes.get(k);
430
if (stopRendering) throw new AbortRenderingException();
432
// get visual characteristics of shape
433
Layer layer = vb.layer;
434
boolean dimmed = false;
439
// greeked cells ignore cut and implant layers
440
Layer.Function fun = layer.getFunction();
441
if (fun.isContact() || fun.isWell() || fun.isSubstrate()) continue;
443
if (!forceVisible && !layer.isVisible()) continue;
444
dimmed = layer.isDimmed();
446
byte [][] layerBitMap = null;
447
EGraphics graphics = vb.graphics;
448
if (graphics != null)
450
int layerNum = graphics.getTransparentLayer() - 1;
451
if (layerNum < offscreen.numLayerBitMaps) layerBitMap = offscreen.getLayerBitMap(layerNum);
455
if (vb instanceof VectorCache.VectorManhattan)
458
VectorCache.VectorManhattan vm = (VectorCache.VectorManhattan)vb;
460
double maxSize = maxObjectSize*DBMath.GRID;
464
Layer.Function fun = layer.getFunction();
465
if (fun.isImplant() || fun.isSubstrate())
467
// well and substrate layers are made smaller so that they "greek" sooner
470
} else if (vm.graphics != null) {
471
fadeCol = vm.graphics.getRGB();
474
for (int i = 0; i < vm.coords.length; i += 4) {
475
int c1X = vm.coords[i];
476
int c1Y = vm.coords[i+1];
477
int c2X = vm.coords[i+2];
478
int c2Y = vm.coords[i+3];
481
if (dX < maxSize || dY < maxSize)
483
if (fadeCol < 0) continue;
484
if (dX < maxSize && dY < maxSize)
486
// both dimensions tiny: just draw a dot
487
gridToScreen(c1X+oX, c1Y+oY, tempPt1);
490
if (x < screenLX || x >= screenHX) continue;
491
if (y < screenLY || y >= screenHY) continue;
492
offscreen.drawPoint(x, y, null, fadeCol);
496
// one dimension tiny: draw a line
497
gridToScreen(c1X+oX, c2Y+oY, tempPt1);
498
gridToScreen(c2X+oX, c1Y+oY, tempPt2);
499
assert tempPt1.x <= tempPt2.x && tempPt1.y <= tempPt2.y;
504
if (hX < screenLX || lX >= screenHX) continue;
505
if (hY < screenLY || lY >= screenHY) continue;
506
drawTinyBox(lX, hX, lY, hY, fadeCol, null);
512
// determine coordinates of rectangle on the screen
513
gridToScreen(c1X+oX, c2Y+oY, tempPt1);
514
gridToScreen(c2X+oX, c1Y+oY, tempPt2);
515
assert tempPt1.x <= tempPt2.x && tempPt1.y <= tempPt2.y;
521
// reject if completely off the screen
522
if (hX < screenLX || lX >= screenHX) continue;
523
if (hY < screenLY || lY >= screenHY) continue;
526
if (lX < screenLX) lX = screenLX;
527
if (hX >= screenHX) hX = screenHX-1;
528
if (lY < screenLY) lY = screenLY;
529
if (hY >= screenHY) hY = screenHY-1;
532
offscreen.drawBox(lX, hX, lY, hY, layerBitMap, graphics, dimmed);
534
} else if (vb instanceof VectorCache.VectorLine)
537
VectorCache.VectorLine vl = (VectorCache.VectorLine)vb;
539
// determine coordinates of line on the screen
540
gridToScreen(vl.fX+oX, vl.fY+oY, tempPt1);
541
gridToScreen(vl.tX+oX, vl.tY+oY, tempPt2);
543
// clip and draw the line
544
offscreen.drawLine(tempPt1, tempPt2, layerBitMap, graphics, vl.texture, dimmed);
545
} else if (vb instanceof VectorCache.VectorPolygon)
548
VectorCache.VectorPolygon vp = (VectorCache.VectorPolygon)vb;
549
Point [] intPoints = new Point[vp.points.length];
550
for(int i=0; i<vp.points.length; i++)
552
intPoints[i] = new Point();
553
gridToScreen(vp.points[i].x+oX, vp.points[i].y+oY, intPoints[i]);
555
Point [] clippedPoints = GenMath.clipPoly(intPoints, screenLX, screenHX-1, screenLY, screenHY-1);
556
offscreen.drawPolygon(clippedPoints, layerBitMap, graphics, dimmed);
557
} else if (vb instanceof VectorCache.VectorCross)
560
VectorCache.VectorCross vcr = (VectorCache.VectorCross)vb;
561
gridToScreen(vcr.x+oX, vcr.y+oY, tempPt1);
563
if (vcr.small) size = 3;
564
offscreen.drawLine(new Point(tempPt1.x-size, tempPt1.y), new Point(tempPt1.x+size, tempPt1.y), null, graphics, 0, dimmed);
565
offscreen.drawLine(new Point(tempPt1.x, tempPt1.y-size), new Point(tempPt1.x, tempPt1.y+size), null, graphics, 0, dimmed);
566
} else if (vb instanceof VectorCache.VectorText)
568
VectorCache.VectorText vt = (VectorCache.VectorText)vb;
571
case VectorCache.VectorText.TEXTTYPEARC:
572
if (!User.isTextVisibilityOnArc()) continue;
574
case VectorCache.VectorText.TEXTTYPENODE:
575
if (!User.isTextVisibilityOnNode()) continue;
577
case VectorCache.VectorText.TEXTTYPECELL:
578
if (!User.isTextVisibilityOnCell()) continue;
580
case VectorCache.VectorText.TEXTTYPEEXPORT:
581
if (!User.isTextVisibilityOnExport()) continue;
583
case VectorCache.VectorText.TEXTTYPEANNOTATION:
584
if (!User.isTextVisibilityOnAnnotation()) continue;
586
case VectorCache.VectorText.TEXTTYPEINSTANCE:
587
if (!User.isTextVisibilityOnInstance()) continue;
590
if (vt.height < maxTextSize) continue;
592
String drawString = vt.str;
593
int lX = vt.bounds.x;
594
int lY = vt.bounds.y;
595
int hX = lX + vt.bounds.width;
596
int hY = lY + vt.bounds.height;
597
gridToScreen(lX + oX, hY + oY, tempPt1);
598
gridToScreen(hX + oX, lY + oY, tempPt2);
603
// int lX, hX, lY, hY;
604
// if (tempPt1.x < tempPt2.x) { lX = tempPt1.x; hX = tempPt2.x; } else
605
// { lX = tempPt2.x; hX = tempPt1.x; }
606
// if (tempPt1.y < tempPt2.y) { lY = tempPt1.y; hY = tempPt2.y; } else
607
// { lY = tempPt2.y; hY = tempPt1.y; }
609
// for ports, switch between the different port display methods
610
// if (vt.textType == VectorCache.VectorText.TEXTTYPEPORT)
612
// int portDisplayLevel = User.getPortDisplayLevel();
613
// Color portColor = vt.e.getBasePort().getPortColor();
614
// if (vt.ni.isExpanded()) portColor = textColor;
615
// if (portColor != null) portGraphics.setColor(portColor);
616
// int cX = (lX + hX) / 2;
617
// int cY = (lY + hY) / 2;
618
// if (portDisplayLevel == 2)
620
// // draw port as a cross
622
// offscreen.drawLine(new Point(cX-size, cY), new Point(cX+size, cY), null, portGraphics, 0, false);
623
// offscreen.drawLine(new Point(cX, cY-size), new Point(cX, cY+size), null, portGraphics, 0, false);
628
// // draw port as text
629
// if (portDisplayLevel == 1) drawString = vt.e.getShortName(); else
630
// drawString = vt.e.getName();
631
// graphics = portGraphics;
632
// layerBitMap = null;
636
if (vt.textType == VectorCache.VectorText.TEXTTYPEEXPORT && vt.basePort != null)
638
if (!vt.basePort.getParent().isVisible()) continue;
639
int exportDisplayLevel = User.getExportDisplayLevel();
640
if (exportDisplayLevel == 2)
642
// draw export as a cross
643
int cX = (lX + hX) / 2;
644
int cY = (lY + hY) / 2;
646
offscreen.drawLine(new Point(cX-size, cY), new Point(cX+size, cY), null, textGraphics, 0, false);
647
offscreen.drawLine(new Point(cX, cY-size), new Point(cX, cY+size), null, textGraphics, 0, false);
652
// draw export as text
653
if (exportDisplayLevel == 1)
654
drawString = Export.getShortName(drawString);
655
graphics = textGraphics;
660
tempRect.setBounds(lX, lY, hX-lX, hY-lY);
661
offscreen.drawText(tempRect, vt.style, vt.descript, drawString, layerBitMap, graphics, dimmed);
662
} else if (vb instanceof VectorCache.VectorCircle)
665
VectorCache.VectorCircle vci = (VectorCache.VectorCircle)vb;
666
gridToScreen(vci.cX+oX, vci.cY+oY, tempPt1);
667
gridToScreen(vci.eX+oX, vci.eY+oY, tempPt2);
670
case 0: offscreen.drawCircle(tempPt1, tempPt2, layerBitMap, graphics, dimmed); break;
671
case 1: offscreen.drawThickCircle(tempPt1, tempPt2, layerBitMap, graphics, dimmed); break;
672
case 2: offscreen.drawDisc(tempPt1, tempPt2, layerBitMap, graphics, dimmed); break;
674
} else if (vb instanceof VectorCache.VectorCircleArc)
677
VectorCache.VectorCircleArc vca = (VectorCache.VectorCircleArc)vb;
678
gridToScreen(vca.cX+oX, vca.cY+oY, tempPt1);
679
gridToScreen(vca.eX1+oX, vca.eY1+oY, tempPt2);
680
gridToScreen(vca.eX2+oX, vca.eY2+oY, tempPt3);
681
offscreen.drawCircleArc(tempPt1, tempPt2, tempPt3, vca.thick, layerBitMap, graphics, dimmed);
687
* Method to draw a list of cached port shapes.
688
* @param oX the X offset to draw the shapes (in database grid coordinates).
689
* @param oY the Y offset to draw the shapes (in database grid coordinates).
690
* @parem true to draw a list on expanded instance
692
private void drawPortList(VectorCache.VectorSubCell vsc, VectorCache.VectorCell subVC_, int oX, int oY, boolean expanded)
693
throws AbortRenderingException
695
if (!User.isTextVisibilityOnPort()) return;
697
List<VectorCache.VectorCellExport> portShapes = subVC_.vcg.getPortShapes();
698
int[] portCenters = subVC_.getPortCenters();
699
assert portShapes.size()*2 == portCenters.length;
700
for (int i = 0; i < portShapes.size(); i++) {
701
VectorCache.VectorCellExport vce = portShapes.get(i);
702
if (stopRendering) throw new AbortRenderingException();
704
// get visual characteristics of shape
705
if (vsc.shownPorts.get(vce.getChronIndex())) continue;
706
if (vce.height < maxTextSize) continue;
708
int cX = portCenters[i*2];
709
int cY = portCenters[i*2 + 1];
710
gridToScreen(cX + oX, cY + oY, tempPt1);
714
int portDisplayLevel = User.getPortDisplayLevel();
715
Color portColor = vce.getPortColor();
716
if (expanded) portColor = textColor;
717
if (portColor != null) portGraphics.setColor(portColor);
718
if (portDisplayLevel == 2)
720
// draw port as a cross
722
offscreen.drawLine(new Point(cX-size, cY), new Point(cX+size, cY), null, portGraphics, 0, false);
723
offscreen.drawLine(new Point(cX, cY-size), new Point(cX, cY+size), null, portGraphics, 0, false);
729
boolean shortName = portDisplayLevel == 1;
730
String drawString = vce.getName(shortName);
733
tempRect.setBounds(cX, cY, 0, 0);
734
offscreen.drawText(tempRect, vce.style, vce.descript, drawString, null, portGraphics, false);
739
* Method to convert a database grid coordinate to screen coordinates.
740
* @param dbX the X coordinate (in database grid units).
741
* @param dbY the Y coordinate (in database grid units).
742
* @param result the Point in which to store the screen coordinates.
744
private void gridToScreen(int dbX, int dbY, Point result)
747
result.x = ((dbX - factorX_) * scale_int) >> SCALE_SH;
748
result.y = ((factorY_ - dbY) * scale_int) >> SCALE_SH;
750
double scrX = (dbX - factorX) * scale_;
751
double scrY = (factorY - dbY) * scale_;
752
result.x = (int)(scrX >= 0 ? scrX + 0.5 : scrX - 0.5);
753
result.y = (int)(scrY >= 0 ? scrY + 0.5 : scrY - 0.5);
758
* Method to draw a tiny box on the screen in a given color.
759
* Done when the object is too small to draw in full detail.
760
* @param lX the low X coordinate of the box.
761
* @param hX the high X coordinate of the box.
762
* @param lY the low Y coordinate of the box.
763
* @param hY the high Y coordinate of the box.
764
* @param col the color to draw.
766
private void drawTinyBox(int lX, int hX, int lY, int hY, int col, VectorCache.VectorCell greekedCell)
768
if (lX < screenLX) lX = screenLX;
769
if (hX >= screenHX) hX = screenHX-1;
770
if (lY < screenLY) lY = screenLY;
771
if (hY >= screenHY) hY = screenHY-1;
772
if (User.isUseCellGreekingImages())
774
if (greekedCell != null && greekedCell.fadeImageColors != null)
776
int backgroundColor = User.getColor(User.ColorPrefType.BACKGROUND);
777
int backgroundRed = (backgroundColor >> 16) & 0xFF;
778
int backgroundGreen = (backgroundColor >> 8) & 0xFF;
779
int backgroundBlue = backgroundColor & 0xFF;
781
// render the icon properly with scale
782
int greekWid = greekedCell.fadeImageWid;
783
int greekHei = greekedCell.fadeImageHei;
786
float xInc = greekWid / (float)wid;
787
float yInc = greekHei / (float)hei;
789
for(int y=0; y<hei; y++)
791
float yEndPos = yPos + yInc;
793
int yE = (int)yEndPos;
796
for(int x=0; x<wid; x++)
798
float xEndPos = xPos + xInc;
800
int xE = (int)xEndPos;
802
float r = 0, g = 0, b = 0;
804
for(int yGrab = yS; yGrab <= yE; yGrab++)
806
if (yGrab >= greekHei) continue;
808
if (yGrab == yS) yArea = (1 - (yPos - yS));
809
if (yGrab == yE) yArea *= (yEndPos-yE);
811
for(int xGrab = xS; xGrab <= xE; xGrab++)
813
if (xGrab >= greekWid) continue;
814
int index = xGrab + yGrab*greekedCell.fadeImageWid;
815
if (greekedCell.fadeImageColors==null || index >= greekedCell.fadeImageColors.length)
817
int value = greekedCell.fadeImageColors[index];
818
int red = (value >> 16) & 0xFF;
819
int green = (value >> 8) & 0xFF;
820
int blue = value & 0xFF;
822
if (xGrab == xS) area *= (1 - (xPos - xS));
823
if (xGrab == xE) area *= (xEndPos-xE);
824
if (area <= 0) continue;
833
int red = (int)(r / totalArea);
834
if (red > 255) red = 255;
835
int green = (int)(g / totalArea);
836
if (green > 255) green = 255;
837
int blue = (int)(b / totalArea);
838
if (blue > 255) blue = 255;
839
if (Math.abs(backgroundRed-red) > 2 || Math.abs(backgroundGreen-green) > 2 ||
840
Math.abs(backgroundBlue-blue) > 2)
842
offscreen.drawPoint(lX+x, lY+y, null, (red << 16) | (green << 8) | blue);
851
for(int y=0; y<greekedCell.fadeImageHei; y++)
853
for(int x=0; x<greekedCell.fadeImageWid; x++)
855
int valToSet = greekedCell.fadeImageColors[x+y*greekedCell.fadeImageWid];
856
topVD.offscreen.drawPoint(greekedCell.fadeOffsetX+x+1, greekedCell.fadeOffsetY+y+1, null, valToSet);
858
topVD.offscreen.drawPoint(greekedCell.fadeOffsetX, greekedCell.fadeOffsetY+y+1, null, 0);
859
topVD.offscreen.drawPoint(greekedCell.fadeOffsetX+greekedCell.fadeImageWid+1, greekedCell.fadeOffsetY+y+1, null, 0);
861
for(int x=0; x<greekedCell.fadeImageWid; x++)
863
topVD.offscreen.drawPoint(greekedCell.fadeOffsetX+x, greekedCell.fadeOffsetY, null, 0);
864
topVD.offscreen.drawPoint(greekedCell.fadeOffsetX+x, greekedCell.fadeOffsetY+greekedCell.fadeImageHei+1, null, 0);
871
// no greeked image: just use the greeked color
872
for(int y=lY; y<=hY; y++)
874
for(int x=lX; x<=hX; x++)
875
offscreen.drawPoint(x, y, null, col);
880
* Method to determine whether a cell has tiny contents.
881
* Recursively examines the cache of this and all subcells to see if the
882
* maximum feature sizes are all below the global threshold "maxObjectSize".
883
* @param cell the Cell in question.
884
* @param vc the cached representation of the cell.
885
* @param trans the Orientation of the cell.
886
* @return true if the cell has all tiny contents.
888
private boolean isContentsTiny(Cell cell, VectorCache.VectorCell vc, Orientation trans, VarContext context)
889
throws AbortRenderingException
891
if (vc.maxFeatureSize > maxObjectSize) return false;
892
for(VectorCache.VectorSubCell vsc : vc.subCells)
894
NodeInst ni = cell.getNodeById(vsc.n.nodeId);
895
VectorCache.VectorCell subVC = VectorCache.theCache.findVectorCell(vsc.subCellId, vc.orient.concatenate(vsc.n.orient));
896
if (ni.isExpanded() || fullInstantiate)
898
Orientation thisOrient = ni.getOrient();
899
Orientation recurseTrans = trans.concatenate(thisOrient);
900
VarContext subContext = context.push(ni);
901
Cell subCell = (Cell)ni.getProto();
902
VectorCache.VectorCell subVC_ = drawCell(subCell, recurseTrans, subContext);
903
assert subVC_ == subVC;
904
boolean subCellTiny = isContentsTiny(subCell, subVC, recurseTrans, subContext);
905
if (!subCellTiny) return false;
908
if (subVC.vcg.cellMinSize > maxObjectSize) return false;
913
private void makeGreekedImage(VectorCache.VectorCell subVC)
914
throws AbortRenderingException
916
if (subVC.fadeImage) return;
917
if (!User.isUseCellGreekingImages()) return;
919
// determine size and scale of greeked cell image
920
Rectangle2D cellBounds = subVC.vcg.bounds;
921
Rectangle2D ownBounds = new Rectangle2D.Double(cellBounds.getMinX(), cellBounds.getMinY(), cellBounds.getWidth(), cellBounds.getHeight());
922
AffineTransform trans = subVC.orient.rotateAbout(0, 0);
923
DBMath.transformRect(ownBounds, trans);
924
double greekScale = MAXGREEKSIZE / ownBounds.getHeight();
925
if (ownBounds.getWidth() > ownBounds.getHeight())
926
greekScale = MAXGREEKSIZE / ownBounds.getWidth();
927
int lX = (int)Math.floor(cellBounds.getMinX()*greekScale);
928
int hX = (int)Math.ceil(cellBounds.getMaxX()*greekScale);
929
int lY = (int)Math.floor(cellBounds.getMinY()*greekScale);
930
int hY = (int)Math.ceil(cellBounds.getMaxY()*greekScale);
931
if (hX <= lX) hX = lX + 1;
932
int greekWid = hX - lX;
933
if (hY <= lY) hY = lY + 1;
934
int greekHei = hY - lY;
935
Rectangle screenBounds = new Rectangle(lX, lY, greekWid, greekHei);
937
// construct the offscreen buffers for the greeked cell image
938
PixelDrawing offscreen = new PixelDrawing(greekScale, screenBounds);
939
Point2D cellCtr = new Point2D.Double(ownBounds.getCenterX(), ownBounds.getCenterY());
940
VectorDrawing subVD = new VectorDrawing();
942
subVC.fadeOffsetX = debugXP;
943
subVC.fadeOffsetY = debugYP;
944
debugXP += MAXGREEKSIZE + 5;
947
if (debugXP + MAXGREEKSIZE+2 >= topVD.offscreen.getSize().width)
950
debugYP += MAXGREEKSIZE + 5;
954
// set rendering information for the greeked cell image
955
subVD.offscreen = offscreen;
956
subVD.screenLX = 0; subVD.screenHX = greekWid;
957
subVD.screenLY = 0; subVD.screenHY = greekHei;
958
subVD.szHalfWidth = greekWid / 2;
959
subVD.szHalfHeight = greekHei / 2;
960
subVD.maxObjectSize = 0;
961
subVD.maxTextSize = 0;
962
subVD.scale = (float)greekScale;
963
subVD.scale_ = (float)(greekScale/DBMath.GRID);
964
subVD.factorX = (float)(cellCtr.getX()*DBMath.GRID - subVD.szHalfWidth/subVD.scale_);
965
subVD.factorY = (float)(cellCtr.getY()*DBMath.GRID + subVD.szHalfHeight/subVD.scale_);
966
subVD.factorX_ = (int)subVD.factorX;
967
subVD.factorY_ = (int)subVD.factorY;
968
subVD.scale_int = (int)(subVD.scale_ * (1 << SCALE_SH));
969
subVD.fullInstantiate = true;
970
subVD.takingLongTime = true;
972
// render the greeked cell
973
subVD.offscreen.clearImage(null);
974
subVD.render(subVC, 0, 0, VarContext.globalContext, -1);
975
subVD.offscreen.composite(null);
977
// remember the greeked cell image
978
int[] img = offscreen.getOpaqueData();
979
subVC.fadeImageWid = greekWid;
980
subVC.fadeImageHei = greekHei;
981
subVC.fadeImageColors = new int[subVC.fadeImageWid * subVC.fadeImageHei];
983
for(int y=0; y<subVC.fadeImageHei; y++)
985
for(int x=0; x<subVC.fadeImageWid; x++)
988
subVC.fadeImageColors[i++] = value & 0xFFFFFF;
991
subVC.fadeImage = true;
995
* Method to determine the "fade" color for a cached cell.
996
* Fading is done when the cell is too tiny to draw (or all of its contents are too tiny).
997
* Instead of drawing the cell contents, the entire cell is painted with the "fade" color.
998
* @param vc the cached cell.
999
* @return the fade color (an integer with red/green/blue).
1001
private int getFadeColor(VectorCache.VectorCell vc, VarContext context)
1002
throws AbortRenderingException
1004
if (vc.hasFadeColor) return vc.fadeColor;
1006
// examine all shapes
1007
Map<Layer,MutableDouble> layerAreas = new HashMap<Layer,MutableDouble>();
1008
gatherContents(vc, layerAreas, context);
1010
// now compute the color
1011
Set<Layer> keys = layerAreas.keySet();
1012
double totalArea = 0;
1013
for(Layer layer : keys)
1015
MutableDouble md = layerAreas.get(layer);
1016
totalArea += md.doubleValue();
1018
double r = 0, g = 0, b = 0;
1021
for(Layer layer : keys)
1023
MutableDouble md = layerAreas.get(layer);
1024
double portion = md.doubleValue() / totalArea;
1025
EGraphics desc = layer.getGraphics();
1026
Color col = desc.getColor();
1027
r += col.getRed() * portion;
1028
g += col.getGreen() * portion;
1029
b += col.getBlue() * portion;
1032
if (r < 0) r = 0; if (r > 255) r = 255;
1033
if (g < 0) g = 0; if (g > 255) g = 255;
1034
if (b < 0) b = 0; if (b > 255) b = 255;
1035
vc.fadeColor = (((int)r) << 16) | (((int)g) << 8) | (int)b;
1036
vc.hasFadeColor = true;
1037
return vc.fadeColor;
1041
* Helper method to recursively examine a cached cell and its subcells and compute
1042
* the coverage of each layer.
1043
* @param vc the cached cell to examine.
1044
* @param layerAreas a HashMap of all layers and the areas they cover.
1046
private void gatherContents(VectorCache.VectorCell vc, Map<Layer,MutableDouble> layerAreas, VarContext context)
1047
throws AbortRenderingException
1049
for(VectorCache.VectorBase vb : vc.filledShapes)
1051
Layer layer = vb.layer;
1052
if (layer == null) continue;
1053
Layer.Function fun = layer.getFunction();
1054
if (fun.isImplant() || fun.isSubstrate()) continue;
1056
// handle each shape
1058
if (vb instanceof VectorCache.VectorManhattan)
1060
VectorCache.VectorManhattan vm = (VectorCache.VectorManhattan)vb;
1061
for (int i = 0; i < vm.coords.length; i += 4) {
1062
double c1X = vm.coords[i];
1063
double c1Y = vm.coords[i + 1];
1064
double c2X = vm.coords[i + 2];
1065
double c2Y = vm.coords[i + 3];
1066
area += (c1X-c2X) * (c1Y-c2Y);
1068
} else if (vb instanceof VectorCache.VectorPolygon)
1070
VectorCache.VectorPolygon vp = (VectorCache.VectorPolygon)vb;
1071
area = GenMath.getAreaOfPoints(vp.points);
1072
} else if (vb instanceof VectorCache.VectorCircle)
1074
VectorCache.VectorCircle vci = (VectorCache.VectorCircle)vb;
1075
double radius = new Point2D.Double(vci.cX, vci.cY).distance(new Point2D.Double(vci.eX, vci.eY));
1076
area = radius * radius * Math.PI;
1078
if (area == 0) continue;
1079
MutableDouble md = layerAreas.get(layer);
1082
md = new MutableDouble(0);
1083
layerAreas.put(layer, md);
1085
md.setValue(md.doubleValue() + area);
1088
Cell cell = VectorCache.theCache.database.getCell(vc.vcg.cellId);
1089
for(VectorCache.VectorSubCell vsc : vc.subCells)
1091
VectorCache.VectorCellGroup vcg = VectorCache.theCache.findCellGroup(vsc.subCellId);
1092
VectorCache.VectorCell subVC = vcg.getAnyCell();
1093
NodeInst ni = cell.getNodeById(vsc.n.nodeId);
1094
VarContext subContext = context.push(ni);
1096
subVC = drawCell((Cell)ni.getProto(), Orientation.IDENT, subContext);
1097
gatherContents(subVC, layerAreas, subContext);
1101
// ************************************* CACHE CREATION *************************************
1104
* Method to cache the contents of a cell.
1105
* @param cell the Cell to cache
1106
* @param prevTrans the orientation of the cell (just a rotation, no offsets here).
1107
* @return a cached cell object for the given Cell.
1109
private VectorCache.VectorCell drawCell(Cell cell, Orientation prevTrans, VarContext context)
1110
throws AbortRenderingException
1112
// caching the cell: check for abort and delay reporting
1113
if (stopRendering) throw new AbortRenderingException();
1114
if (!takingLongTime)
1116
long currentTime = System.currentTimeMillis();
1117
if (currentTime - startTime > 1000)
1119
System.out.print("Display caching, please wait...");
1120
TopLevel.setBusyCursor(true);
1121
takingLongTime = true;
1125
return VectorCache.theCache.drawCell(cell.getId(), prevTrans, context, scale);