/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution 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. * * logisim-evolution 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 logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.cburch.logisim.tools.move; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Set; import com.cburch.logisim.circuit.Wire; import com.cburch.logisim.comp.Component; import com.cburch.logisim.data.Bounds; import com.cburch.logisim.data.Location; class AvoidanceMap { static AvoidanceMap create(Collection<Component> elements, int dx, int dy) { AvoidanceMap ret = new AvoidanceMap(new HashMap<Location, String>()); ret.markAll(elements, dx, dy); return ret; } private final HashMap<Location, String> avoid; private AvoidanceMap(HashMap<Location, String> map) { avoid = map; } public AvoidanceMap cloneMap() { return new AvoidanceMap(new HashMap<Location, String>(avoid)); } public Object get(Location loc) { return avoid.get(loc); } public void markAll(Collection<Component> elements, int dx, int dy) { // first we go through the components, saying that we should not // intersect with any point that lies within a component for (Component el : elements) { if (el instanceof Wire) { markWire((Wire) el, dx, dy); } else { markComponent(el, dx, dy); } } } public void markComponent(Component comp, int dx, int dy) { HashMap<Location, String> avoid = this.avoid; boolean translated = dx != 0 || dy != 0; Bounds bds = comp.getBounds(); int x0 = bds.getX() + dx; int y0 = bds.getY() + dy; int x1 = x0 + bds.getWidth(); int y1 = y0 + bds.getHeight(); x0 += 9 - (x0 + 9) % 10; y0 += 9 - (y0 + 9) % 10; for (int x = x0; x <= x1; x += 10) { for (int y = y0; y <= y1; y += 10) { Location loc = Location.create(x, y); // loc is most likely in the component, so go ahead and // put it into the map as if it is - and in the rare event // that loc isn't in the component, we can remove it. String prev = avoid.put(loc, Connector.ALLOW_NEITHER); if (prev != Connector.ALLOW_NEITHER) { Location baseLoc = translated ? loc.translate(-dx, -dy) : loc; if (!comp.contains(baseLoc)) { if (prev == null) { avoid.remove(loc); } else { avoid.put(loc, prev); } } } } } } public void markWire(Wire w, int dx, int dy) { HashMap<Location, String> avoid = this.avoid; boolean translated = dx != 0 || dy != 0; Location loc0 = w.getEnd0(); Location loc1 = w.getEnd1(); if (translated) { loc0 = loc0.translate(dx, dy); loc1 = loc1.translate(dx, dy); } avoid.put(loc0, Connector.ALLOW_NEITHER); avoid.put(loc1, Connector.ALLOW_NEITHER); int x0 = loc0.getX(); int y0 = loc0.getY(); int x1 = loc1.getX(); int y1 = loc1.getY(); if (x0 == x1) { // vertical wire for (Location loc : Wire.create(loc0, loc1)) { Object prev = avoid.put(loc, Connector.ALLOW_HORIZONTAL); if (prev == Connector.ALLOW_NEITHER || prev == Connector.ALLOW_VERTICAL) { avoid.put(loc, Connector.ALLOW_NEITHER); } } } else if (y0 == y1) { // horizontal wire for (Location loc : Wire.create(loc0, loc1)) { Object prev = avoid.put(loc, Connector.ALLOW_VERTICAL); if (prev == Connector.ALLOW_NEITHER || prev == Connector.ALLOW_HORIZONTAL) { avoid.put(loc, Connector.ALLOW_NEITHER); } } } else { // diagonal - shouldn't happen throw new RuntimeException("diagonal wires not supported"); } } public void print(PrintStream stream) { ArrayList<Location> list = new ArrayList<Location>(avoid.keySet()); Collections.sort(list); for (int i = 0, n = list.size(); i < n; i++) { stream.println(list.get(i) + ": " + avoid.get(list.get(i))); } } public void unmarkLocation(Location loc) { avoid.remove(loc); } public void unmarkWire(Wire w, Location deletedEnd, Set<Location> unmarkable) { Location loc0 = w.getEnd0(); Location loc1 = w.getEnd1(); if (unmarkable == null || unmarkable.contains(deletedEnd)) { avoid.remove(deletedEnd); } int x0 = loc0.getX(); int y0 = loc0.getY(); int x1 = loc1.getX(); int y1 = loc1.getY(); if (x0 == x1) { // vertical wire for (Location loc : w) { if (unmarkable == null || unmarkable.contains(deletedEnd)) { Object prev = avoid.remove(loc); if (prev != Connector.ALLOW_HORIZONTAL && prev != null) { avoid.put(loc, Connector.ALLOW_VERTICAL); } } } } else if (y0 == y1) { // horizontal wire for (Location loc : w) { if (unmarkable == null || unmarkable.contains(deletedEnd)) { Object prev = avoid.remove(loc); if (prev != Connector.ALLOW_VERTICAL && prev != null) { avoid.put(loc, Connector.ALLOW_HORIZONTAL); } } } } else { // diagonal - shouldn't happen throw new RuntimeException("diagonal wires not supported"); } } }