use of org.eclipse.elk.alg.common.polyomino.structures.Polyomino in project elk by eclipse.
the class DisCoGraphRenderer method renderPolyominoes.
// added by mic
/**
* Paints all polyominoes that fall into the given dirty area.
*
* @param polys
* the polyominoes to paint
* @param graphics
* the graphics context used to paint
* @param area
* dirty area that needs painting
* @param offset
* offset to be added to relative coordinates
* @param nodeAlpha
* alpha value for nodes
* @param fillingAlpha
* alpha value for node fillings
*/
private void renderPolyominoes(final ElkNode parent, final List<DCPolyomino> polys, final GC graphics, final Rectangle area, final KVector offset, final int nodeAlpha, final int fillingAlpha, final int levelNumber) {
for (DCPolyomino poly : polys) {
KVector polyCorner = poly.getMinCornerOnCanvas();
double topLeftCornerX = polyCorner.x;
double topLeftCornerY = polyCorner.y;
double cellSizeX = poly.getCellSizeX();
double cellSizeY = poly.getCellSizeY();
double bottomRightCornerX = topLeftCornerX + cellSizeX * poly.getWidth();
double bottomRightCornerY = topLeftCornerY + cellSizeY * poly.getHeight();
for (int x = 0; x < poly.getWidth(); x++) {
for (int y = 0; y < poly.getHeight(); y++) {
Triple<Polyomino, Integer, Integer> polyoCell = new Triple<Polyomino, Integer, Integer>(poly, x, y);
PaintRectangle rect = polyominoMap.get(polyoCell);
if (rect == null) {
rect = new PaintRectangle(topLeftCornerX, topLeftCornerY, cellSizeX, cellSizeY, x, y, offset, getScale());
polyominoMap.put(polyoCell, rect);
}
if (!rect.painted && rect.intersects(area)) {
// paint this node
graphics.setAlpha(fillingAlpha);
if (configurator.getPolyominoFillColor() != null && poly.isBlocked(x, y)) {
graphics.setBackground(configurator.getPolyominoFillColor());
graphics.fillRectangle(rect.x, rect.y, rect.width, rect.height);
if (configurator.getNodeLabelFont() != null) {
graphics.setFont(configurator.getNodeLabelFont());
}
graphics.setAlpha(nodeAlpha);
graphics.setForeground(configurator.getPolyominoBorderTextColor());
if (state.drawLabels()) {
String levelprefix = levelNumber + "_";
if (state.removeLvl()) {
levelprefix = "";
}
graphics.drawString(levelprefix + Integer.toString(poly.getId()), rect.x, rect.y, true);
}
}
if (configurator.getPolyominoFillColor() != null && poly.isWeaklyBlocked(x, y)) {
// CHECKSTYLEOFF MagicNumber
graphics.setBackgroundPattern(patterns.getPolyominoExtensionPattern(state.makeSolid() ? 255 : fillingAlpha));
// CHECKSTYLEON MagicNumber
graphics.fillRectangle(rect.x, rect.y, rect.width, rect.height);
graphics.setAlpha(nodeAlpha);
graphics.setForeground(configurator.getPolyominoWeaklyBlockedBorderTextColor());
graphics.drawRectangle(rect.x, rect.y, rect.width, rect.height);
if (configurator.getNodeLabelFont() != null) {
graphics.setFont(configurator.getNodeLabelFont());
}
graphics.setAlpha(nodeAlpha);
if (state.drawLabels()) {
String levelprefix = levelNumber + "_";
if (state.removeLvl()) {
levelprefix = "";
}
graphics.drawString(levelprefix + Integer.toString(poly.getId()), rect.x, rect.y, true);
}
}
graphics.setAlpha(nodeAlpha);
if (configurator.getPolyominoBorderTextColor() != null && !poly.isWeaklyBlocked(x, y)) {
graphics.setForeground(configurator.getPolyominoBorderTextColor());
if (state.drawPolyLinesBlack()) {
graphics.setForeground(configurator.getBlack());
}
graphics.drawRectangle(rect.x, rect.y, rect.width, rect.height);
}
rect.painted = true;
}
}
}
if (state.markTheCenter()) {
int x = poly.getCenterX();
int y = poly.getCenterY();
PaintRectangle centerRect = polyominoCenterMap.get(poly);
if (centerRect == null) {
centerRect = new PaintRectangle(topLeftCornerX, topLeftCornerY, cellSizeX, cellSizeY, x, y, offset, getScale());
polyominoCenterMap.put(poly, centerRect);
}
if (configurator.getPolyominoFillColor() != null) {
// CHECKSTYLEOFF MagicNumber
graphics.setBackgroundPattern(patterns.getPolyominoCenterPattern(state.makeSolid() ? 255 : fillingAlpha));
// CHECKSTYLEON MagicNumber
graphics.fillRectangle(centerRect.x, centerRect.y, centerRect.width, centerRect.height);
graphics.setAlpha(nodeAlpha);
}
}
for (UniqueTriple<Direction, Integer, Integer> ext : poly.getPolyominoExtensions()) {
PaintRectangle rect = polyominoExtensionMap.get(ext);
if (rect == null) {
Direction dir = ext.getFirst();
int extStart = ext.getSecond();
int extEnd = ext.getThird();
switch(dir) {
case NORTH:
rect = new PaintRectangle(topLeftCornerX + extStart * cellSizeX, 0, (extEnd - extStart + 1) * cellSizeX, topLeftCornerY, offset, getScale());
break;
case SOUTH:
rect = new PaintRectangle(topLeftCornerX + extStart * cellSizeX, bottomRightCornerY, (extEnd - extStart + 1) * cellSizeX, parent.getHeight() - bottomRightCornerY, offset, getScale());
break;
case WEST:
rect = new PaintRectangle(0, topLeftCornerY + extStart * cellSizeY, topLeftCornerX, (extEnd - extStart + 1) * cellSizeY, offset, getScale());
break;
default:
// EAST
rect = new PaintRectangle(bottomRightCornerX, topLeftCornerY + extStart * cellSizeY, parent.getWidth() - bottomRightCornerX, (extEnd - extStart + 1) * cellSizeY, offset, getScale());
break;
}
// Maybe not unique in extreme cases where extensions
// are very close to each other, but it doesn't matter
// for the drawing
polyominoExtensionMap.put(ext, rect);
}
graphics.setAlpha(fillingAlpha);
// CHECKSTYLEOFF MagicNumber
graphics.setBackgroundPattern(patterns.getPolyominoExtensionPattern(state.makeSolid() ? 255 : fillingAlpha));
// CHECKSTYLEON MagicNumber
graphics.fillRectangle(rect.x, rect.y, rect.width, rect.height);
graphics.setAlpha(nodeAlpha);
graphics.setForeground(configurator.getPolyominoWeaklyBlockedBorderTextColor());
graphics.drawRectangle(rect.x, rect.y, rect.width, rect.height);
if (configurator.getNodeLabelFont() != null) {
graphics.setFont(configurator.getNodeLabelFont());
}
graphics.setAlpha(nodeAlpha);
if (state.drawLabels()) {
String levelprefix = levelNumber + "_";
if (state.removeLvl()) {
levelprefix = "";
}
graphics.drawString(levelprefix + Integer.toString(poly.getId()), rect.x, rect.y, true);
}
}
}
}
use of org.eclipse.elk.alg.common.polyomino.structures.Polyomino in project elk by eclipse.
the class PolyominoCompactor method packPolyominoes.
/**
* Places {@link Polyomino polyominoes} close together, in order to achieve a minimum area, based on the heuristic
* algorithm PackPolyominoes from the paper.
*/
public <P extends Polyomino> void packPolyominoes(final Polyominoes<P> polyHolder) {
List<P> polys = polyHolder.getPolyominoes();
PlanarGrid grid = polyHolder.getGrid();
// 1. Sort polyominoes by some strategy
switch(polyHolder.getProperty(PolyominoOptions.POLYOMINO_LOW_LEVEL_SORT)) {
case BY_SIZE:
polys.sort(new MinPerimeterComparator().reversed());
break;
case BY_SIZE_AND_SHAPE:
default:
polys.sort(new MinPerimeterComparatorWithShape().reversed());
break;
}
switch(polyHolder.getProperty(PolyominoOptions.POLYOMINO_HIGH_LEVEL_SORT)) {
case CORNER_CASES_THAN_SINGLE_SIDE_LAST:
polys.sort(new MinNumOfExtensionsComparator());
polys.sort(new SingleExtensionSideGreaterThanRestComparator());
polys.sort(new CornerCasesGreaterThanRestComparator());
break;
case NUM_OF_EXTERNAL_SIDES_THAN_NUM_OF_EXTENSIONS_LAST:
default:
polys.sort(new MinNumOfExtensionsComparator());
polys.sort(new MinNumOfExtensionDirectionsComparator());
}
// 2. Initialize cost function. Implemented as a BiFunction for future interchangeability with different
// metrics.
BiFunction<Pair<Integer, Integer>, Polyomino, Pair<Integer, Integer>> successorBasedOnCost;
switch(polyHolder.getProperty(PolyominoOptions.POLYOMINO_TRAVERSAL_STRATEGY)) {
case SPIRAL:
successorBasedOnCost = new SuccessorMaxNormWindingInMathPosSense();
break;
case LINE_BY_LINE:
successorBasedOnCost = new SuccessorLineByLine();
break;
case MANHATTAN:
successorBasedOnCost = new SuccessorManhattan();
break;
case JITTER:
successorBasedOnCost = new SuccessorJitter();
break;
case QUADRANTS_MANHATTAN:
successorBasedOnCost = new SuccessorQuadrantsGeneric(new SuccessorManhattan());
break;
case QUADRANTS_LINE_BY_LINE:
successorBasedOnCost = new SuccessorQuadrantsGeneric(new SuccessorLineByLine());
break;
case COMBINE_LINE_BY_LINE_MANHATTAN:
successorBasedOnCost = new SuccessorCombination(new SuccessorQuadrantsGeneric(new SuccessorLineByLine()), new SuccessorQuadrantsGeneric(new SuccessorManhattan()));
break;
case COMBINE_JITTER_MANHATTAN:
successorBasedOnCost = new SuccessorCombination(new SuccessorQuadrantsGeneric(new SuccessorJitter()), new SuccessorQuadrantsGeneric(new SuccessorManhattan()));
break;
case QUADRANTS_JITTER:
default:
successorBasedOnCost = new SuccessorQuadrantsGeneric(new SuccessorJitter());
}
for (Polyomino poly : polys) {
// 3. Start placement of each polyomino at the center of the grid
int offX = 0;
int offY = 0;
Pair<Integer, Integer> next = new Pair<Integer, Integer>(offX, offY);
// 4. Until no polyomino cell intersects with another polyomino already placed ...
while (grid.intersectsWithCenterBased(poly, offX, offY)) {
// ... get next trial position based on cost function
next = successorBasedOnCost.apply(next, poly);
offX = next.getFirst();
offY = next.getSecond();
}
// 5. When a valid position is found, mark all new cells in the underlying grid and save the position of the
// polyomino's center relative to the grid's center
grid.addFilledCellsFrom(poly, offX, offY);
}
}
Aggregations