this.cellHeight = options.renderingOptions.getCellHeight();
width = grid.getWidth() * cellWidth;
height = grid.getHeight() * cellHeight;
TextGrid workGrid = new TextGrid(grid);
workGrid.replaceTypeOnLine();
workGrid.replacePointMarkersOnLine();
if(DEBUG) workGrid.printDebug();
int width = grid.getWidth();
int height = grid.getHeight();
//split distinct shapes using AbstractionGrid
AbstractionGrid temp = new AbstractionGrid(workGrid, workGrid.getAllBoundaries());
ArrayList<CellSet> boundarySetsStep1 = temp.getDistinctShapes();
if(DEBUG){
System.out.println("******* Distinct shapes found using AbstractionGrid *******");
Iterator<CellSet> dit = boundarySetsStep1.iterator();
while (dit.hasNext()) {
CellSet set = dit.next();
set.printAsGrid();
}
System.out.println("******* Same set of shapes after processing them by filling *******");
}
//Find all the boundaries by using the special version of the filling method
//(fills in a different buffer than the buffer it reads from)
ArrayList<CellSet> boundarySetsStep2 = new ArrayList<CellSet>();
for(CellSet set : boundarySetsStep1) {
//the fill buffer keeps track of which cells have been
//filled already
TextGrid fillBuffer = new TextGrid(width * 3, height * 3);
for(int yi = 0; yi < height * 3; yi++){
for(int xi = 0; xi < width * 3; xi++){
if(fillBuffer.isBlank(xi, yi)){
TextGrid copyGrid = new AbstractionGrid(workGrid, set).getCopyOfInternalBuffer();
CellSet boundaries =
copyGrid
.findBoundariesExpandingFrom(copyGrid.new Cell(xi, yi));
if(boundaries.size() == 0) continue; //i'm not sure why these occur
boundarySetsStep2.add(boundaries.makeScaledOneThirdEquivalent());
copyGrid = new AbstractionGrid(workGrid, set).getCopyOfInternalBuffer();
CellSet filled =
copyGrid
.fillContinuousArea(copyGrid.new Cell(xi, yi), '*');
fillBuffer.fillCellsWith(filled, '*');
fillBuffer.fillCellsWith(boundaries, '-');
if(DEBUG){
//System.out.println("Fill buffer:");
//fillBuffer.printDebug();
boundaries.makeScaledOneThirdEquivalent().printAsGrid();
System.out.println("-----------------------------------");
}
}
}
}
}
if (DEBUG)
System.out.println("******* Removed duplicates *******");
boundarySetsStep2 = CellSet.removeDuplicateSets(boundarySetsStep2);
if(DEBUG){
Iterator<CellSet> dit = boundarySetsStep2.iterator();
while (dit.hasNext()) {
CellSet set = dit.next();
set.printAsGrid();
}
}
int originalSize = boundarySetsStep2.size();
boundarySetsStep2 = CellSet.removeDuplicateSets(boundarySetsStep2);
if(DEBUG) {
System.out.println(
"******* Removed duplicates: there were "
+originalSize
+" shapes and now there are "
+boundarySetsStep2.size());
}
//split boundaries to open, closed and mixed
if (DEBUG)
System.out.println("******* First evaluation of openess *******");
ArrayList<CellSet> open = new ArrayList<CellSet>();
ArrayList<CellSet> closed = new ArrayList<CellSet>();
ArrayList<CellSet> mixed = new ArrayList<CellSet>();
Iterator<CellSet> sets = boundarySetsStep2.iterator();
while(sets.hasNext()){
CellSet set = (CellSet) sets.next();
int type = set.getType(workGrid);
if(type == CellSet.TYPE_CLOSED) closed.add(set);
else if(type == CellSet.TYPE_OPEN) open.add(set);
else if(type == CellSet.TYPE_MIXED) mixed.add(set);
if(DEBUG){
if(type == CellSet.TYPE_CLOSED) System.out.println("Closed boundaries:");
else if(type == CellSet.TYPE_OPEN) System.out.println("Open boundaries:");
else if(type == CellSet.TYPE_MIXED) System.out.println("Mixed boundaries:");
set.printAsGrid();
}
}
boolean hadToEliminateMixed = false;
if(mixed.size() > 0 && closed.size() > 0) {
// mixed shapes can be eliminated by
// subtracting all the closed shapes from them
if (DEBUG)
System.out.println("******* Eliminating mixed shapes (basic algorithm) *******");
hadToEliminateMixed = true;
//subtract from each of the mixed sets all the closed sets
sets = mixed.iterator();
while(sets.hasNext()){
CellSet set = (CellSet) sets.next();
Iterator<CellSet> closedSets = closed.iterator();
while(closedSets.hasNext()){
CellSet closedSet = closedSets.next();
set.subtractSet(closedSet);
}
// this is necessary because some mixed sets produce
// several distinct open sets after you subtract the
// closed sets from them
if(set.getType(workGrid) == CellSet.TYPE_OPEN) {
boundarySetsStep2.remove(set);
boundarySetsStep2.addAll(set.breakIntoDistinctBoundaries(workGrid));
}
}
} else if(mixed.size() > 0 && closed.size() == 0) {
// no closed shape exists, will have to
// handle mixed shape on its own
// an example of this case is the following:
// +-----+
// | A |C B
// + ---+-------------------
// | |
// +-----+
hadToEliminateMixed = true;
if (DEBUG)
System.out.println("******* Eliminating mixed shapes (advanced algorithm for truly mixed shapes) *******");
sets = mixed.iterator();
while(sets.hasNext()){
CellSet set = (CellSet) sets.next();
boundarySetsStep2.remove(set);
boundarySetsStep2.addAll(set.breakTrulyMixedBoundaries(workGrid));
}
} else {
if (DEBUG)
System.out.println("No mixed shapes found. Skipped mixed shape elimination step");
}
if(hadToEliminateMixed){
if (DEBUG)
System.out.println("******* Second evaluation of openess *******");
//split boundaries again to open, closed and mixed
open = new ArrayList<CellSet>();
closed = new ArrayList<CellSet>();
mixed = new ArrayList<CellSet>();
sets = boundarySetsStep2.iterator();
while(sets.hasNext()){
CellSet set = (CellSet) sets.next();
int type = set.getType(workGrid);
if(type == CellSet.TYPE_CLOSED) closed.add(set);
else if(type == CellSet.TYPE_OPEN) open.add(set);
else if(type == CellSet.TYPE_MIXED) mixed.add(set);
if(DEBUG){
if(type == CellSet.TYPE_CLOSED) System.out.println("Closed boundaries:");
else if(type == CellSet.TYPE_OPEN) System.out.println("Open boundaries:");
else if(type == CellSet.TYPE_MIXED) System.out.println("Mixed boundaries:");
set.printAsGrid();
}
}
}
boolean removedAnyObsolete = removeObsoleteShapes(workGrid, closed);
boolean allCornersRound = false;
if(options.processingOptions.areAllCornersRound()) allCornersRound = true;
//make shapes from the boundary sets
//make closed shapes
if(DEBUG_MAKE_SHAPES) {
System.out.println("***** MAKING SHAPES FROM BOUNDARY SETS *****");
System.out.println("***** CLOSED: *****");
}
ArrayList<DiagramComponent> closedShapes = new ArrayList<DiagramComponent>();
sets = closed.iterator();
while(sets.hasNext()){
CellSet set = (CellSet) sets.next();
if(DEBUG_MAKE_SHAPES) {
set.printAsGrid();
}
DiagramComponent shape = DiagramComponent.createClosedFromBoundaryCells(workGrid, set, cellWidth, cellHeight, allCornersRound);
if(shape != null){
if(shape instanceof DiagramShape){
addToShapes((DiagramShape) shape);
closedShapes.add(shape);
} else if(shape instanceof CompositeDiagramShape)
addToCompositeShapes((CompositeDiagramShape) shape);
}
}
if(options.processingOptions.performSeparationOfCommonEdges())
separateCommonEdges(closedShapes);
//make open shapes
sets = open.iterator();
while(sets.hasNext()){
CellSet set = (CellSet) sets.next();
if(set.size() == 1){ //single cell "shape"
TextGrid.Cell cell = (TextGrid.Cell) set.getFirst();
if(!grid.cellContainsDashedLineChar(cell)) {
DiagramShape shape = DiagramShape.createSmallLine(workGrid, cell, cellWidth, cellHeight);
if(shape != null) {
addToShapes(shape);
shape.connectEndsToAnchors(workGrid, this);
}
}
} else { //normal shape
if (DEBUG)
System.out.println(set.getCellsAsString());
DiagramComponent shape =
CompositeDiagramShape
.createOpenFromBoundaryCells(
workGrid, set, cellWidth, cellHeight, allCornersRound);
if(shape != null){
if(shape instanceof CompositeDiagramShape){
addToCompositeShapes((CompositeDiagramShape) shape);
((CompositeDiagramShape) shape).connectEndsToAnchors(workGrid, this);
} else if(shape instanceof DiagramShape) {
addToShapes((DiagramShape) shape);
((DiagramShape) shape).connectEndsToAnchors(workGrid, this);
((DiagramShape) shape).moveEndsToCellEdges(grid, this);
}
}
}
}
//assign color codes to shapes
//TODO: text on line should not change its color
Iterator<CellColorPair> cellColorPairs = grid.findColorCodes().iterator();
while(cellColorPairs.hasNext()){
TextGrid.CellColorPair pair =
(TextGrid.CellColorPair) cellColorPairs.next();
ShapePoint point =
new ShapePoint(getCellMidX(pair.cell), getCellMidY(pair.cell));
DiagramShape containingShape = findSmallestShapeContaining(point);
if(containingShape != null)
containingShape.setFillColor(pair.color);
}
//assign markup to shapes
Iterator<CellTagPair> cellTagPairs = grid.findMarkupTags().iterator();
while(cellTagPairs.hasNext()){
TextGrid.CellTagPair pair =
(TextGrid.CellTagPair) cellTagPairs.next();
ShapePoint point =
new ShapePoint(getCellMidX(pair.cell), getCellMidY(pair.cell));
DiagramShape containingShape = findSmallestShapeContaining(point);
//this tag is not within a shape, skip
if(containingShape == null) continue;
//TODO: the code below could be a lot more concise
if(pair.tag.equals("d")){
CustomShapeDefinition def =
options.processingOptions.getFromCustomShapes("d");
if(def == null)
containingShape.setType(DiagramShape.TYPE_DOCUMENT);
else {
containingShape.setType(DiagramShape.TYPE_CUSTOM);
containingShape.setDefinition(def);
}
} else if(pair.tag.equals("s")){
CustomShapeDefinition def =
options.processingOptions.getFromCustomShapes("s");
if(def == null)
containingShape.setType(DiagramShape.TYPE_STORAGE);
else {
containingShape.setType(DiagramShape.TYPE_CUSTOM);
containingShape.setDefinition(def);
}
} else if(pair.tag.equals("io")){
CustomShapeDefinition def =
options.processingOptions.getFromCustomShapes("io");
if(def == null)
containingShape.setType(DiagramShape.TYPE_IO);
else {
containingShape.setType(DiagramShape.TYPE_CUSTOM);
containingShape.setDefinition(def);
}
} else if(pair.tag.equals("c")){
CustomShapeDefinition def =
options.processingOptions.getFromCustomShapes("c");
if(def == null)
containingShape.setType(DiagramShape.TYPE_DECISION);
else {
containingShape.setType(DiagramShape.TYPE_CUSTOM);
containingShape.setDefinition(def);
}
} else if(pair.tag.equals("mo")){
CustomShapeDefinition def =
options.processingOptions.getFromCustomShapes("mo");
if(def == null)
containingShape.setType(DiagramShape.TYPE_MANUAL_OPERATION);
else {
containingShape.setType(DiagramShape.TYPE_CUSTOM);
containingShape.setDefinition(def);
}
} else if(pair.tag.equals("tr")){
CustomShapeDefinition def =
options.processingOptions.getFromCustomShapes("tr");
if(def == null)
containingShape.setType(DiagramShape.TYPE_TRAPEZOID);
else {
containingShape.setType(DiagramShape.TYPE_CUSTOM);
containingShape.setDefinition(def);
}
} else if(pair.tag.equals("o")){
CustomShapeDefinition def =
options.processingOptions.getFromCustomShapes("o");
if(def == null)
containingShape.setType(DiagramShape.TYPE_ELLIPSE);
else {
containingShape.setType(DiagramShape.TYPE_CUSTOM);
containingShape.setDefinition(def);
}
} else {
CustomShapeDefinition def =
options.processingOptions.getFromCustomShapes(pair.tag);
containingShape.setType(DiagramShape.TYPE_CUSTOM);
containingShape.setDefinition(def);
}
}
//make arrowheads
Iterator<Cell> arrowheadCells = workGrid.findArrowheads().iterator();
while(arrowheadCells.hasNext()){
TextGrid.Cell cell = arrowheadCells.next();
DiagramShape arrowhead = DiagramShape.createArrowhead(workGrid, cell, cellWidth, cellHeight);
if(arrowhead != null) addToShapes(arrowhead);
else System.err.println("Could not create arrowhead shape. Unexpected error.");
}
//make point markers
Iterator<TextGrid.Cell> markersIt = grid.getPointMarkersOnLine().iterator();
while (markersIt.hasNext()) {
TextGrid.Cell cell = markersIt.next();
DiagramShape mark = new DiagramShape();
mark.addToPoints(new ShapePoint(
getCellMidX(cell),
getCellMidY(cell)
));
mark.setType(DiagramShape.TYPE_POINT_MARKER);
mark.setFillColor(Color.white);
shapes.add(mark);
}
removeDuplicateShapes();
if(DEBUG) System.out.println("Shape count: "+shapes.size());
if(DEBUG) System.out.println("Composite shape count: "+compositeShapes.size());
//copy again
workGrid = new TextGrid(grid);
workGrid.removeNonText();
// ****** handle text *******
//break up text into groups
TextGrid textGroupGrid = new TextGrid(workGrid);
CellSet gaps = textGroupGrid.getAllBlanksBetweenCharacters();
//kludge
textGroupGrid.fillCellsWith(gaps, '|');
CellSet nonBlank = textGroupGrid.getAllNonBlank();
ArrayList<CellSet> textGroups = nonBlank.breakIntoDistinctBoundaries();
if(DEBUG) System.out.println(textGroups.size()+" text groups found");
Font font = FontMeasurer.instance().getFontFor(cellHeight);
Iterator<CellSet> textGroupIt = textGroups.iterator();
while(textGroupIt.hasNext()){
CellSet textGroupCellSet = (CellSet) textGroupIt.next();
TextGrid isolationGrid = new TextGrid(width, height);
workGrid.copyCellsTo(textGroupCellSet, isolationGrid);
ArrayList<CellStringPair> strings = isolationGrid.findStrings();
Iterator<CellStringPair> it = strings.iterator();
while(it.hasNext()){
TextGrid.CellStringPair pair = it.next();
TextGrid.Cell cell = pair.cell;
String string = pair.string;
if (DEBUG)
System.out.println("Found string "+string);
TextGrid.Cell lastCell = isolationGrid.new Cell(cell.x + string.length() - 1, cell.y);
int minX = getCellMinX(cell);
int y = getCellMaxY(cell);
int maxX = getCellMaxX(lastCell);
DiagramText textObject;
if(FontMeasurer.instance().getWidthFor(string, font) > maxX - minX){ //does not fit horizontally
Font lessWideFont = FontMeasurer.instance().getFontFor(maxX - minX, string);
textObject = new DiagramText(minX, y, string, lessWideFont);
} else textObject = new DiagramText(minX, y, string, font);
textObject.centerVerticallyBetween(getCellMinY(cell), getCellMaxY(cell));
//TODO: if the strings start with bullets they should be aligned to the left
//position text correctly
int otherStart = isolationGrid.otherStringsStartInTheSameColumn(cell);
int otherEnd = isolationGrid.otherStringsEndInTheSameColumn(lastCell);
if(0 == otherStart && 0 == otherEnd) {
textObject.centerHorizontallyBetween(minX, maxX);
} else if(otherEnd > 0 && otherStart == 0) {
textObject.alignRightEdgeTo(maxX);
} else if(otherEnd > 0 && otherStart > 0){