diff --git a/diylc/diylc-core/src/org/diylc/presenter/AreaUtils.java b/diylc/diylc-core/src/org/diylc/presenter/AreaUtils.java new file mode 100644 index 00000000..4a8674e7 --- /dev/null +++ b/diylc/diylc-core/src/org/diylc/presenter/AreaUtils.java @@ -0,0 +1,125 @@ +/* + + DIY Layout Creator (DIYLC). + Copyright (c) 2009-2018 held jointly by the individual authors. + + This file is part of DIYLC. + + DIYLC is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + DIYLC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DIYLC. If not, see . + +*/ +package org.diylc.presenter; + +import java.awt.geom.Area; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class AreaUtils { + + /** + * Merges all areas that either overlap or are joined by connections. + * + * @param areas + * @param connections + * @return + */ + public static boolean crunchAreas(List areas, Set connections) { + boolean isChanged = false; + + List newAreas = new ArrayList(); + List consumed = new ArrayList(); + for (int i = 0; i < areas.size(); i++) { + consumed.add(false); + } + for (int i = 0; i < areas.size(); i++) { + for (int j = i + 1; j < areas.size(); j++) { + if (consumed.get(j)) + continue; + Area a1 = areas.get(i); + Area a2 = areas.get(j); + Area intersection = null; + if (a1.getBounds2D().intersects(a2.getBounds())) { + intersection = new Area(a1); + intersection.intersect(a2); + } + // if the two areas intersect, make a union and consume the second area + if (intersection != null && !intersection.isEmpty()) { + a1.add(a2); + consumed.set(j, true); + } else { // maybe there's a connection between them + for (Connection p : connections) { // use getBounds to optimize the computation, don't get into complex math if not needed + if ((a1.getBounds().contains(p.getP1()) && a2.getBounds().contains(p.getP2()) && a1.contains(p.getP1()) && a2.contains(p.getP2())) || + (a1.getBounds().contains(p.getP2()) && a2.getBounds().contains(p.getP1())) && a1.contains(p.getP2()) && a2.contains(p.getP1())) { + a1.add(a2); + consumed.set(j, true); + break; + } + } + } + } + } + for (int i = 0; i < areas.size(); i++) + if (!consumed.get(i)) + newAreas.add(areas.get(i)); + else + isChanged = true; + + if (isChanged) { + areas.clear(); + areas.addAll(newAreas); + crunchAreas(areas, connections); + } + + return isChanged; + } + + public static List tryAreaBreakout(Area a) { + List toReturn = new ArrayList(); + Path2D p = null; + PathIterator pathIterator = a.getPathIterator(null); + while (!pathIterator.isDone()) { + double[] coord = new double[6]; + int type = pathIterator.currentSegment(coord); + switch (type) { + case PathIterator.SEG_MOVETO: + if (p != null) { + Area partArea = new Area(p); + toReturn.add(partArea); + } + p = new Path2D.Double(); + p.moveTo(coord[0], coord[1]); + break; + case PathIterator.SEG_LINETO: + p.lineTo(coord[0], coord[1]); + break; + case PathIterator.SEG_CUBICTO: + p.curveTo(coord[0], coord[1], coord[2], coord[3], coord[4], coord[5]); + break; + case PathIterator.SEG_QUADTO: + p.quadTo(coord[0], coord[1], coord[2], coord[3]); + break; + } + pathIterator.next(); + } + if (p != null) { + Area partArea = new Area(p); + toReturn.add(partArea); + } + + return toReturn; + } +} diff --git a/diylc/diylc-core/src/org/diylc/presenter/CalcUtils.java b/diylc/diylc-core/src/org/diylc/presenter/CalcUtils.java index 204255e6..c74b9324 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/CalcUtils.java +++ b/diylc/diylc-core/src/org/diylc/presenter/CalcUtils.java @@ -22,7 +22,9 @@ package org.diylc.presenter; import java.awt.Point; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.diylc.core.IDIYComponent; import org.diylc.core.measures.Size; @@ -56,5 +58,24 @@ public class CalcUtils { return; } } + } + + public static void expandConnections(Set connections) { + Set toAdd = new HashSet(); + for (Connection c1 : connections) + for (Connection c2 : connections) { + if (c1 == c2) + continue; + if (c1.getP1().distance(c2.getP1()) < DrawingManager.CONTROL_POINT_SIZE) + toAdd.add(new Connection(c1.getP2(), c2.getP2())); + if (c1.getP1().distance(c2.getP2()) < DrawingManager.CONTROL_POINT_SIZE) + toAdd.add(new Connection(c1.getP2(), c2.getP1())); + if (c1.getP2().distance(c2.getP1()) < DrawingManager.CONTROL_POINT_SIZE) + toAdd.add(new Connection(c1.getP1(), c2.getP2())); + if (c1.getP2().distance(c2.getP2()) < DrawingManager.CONTROL_POINT_SIZE) + toAdd.add(new Connection(c1.getP1(), c2.getP1())); + } + if (connections.addAll(toAdd)) + expandConnections(connections); } } diff --git a/diylc/diylc-core/src/org/diylc/presenter/DrawingManager.java b/diylc/diylc-core/src/org/diylc/presenter/DrawingManager.java index 9a8ff14a..6649fa36 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/DrawingManager.java +++ b/diylc/diylc-core/src/org/diylc/presenter/DrawingManager.java @@ -29,8 +29,6 @@ import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.Line2D; -import java.awt.geom.Path2D; -import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collection; @@ -631,127 +629,15 @@ public class DrawingManager { for (int i = 0; i < preliminaryAreas.size(); i++) { Area a = preliminaryAreas.get(i); if (checkBreakout.get(i)) - areas.addAll(tryBreakout(a)); + areas.addAll(AreaUtils.tryAreaBreakout(a)); else areas.add(a); } - expandConnections(connections); + CalcUtils.expandConnections(connections); - crunchAreas(areas, connections); + AreaUtils.crunchAreas(areas, connections); return areas; - } - - public void expandConnections(Set connections) { - Set toAdd = new HashSet(); - for (Connection c1 : connections) - for (Connection c2 : connections) { - if (c1 == c2) - continue; - if (c1.getP1().distance(c2.getP1()) < CONTROL_POINT_SIZE) - toAdd.add(new Connection(c1.getP2(), c2.getP2())); - if (c1.getP1().distance(c2.getP2()) < CONTROL_POINT_SIZE) - toAdd.add(new Connection(c1.getP2(), c2.getP1())); - if (c1.getP2().distance(c2.getP1()) < CONTROL_POINT_SIZE) - toAdd.add(new Connection(c1.getP1(), c2.getP2())); - if (c1.getP2().distance(c2.getP2()) < CONTROL_POINT_SIZE) - toAdd.add(new Connection(c1.getP1(), c2.getP1())); - } - if (connections.addAll(toAdd)) - expandConnections(connections); - } - - /** - * Merges all areas that either overlap or are joined by connections. - * - * @param areas - * @param connections - * @return - */ - private boolean crunchAreas(List areas, Set connections) { - boolean isChanged = false; - - List newAreas = new ArrayList(); - List consumed = new ArrayList(); - for (int i = 0; i < areas.size(); i++) { - consumed.add(false); - } - for (int i = 0; i < areas.size(); i++) { - for (int j = i + 1; j < areas.size(); j++) { - if (consumed.get(j)) - continue; - Area a1 = areas.get(i); - Area a2 = areas.get(j); - Area intersection = null; - if (a1.getBounds2D().intersects(a2.getBounds())) { - intersection = new Area(a1); - intersection.intersect(a2); - } - // if the two areas intersect, make a union and consume the second area - if (intersection != null && !intersection.isEmpty()) { - a1.add(a2); - consumed.set(j, true); - } else { // maybe there's a connection between them - for (Connection p : connections) { // use getBounds to optimize the computation, don't get into complex math if not needed - if ((a1.getBounds().contains(p.getP1()) && a2.getBounds().contains(p.getP2()) && a1.contains(p.getP1()) && a2.contains(p.getP2())) || - (a1.getBounds().contains(p.getP2()) && a2.getBounds().contains(p.getP1())) && a1.contains(p.getP2()) && a2.contains(p.getP1())) { - a1.add(a2); - consumed.set(j, true); - break; - } - } - } - } - } - for (int i = 0; i < areas.size(); i++) - if (!consumed.get(i)) - newAreas.add(areas.get(i)); - else - isChanged = true; - - if (isChanged) { - areas.clear(); - areas.addAll(newAreas); - crunchAreas(areas, connections); - } - - return isChanged; - } - - private List tryBreakout(Area a) { - List toReturn = new ArrayList(); - Path2D p = null; - PathIterator pathIterator = a.getPathIterator(null); - while (!pathIterator.isDone()) { - double[] coord = new double[6]; - int type = pathIterator.currentSegment(coord); - switch (type) { - case PathIterator.SEG_MOVETO: - if (p != null) { - Area partArea = new Area(p); - toReturn.add(partArea); - } - p = new Path2D.Double(); - p.moveTo(coord[0], coord[1]); - break; - case PathIterator.SEG_LINETO: - p.lineTo(coord[0], coord[1]); - break; - case PathIterator.SEG_CUBICTO: - p.curveTo(coord[0], coord[1], coord[2], coord[3], coord[4], coord[5]); - break; - case PathIterator.SEG_QUADTO: - p.quadTo(coord[0], coord[1], coord[2], coord[3]); - break; - } - pathIterator.next(); - } - if (p != null) { - Area partArea = new Area(p); - toReturn.add(partArea); - } - - return toReturn; - } + } } diff --git a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java index eeeb5d6d..d38701bf 100644 --- a/diylc/diylc-core/src/org/diylc/presenter/Presenter.java +++ b/diylc/diylc-core/src/org/diylc/presenter/Presenter.java @@ -3141,7 +3141,7 @@ public class Presenter implements IPlugInPort { } } - drawingManager.expandConnections(connections); + CalcUtils.expandConnections(connections); return new ArrayList(connections); }