coriolis/hurricane/src/viewer/CellWidget.cpp

574 lines
17 KiB
C++

#include <math.h>
#include <QPaintEvent>
#include <QPainter>
#include <QPen>
#include "DataBase.h"
#include "Technology.h"
#include "BasicLayer.h"
#include "Slice.h"
#include "Box.h"
#include "Segment.h"
using namespace H;
#include "CellWidget.h"
namespace {
QBrush getBrush(const string &pattern, int redValue, int greenValue, int blueValue) {
if (pattern == "FFFFFFFFFFFFFFFF") {
return QBrush(QColor(redValue, greenValue, blueValue));
} else {
char bits[8];
for (int i = 0; i < 8; i++) {
int high = pattern[i * 2];
if (('0' <= high) && (high <= '9')) {
high = high - '0';
} else {
if (('a' <= high) && (high <= 'f')) {
high = 10 + high - 'a';
} else {
if (('A' <= high) && (high <= 'F')) {
high = 10 + high - 'A';
} else {
high = '0';
}
}
}
int low = pattern[(i * 2) + 1];
if (('0' <= low) && (low <= '9')) {
low = low - '0';
} else {
if (('a' <= low) && (low <= 'f')) {
low = 10 + low - 'a';
} else {
if (('A' <= low) && (low <= 'F')) {
low = 10 + low - 'A';
} else {
low = '0';
}
}
}
bits[i] = (char)((high * 16) + low);
}
return QBrush(QColor(redValue, greenValue, blueValue),
QPixmap(bits));
}
}
Technology* getTechnology() {
DataBase* database = GetDataBase();
if (database) {
return database->GetTechnology();
}
return NULL;
}
static QColor backgroundColor = QColor( 50, 50, 50 );
static QColor foregroundColor = QColor( 255, 255, 255 );
static QColor rubberColor = QColor( 192, 0, 192 );
static QColor phantomColor = QColor( 139, 134, 130 );
static QColor boundaryColor = QColor( 208, 199, 192 );
static QColor markerColor = QColor( 80, 250, 80 );
static QColor selectionDrawColor = QColor( 255, 255, 255 );
static QColor selectionFillColor = QColor( 255, 255, 255 );
static QColor gridColor = QColor( 255, 255, 255 );
static QColor spotColor = QColor( 255, 255, 255 );
static QColor ghostColor = QColor( 255, 255, 255 );
static QPen boundariesPen = QPen(boundaryColor);
static QBrush boundariesBrush = QBrush(boundaryColor);
static QPen phantomsPen = QPen(phantomColor);
static QBrush phantomsBrush = QBrush(phantomColor);
}
CellWidget::CellWidget(Cell* c, QWidget* parent)
: QWidget(parent),
cell(c),
invalidRegion(),
clipBox(),
clipX(),
clipY(),
painter(NULL),
backgroundColor(20, 20, 20),
foregroundColor(255, 255, 255),
scale(1),
screenDx(0),
screenDy(0),
brushDx(0),
brushDy(0),
basicLayersBrush(),
basicLayersPen() {
for_each_basic_layer(basiclayer, getTechnology()->GetBasicLayers()) {
basicLayersBrush[basiclayer] =
getBrush(basiclayer->GetFillPattern(),
basiclayer->GetRedValue(),
basiclayer->GetGreenValue(),
basiclayer->GetBlueValue());
basicLayersPen[basiclayer] =
QPen(QColor(basiclayer->GetRedValue(), basiclayer->GetGreenValue(), basiclayer->GetBlueValue()));
end_for;
}
}
void CellWidget::paintEvent(QPaintEvent* event) {
invalidate(event->rect());
redraw();
}
void CellWidget::reframe(double sc) {
reframe(center, sc);
}
void CellWidget::reframe(const Point& c, double sc) {
if (0 < sc) {
center = c;
scale = sc;
screenDx = -(int)rint((GetValue(center.getX()) - (width() / (scale*2))) * scale);
screenDy = -(int)rint((GetValue(center.getY()) - (height() / (scale*2))) * scale);
brushDx = 0;
brushDy = 0;
invalidate();
}
}
void CellWidget::invalidate() {
invalidRegion = QRegion(rect());
}
void CellWidget::invalidate(const QRect& screenRect) {
QRect visibleScreenRect = screenRect.intersect(rect());
if (!visibleScreenRect.isEmpty()) {
invalidRegion = invalidRegion.unite(QRegion(visibleScreenRect));
}
}
void CellWidget::redraw() {
if (!invalidRegion.isEmpty()) {
QRect invalidRect = invalidRegion.boundingRect();
H::Box area = getBox(invalidRect).inflate(getSize(1));
setClipBox(area);
QPaintDevice* device = this;
QPainter newPainter(device);
QPainter* oldPainter = painter;
painter = &newPainter;
double brightness = 1.0;
painter->setClipRegion(invalidRegion);
painter->fillRect(invalidRect, QBrush(getBackgroundColor()));
painter->save();
setPen(boundariesPen, brightness);
setBrush(boundariesBrush, brightness);
drawBoundaries(cell, area, Transformation());
painter->restore();
for_each_basic_layer(basiclayer, getTechnology()->GetBasicLayers()) {
if (isDrawable(basiclayer)) {
//painter->save();
map<BasicLayer*, QBrush>::const_iterator bmit = basicLayersBrush.find(basiclayer);
if (bmit != basicLayersBrush.end()) {
setBrush(bmit->second, brightness);
}
map<BasicLayer*, QPen>::const_iterator pmit = basicLayersPen.find(basiclayer);
if (pmit != basicLayersPen.end()) {
setPen(pmit->second, brightness);
}
drawContent(cell, basiclayer, area, Transformation());
//painter->restore();
end_for;
}
}
painter = oldPainter;
invalidRegion = QRegion();
}
}
void CellWidget::drawContent(const Cell* cell, const BasicLayer* basicLayer, const H::Box& updateArea, const Transformation& transformation) const {
for_each_instance(instance, cell->GetInstancesUnder(updateArea)) {
drawContent(instance, basicLayer, updateArea, transformation);
end_for;
}
for_each_slice(slice, cell->GetSlices()) {
drawSlice(slice, basicLayer, updateArea, transformation);
end_for;
}
}
void CellWidget::drawContent(const Instance* instance, const BasicLayer* basicLayer, const H::Box& updateArea, const Transformation& transformation) const {
Box masterArea = updateArea;
Transformation masterTransformation = instance->GetTransformation();
instance->GetTransformation().getInvert().applyOn(masterArea);
transformation.applyOn(masterTransformation);
drawContent(instance->GetMasterCell(), basicLayer, masterArea, masterTransformation);
}
void CellWidget::drawSlice(const Slice* slice, const BasicLayer* basicLayer, const H::Box& updateArea, const Transformation& transformation) const {
if (slice->GetLayer()->Contains(basicLayer)) {
if (slice->GetBoundingBox().intersect(updateArea)) {
//if ((basicLayer == _layer->_GetSymbolicBasicLayer()) || (3 < view->GetScale()))
for_each_go(go, slice->GetGosUnder(updateArea)) {
drawGo(go, basicLayer, updateArea, transformation);
end_for;
}
}
}
}
void CellWidget::drawGo(const Go* go, const BasicLayer* basicLayer, const Box& updateArea, const Transformation& transformation) const {
const Segment* segment = dynamic_cast<const Segment*>(go);
if (segment) {
drawSegment(segment, basicLayer, updateArea, transformation);
return;
}
const Contact* contact = dynamic_cast<const Contact*>(go);
if (contact) {
drawContact(contact, basicLayer, updateArea, transformation);
return;
}
}
void CellWidget::drawSegment(const Segment* segment, const BasicLayer* basicLayer, const Box& updateArea, const Transformation& transformation) const {
if (1 < getScreenSize(segment->GetWidth())) {
drawRectangle(transformation.getBox(segment->GetBoundingBox(basicLayer)));
} else {
drawLine(transformation.getPoint(segment->GetSourcePosition()),
transformation.getPoint(segment->GetTargetPosition()));
}
}
void CellWidget::drawContact(const Contact* contact, const BasicLayer* basicLayer, const Box& updateArea, const Transformation& transformation) const {
drawRectangle(transformation.getBox(contact->GetBoundingBox(basicLayer)));
}
void CellWidget::drawPhantoms(const Cell* cell, const H::Box& updateArea, const Transformation& transformation) const {
for_each_instance(instance, cell->GetInstancesUnder(updateArea)) {
drawPhantoms(instance, updateArea, transformation);
end_for;
}
}
void CellWidget::drawPhantoms(const Instance* instance, const H::Box& updateArea, const Transformation& transformation) const {
H::Box masterArea = updateArea;
Transformation masterTransformation = instance->GetTransformation();
instance->GetTransformation().getInvert().applyOn(masterArea);
transformation.applyOn(masterTransformation);
drawPhantoms(instance->GetMasterCell(), masterArea, masterTransformation);
}
void CellWidget::drawBoundaries(const Cell* cell, const H::Box& updateArea, const Transformation& transformation) const {
drawRectangle(transformation.getBox(cell->GetAbutmentBox()));
for_each_instance(instance, cell->GetInstances()) {
drawBoundaries(instance, updateArea, transformation);
end_for;
}
}
void CellWidget::drawBoundaries(const Instance* instance, const H::Box& updateArea, const Transformation& transformation) const {
H::Box masterArea = updateArea;
Transformation masterTransformation = instance->GetTransformation();
instance->GetTransformation().getInvert().applyOn(masterArea);
transformation.applyOn(masterTransformation);
drawBoundaries(instance->GetMasterCell(), masterArea, masterTransformation);
}
void CellWidget::drawRectangle(const H::Box& box) const {
if (painter) {
H::Box ibox = box.getIntersection(clipBox);
if (!ibox.isEmpty()) {
int x = getScreenX(ibox.getXMin());
int y = getScreenY(ibox.getYMax());
int w = getScreenX(ibox.getXMax()) - x + 1;
int h = getScreenY(ibox.getYMin()) - y + 1;
painter->drawRect(x, y, w, h);
}
}
}
void CellWidget::drawLine(const Point& po, const Point& pe) const {
drawLine(po.getX(), po.getY(), pe.getX(), pe.getY());
}
void CellWidget::drawLine(const Unit& xo,
const Unit& yo,
const Unit& xe,
const Unit& ye) const {
if (painter) {
double dxo = GetValue(xo);
double dyo = GetValue(yo);
int co = getClipCode(dxo, dyo);
double dxe = GetValue(xe);
double dye = GetValue(ye);
int ce = getClipCode(dxe, dye);
if (clipLine(dxo, dyo, co, dxe, dye, ce)) {
int ixo = getScreenX(GetUnit(dxo));
int iyo = getScreenY(GetUnit(dyo));
int ixe = getScreenX(GetUnit(dxe));
int iye = getScreenY(GetUnit(dye));
//painter->save();
if (painter->pen() == Qt::NoPen) {
painter->setPen(painter->brush().color());
}
//painter->moveTo(ixo, iyo);
//painter->lineTo(ixe, iye);
painter->drawLine(ixo, iyo, ixe, iye);
//painter->restore();
}
}
}
Unit CellWidget::getX(int screenX) const {
return GetUnit((screenX - screenDx) / scale);
}
Unit CellWidget::getY(int screenY) const {
return GetUnit(((height() - screenY) - screenDy) / scale);
}
Unit CellWidget::getSize(int screenSize) const {
return GetUnit(screenSize / scale);
}
H::Box CellWidget::getBox(const QRect& screenRect) const {
if (screenRect.isEmpty()) {
return H::Box();
}
return H::Box(getX(screenRect.left()),
getY(screenRect.bottom()),
getX(screenRect.right()),
getY(screenRect.top()));
}
int CellWidget::getScreenX(const Unit& x) const {
return screenDx + (int)rint(GetValue(x) * scale);
}
int CellWidget::getScreenY(const Unit& y) const {
return height() - (int)rint(screenDy + (GetValue(y) * scale));
}
int CellWidget::getScreenSize(const Unit& size) const {
return (int)rint(GetValue(size) * scale);
}
void CellWidget::setClipBox(const Box& area) {
clipBox = Box(area).inflate(getSize(2));
clipX[0] = GetValue(clipBox.getXMin());
clipX[1] = GetValue(clipBox.getXMax());
clipX[2] = GetValue(clipBox.getXMin());
clipX[3] = GetValue(clipBox.getXMax());
clipY[0] = GetValue(clipBox.getYMin());
clipY[1] = GetValue(clipBox.getYMin());
clipY[2] = GetValue(clipBox.getYMax());
clipY[3] = GetValue(clipBox.getYMax());
}
int CellWidget::getClipCode(double x, double y) const {
if (x < clipX[0]) {
if (y < clipY[0]) {
return 28;
}
if (clipY[3] < y) {
return 22;
}
return 4;
}
if (clipX[3] < x) {
if (y < clipY[0]) {
return 25;
}
if (clipY[3] < y) {
return 19;
}
return 1;
}
if (y < clipY[0]) {
return 8;
}
if (clipY[3] < y) {
return 2;
}
return 0;
}
bool CellWidget::clipLine(double& xo,
double& yo,
int co,
double& xe,
double& ye,
int ce,
int u) const {
if (co & ce & -17) {
return false;
}
if (!co & !ce) {
return true;
}
if (co & 1) {
yo += ((ye - yo) / (xe - xo)) * (clipX[3] - xo);
xo = clipX[3];
co = getClipCode(xo, yo);
return clipLine(xo, yo, co, xe, ye, ce, u + 1);
}
if (co & 2) {
xo += ((xe - xo) / (ye - yo)) * (clipY[3] - yo);
yo = clipY[3];
co = getClipCode(xo, yo);
return clipLine(xo, yo, co, xe, ye, ce, u + 1);
}
if (co & 4) {
yo += ((ye - yo) / (xe - xo)) * (clipX[0] - xo);
xo = clipX[0];
co = getClipCode(xo, yo);
return clipLine(xo, yo, co, xe, ye, ce, u + 1);
}
if (co & 8) {
xo += ((xe - xo) / (ye - yo)) * (clipY[0] - yo);
yo = clipY[0];
co = getClipCode(xo, yo);
return clipLine(xo, yo, co, xe, ye, ce, u + 1);
}
if (ce & 1) {
ye -= ((ye - yo) / (xe - xo)) * (xe - clipX[3]);
xe = clipX[3];
ce = getClipCode(xe, ye);
return clipLine(xo, yo, co, xe, ye, ce, u + 1);
}
if (ce & 2) {
xe -= ((xe - xo) / (ye - yo)) * (ye - clipY[3]);
ye = clipY[3];
ce = getClipCode(xe, ye);
return clipLine(xo, yo, co, xe, ye, ce, u + 1);
}
if (ce & 4) {
ye -= ((ye - yo) / (xe - xo)) * (xe - clipX[0]);
xe = clipX[0];
ce = getClipCode(xe, ye);
return clipLine(xo, yo, co, xe, ye, ce, u + 1);
}
if (ce & 8) {
xe -= ((xe - xo) / (ye - yo)) * (ye - clipY[0]);
ye = clipY[0];
ce = getClipCode(xe, ye);
return clipLine(xo, yo, co, xe, ye, ce, u + 1);
}
return true;
}
void CellWidget::setFont(const QFont& font) {
if (painter) {
painter->setFont(font);
}
}
void CellWidget::setPen(const QPen& pen, double brightness) {
if (!((0.1 <= brightness) && (brightness <= 1.0))) {
throw Error(__FILE__, __LINE__);
}
if (painter) {
if (pen == Qt::NoPen) {
painter->setPen(pen);
} else {
QPen correctedPen = pen;
if (brightness < 1) {
QColor bgColor = getBackgroundColor();
int r = bgColor.red();
int g = bgColor.green();
int b = bgColor.blue();
QColor color = pen.color();
r = r + (int)((color.red() - r) * brightness);
g = g + (int)((color.green() - g) * brightness);
b = b + (int)((color.blue() - b) * brightness);
correctedPen = QPen(QColor(r, g, b));
}
painter->setPen(correctedPen);
}
}
}
void CellWidget::setBrush(const QBrush& brush, double brightness) {
if (!((0.1 <= brightness) && (brightness <= 1.0))) {
throw Error(__FILE__, __LINE__);
}
if (painter) {
if (brush == Qt::NoBrush) {
painter->setBrush(brush);
} else {
QBrush correctedBrush = brush;
if (brightness < 1) {
QColor bgColor = getBackgroundColor();
int r = bgColor.red();
int g = bgColor.green();
int b = bgColor.blue();
QColor color = brush.color();
r = r + (int)((color.red() - r) * brightness);
g = g + (int)((color.green() - g) * brightness);
b = b + (int)((color.blue() - b) * brightness);
correctedBrush = QBrush(QColor(r, g, b), brush.style());
}
painter->setBrush(correctedBrush);
}
}
}
void CellWidget::setBrushOrigin(const QPoint& origin) {
if (painter) {
painter->setBrushOrigin(brushDx + origin.x(), brushDy + origin.y());
}
}
bool CellWidget::isDrawable(BasicLayer* layer) const {
return (layer->GetDisplayThreshold() <= scale);
}
double CellWidget::getScale() const {
return scale;
}