mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-10 09:12:09 +10:00
reorg area calc code
This commit is contained in:
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
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<Area> areas, Set<Connection> connections) {
|
||||||
|
boolean isChanged = false;
|
||||||
|
|
||||||
|
List<Area> newAreas = new ArrayList<Area>();
|
||||||
|
List<Boolean> consumed = new ArrayList<Boolean>();
|
||||||
|
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<Area> tryAreaBreakout(Area a) {
|
||||||
|
List<Area> toReturn = new ArrayList<Area>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,9 @@
|
|||||||
package org.diylc.presenter;
|
package org.diylc.presenter;
|
||||||
|
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.diylc.core.IDIYComponent;
|
import org.diylc.core.IDIYComponent;
|
||||||
import org.diylc.core.measures.Size;
|
import org.diylc.core.measures.Size;
|
||||||
@@ -56,5 +58,24 @@ public class CalcUtils {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void expandConnections(Set<Connection> connections) {
|
||||||
|
Set<Connection> toAdd = new HashSet<Connection>();
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ import java.awt.RenderingHints;
|
|||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.Area;
|
import java.awt.geom.Area;
|
||||||
import java.awt.geom.Line2D;
|
import java.awt.geom.Line2D;
|
||||||
import java.awt.geom.Path2D;
|
|
||||||
import java.awt.geom.PathIterator;
|
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -631,127 +629,15 @@ public class DrawingManager {
|
|||||||
for (int i = 0; i < preliminaryAreas.size(); i++) {
|
for (int i = 0; i < preliminaryAreas.size(); i++) {
|
||||||
Area a = preliminaryAreas.get(i);
|
Area a = preliminaryAreas.get(i);
|
||||||
if (checkBreakout.get(i))
|
if (checkBreakout.get(i))
|
||||||
areas.addAll(tryBreakout(a));
|
areas.addAll(AreaUtils.tryAreaBreakout(a));
|
||||||
else
|
else
|
||||||
areas.add(a);
|
areas.add(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
expandConnections(connections);
|
CalcUtils.expandConnections(connections);
|
||||||
|
|
||||||
crunchAreas(areas, connections);
|
AreaUtils.crunchAreas(areas, connections);
|
||||||
|
|
||||||
return areas;
|
return areas;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void expandConnections(Set<Connection> connections) {
|
|
||||||
Set<Connection> toAdd = new HashSet<Connection>();
|
|
||||||
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<Area> areas, Set<Connection> connections) {
|
|
||||||
boolean isChanged = false;
|
|
||||||
|
|
||||||
List<Area> newAreas = new ArrayList<Area>();
|
|
||||||
List<Boolean> consumed = new ArrayList<Boolean>();
|
|
||||||
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<Area> tryBreakout(Area a) {
|
|
||||||
List<Area> toReturn = new ArrayList<Area>();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3141,7 +3141,7 @@ public class Presenter implements IPlugInPort {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drawingManager.expandConnections(connections);
|
CalcUtils.expandConnections(connections);
|
||||||
|
|
||||||
return new ArrayList<Connection>(connections);
|
return new ArrayList<Connection>(connections);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user