/******************************************************************************* * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package hr.fer.zemris.vhdllab.applets.editor.schema2.model.queries; import hr.fer.zemris.vhdllab.applets.editor.schema2.constants.Constants; import hr.fer.zemris.vhdllab.applets.editor.schema2.enums.EPropertyChange; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IQuery; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IQueryResult; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaInfo; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaWire; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Caseless; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.PlacedComponent; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Rect2d; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.SchemaPort; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.WireSegment; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.XYLocation; import hr.fer.zemris.vhdllab.applets.editor.schema2.model.QueryResult; import hr.fer.zemris.vhdllab.applets.editor.schema2.model.queries.misc.WalkabilityMap; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Analizira citav schematic i stvara mapu prolaznosti, koja se kasnije * moze koristiti npr. u algoritmu za trazenje najkracih puteva za zice. * * Prolaznost je pohranjena kao WalkabilityMap pod kljucem KEY_WALKABILITY. * * @author Axel * */ public class InspectWalkability implements IQuery { /* static fields */ public static final String KEY_WALKABILITY = "walkability_map"; private static final String QUERY_NAME = InspectWalkability.class.getSimpleName(); private static final int STEP = Constants.GRID_SIZE; private static final Integer ALLUNWALKABLE = 0; private static final Integer HORIZONTALLY_WALKABLE = WalkabilityMap.FROM_WEST | WalkabilityMap.FROM_EAST; private static final Integer VERTICALLY_WALKABLE = WalkabilityMap.FROM_NORTH | WalkabilityMap.FROM_SOUTH; private static final List<EPropertyChange> propdepend = new ArrayList<EPropertyChange>(); private static final List<EPropertyChange> ro_pd = Collections.unmodifiableList(propdepend); { propdepend.add(EPropertyChange.CANVAS_CHANGE); propdepend.add(EPropertyChange.PROPERTY_CHANGE); } /* private fields */ private boolean quick; /* ctors */ /** * Standardni konstruktor. * @param quickinspect * Ako se ovaj parametar postavi u true, * query nece postavljati sve cvorove na mapi prolaznosti * u false za pojedinu komponentu, vec samo za njene rubove. * Ovo je prihvatljivo za algoritme trazenja puteva koji idu * cvor po cvor, a uvelike smanjuje slozenost. */ public InspectWalkability(boolean quickinspect) { quick = quickinspect; } /* methods */ public List<EPropertyChange> getPropertyDependency() { return ro_pd; } public String getQueryName() { return QUERY_NAME; } public boolean isCacheable() { return true; } public IQueryResult performQuery(ISchemaInfo info) { int minx = Integer.MAX_VALUE, miny = Integer.MAX_VALUE; int maxx = Integer.MIN_VALUE, maxy = Integer.MIN_VALUE; WalkabilityMap walkability = new WalkabilityMap(); /* iterate through components and map unwalkable grid points */ for (PlacedComponent placed : info.getComponents()) { /* update bounds */ int tx = placed.pos.x + placed.comp.getWidth(), ty = placed.pos.y + placed.comp.getHeight(); if (placed.pos.x < minx) minx = placed.pos.x; if (placed.pos.y < miny) miny = placed.pos.y; if (tx > maxx) maxx = tx; if (ty > maxy) maxy = ty; /* handle walkability */ if (quick) quickHandleCmp(placed, tx, ty, walkability); else handleCmp(placed, tx, ty, walkability); /* handle pins */ handleSchemaPorts(placed, walkability); } /* iterate through wires and map unwalkable grid points */ for (ISchemaWire wire : info.getWires()) { /* update bounds */ Rect2d wb = wire.getBounds(); if (wb.left < minx) minx = wb.left; if (wb.top < miny) miny = wb.top; if ((wb.left + wb.width) > maxx) maxx = wb.left + wb.width; if ((wb.top + wb.height) > maxy) maxy = wb.top + wb.height; /* handle walkability */ handleWire(wire, walkability); } /* set bounds to walkability map */ walkability.width = ((maxx - minx) / STEP + 1) * STEP; walkability.height = ((maxy - miny) / STEP + 1) * STEP; return new QueryResult(KEY_WALKABILITY, walkability); } private static void handleSchemaPorts(PlacedComponent placed, WalkabilityMap walkability) { int wdt = placed.comp.getWidth(), hgt = placed.comp.getHeight(); for (SchemaPort sp : placed.comp.getSchemaPorts()) { if (!Caseless.isNullOrEmpty(sp.getMapping())) continue; XYLocation offset = sp.getOffset(); XYLocation sploc = new XYLocation(placed.pos.x + offset.x, placed.pos.y + offset.y); Integer walkstatus = ALLUNWALKABLE; if (offset.x == 0) { walkstatus = walkstatus | WalkabilityMap.FROM_WEST; } if (offset.x == wdt) { walkstatus = walkstatus | WalkabilityMap.FROM_EAST; } if (offset.y == 0) { walkstatus = walkstatus | WalkabilityMap.FROM_NORTH; } if (offset.y == hgt) { walkstatus = walkstatus | WalkabilityMap.FROM_SOUTH; } walkability.walkmap.put(sploc, walkstatus); } } private static void handleCmp(PlacedComponent placed, int tox, int toy, WalkabilityMap walkability) { int fromx = placed.pos.x, fromy = placed.pos.y; fromx = (fromx / STEP + (((fromx % STEP) == 0 || fromx < 0) ? (0) : (1))) * STEP; fromy = (fromy / STEP + (((fromy % STEP) == 0 || fromy < 0) ? (0) : (1))) * STEP; for (int i = fromx; i <= tox; i += STEP) { for (int j = fromy; j <= toy; j += STEP) { walkability.walkmap.put(new XYLocation(i, j), ALLUNWALKABLE); } } } private static void quickHandleCmp(PlacedComponent placed, int tox, int toy, WalkabilityMap walkability) { int fromx = placed.pos.x, fromy = placed.pos.y; fromx = (fromx / STEP + (((fromx % STEP) == 0 || fromx < 0) ? (0) : (1))) * STEP; fromy = (fromy / STEP + (((fromy % STEP) == 0 || fromy < 0) ? (0) : (1))) * STEP; tox = (tox / STEP + (((tox % STEP) == 0 || tox > 0) ? (0) : (-1))) * STEP; toy = (toy / STEP + (((toy % STEP) == 0 || toy > 0) ? (0) : (-1))) * STEP; for (int i = fromx; i <= tox; i += STEP) { walkability.walkmap.put(new XYLocation(i, fromy), ALLUNWALKABLE); walkability.walkmap.put(new XYLocation(i, toy), ALLUNWALKABLE); } toy -= STEP; fromy += STEP; for (int j = fromy; j <= toy; j += STEP) { walkability.walkmap.put(new XYLocation(fromx, j), ALLUNWALKABLE); walkability.walkmap.put(new XYLocation(tox, j), ALLUNWALKABLE); } } private static void handleWire(ISchemaWire wire, WalkabilityMap walkability) { for (WireSegment segment : wire.getSegments()) { XYLocation start = segment.getStart(), end; /* check if vertical */ if (segment.isVertical()) { /* check if it is aligned to grid */ if (start.x % STEP != 0) continue; /* handle it */ end = segment.getEnd(); if (start.y > end.y) { XYLocation tmp = start; start = end; end = tmp; } int fromy = (start.y / STEP + (((start.y % STEP) == 0 || start.y < 0) ? (0) : (1))) * STEP; int toy = (end.y / STEP + (((end.y % STEP) == 0 || end.y > 0) ? (0) : (-1))) * STEP; for (int j = fromy; j <= toy; j += STEP) { walkability.walkmap.put(new XYLocation(start.x, j), HORIZONTALLY_WALKABLE); } } else { /* check if it is aligned to grid */ if (start.y % STEP != 0) continue; /* handle it */ end = segment.getEnd(); if (start.x > end.x) { XYLocation tmp = start; start = end; end = tmp; } int fromx = (start.x / STEP + (((start.x % STEP) == 0 || start.x < 0) ? (0) : (1))) * STEP; int tox = (end.x / STEP + (((end.x % STEP) == 0 || end.x > 0) ? (0) : (-1))) * STEP; for (int i = fromx; i <= tox; i += STEP) { walkability.walkmap.put(new XYLocation(i, start.y), VERTICALLY_WALKABLE); } } } } @Override public boolean equals(Object obj) { if (obj == null || !(obj instanceof InspectWalkability)) return false; InspectWalkability other = (InspectWalkability)obj; return other.quick == this.quick; } @Override public int hashCode() { return (quick) ? (2) : (3); } }