Search in sources :

Example 1 with Polyomino

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);
            }
        }
    }
}
Also used : Triple(org.eclipse.elk.core.util.Triple) UniqueTriple(org.eclipse.elk.alg.common.utils.UniqueTriple) DCPolyomino(org.eclipse.elk.alg.disco.structures.DCPolyomino) KVector(org.eclipse.elk.core.math.KVector) Direction(org.eclipse.elk.alg.common.polyomino.structures.Direction) DCDirection(org.eclipse.elk.alg.disco.graph.DCDirection) DCPolyomino(org.eclipse.elk.alg.disco.structures.DCPolyomino) Polyomino(org.eclipse.elk.alg.common.polyomino.structures.Polyomino)

Example 2 with Polyomino

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);
    }
}
Also used : PlanarGrid(org.eclipse.elk.alg.common.polyomino.structures.PlanarGrid) Polyomino(org.eclipse.elk.alg.common.polyomino.structures.Polyomino) Pair(org.eclipse.elk.core.util.Pair)

Aggregations

Polyomino (org.eclipse.elk.alg.common.polyomino.structures.Polyomino)2 Direction (org.eclipse.elk.alg.common.polyomino.structures.Direction)1 PlanarGrid (org.eclipse.elk.alg.common.polyomino.structures.PlanarGrid)1 UniqueTriple (org.eclipse.elk.alg.common.utils.UniqueTriple)1 DCDirection (org.eclipse.elk.alg.disco.graph.DCDirection)1 DCPolyomino (org.eclipse.elk.alg.disco.structures.DCPolyomino)1 KVector (org.eclipse.elk.core.math.KVector)1 Pair (org.eclipse.elk.core.util.Pair)1 Triple (org.eclipse.elk.core.util.Triple)1