001    package ifs.example.rpp;
002    
003    import ifs.model.*;
004    import ifs.util.*;
005    import java.util.*;
006    
007    /**
008     * Resource constraint (rectangular area where the rectangles are to be placed). It prohibits overlapping of the placed rectangles.
009     * 
010     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
011     * @version 1.0
012     */
013    public class ResourceConstraint extends Constraint {
014        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(ResourceConstraint.class);
015        private Variable[][] iResource;
016        private int iWidth, iHeight;
017        
018        /** 
019         * Constructor.
020         * @param width area width
021         * @param height area height
022         */
023        public ResourceConstraint(int width, int height) {
024            super();
025            iWidth = width;
026            iHeight = height;
027            iResource = new Variable[width][height];
028            for (int x = 0; x < width; x++)
029                for (int y = 0; y < height; y++)
030                    iResource[x][y] = null;
031        }
032        
033        /**
034         * Compute conflicts with the given placement of the rectangle.
035         * This means the rectangles which are already placed and which are overlapping with the given assignment.
036         */
037        public void computeConflicts(Value value, Set conflicts) {
038            Rectangle rectangle = (Rectangle)value.variable();
039            Location placement = (Location)value;
040            for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
041                for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++)
042                    if (iResource[x][y] != null)
043                        conflicts.add(iResource[x][y].getAssignment());
044        }
045        
046        /**
047         * Returns true if there is a rectangle which overlaps with the given assignment.
048         */
049        public boolean inConflict(Value value) {
050            Rectangle rectangle = (Rectangle)value.variable();
051            Location placement = (Location)value;
052            for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
053                for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++)
054                    if (iResource[x][y] != null)
055                        return true;
056            return false;
057        }
058        
059        /**
060         * Returns true if the given rectangles (assignments) do not overlap.
061         */
062        public boolean isConsistent(Value value1, Value value2) {
063            Rectangle r1 = (Rectangle)value1.variable();
064            Location p1 = (Location)value1;
065            Rectangle r2 = (Rectangle)value2.variable();
066            Location p2 = (Location)value2;
067            if (p2.getX() + r2.getWidth() <= p1.getX()) return true;
068            if (p2.getX() >= p1.getX() + r1.getWidth()) return true;
069            if (p2.getY() + r2.getHeight() <= p1.getY()) return true;
070            if (p2.getY() >= p1.getY() + r1.getHeight()) return true;
071            return false;
072        }
073        
074        /**
075         * Notification, when a rectangle is placed.
076         * It memorizes the rectangle's new position in 2D ([0..width][0..height]) array.
077         * It is used for faster lookup when computing conflicts.
078         */
079        public void assigned(long iteration, Value value) {
080            super.assigned(iteration, value);
081            Rectangle rectangle = (Rectangle)value.variable();
082            Location placement = (Location)value;
083            for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
084                for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++) {
085                    iResource[x][y] = value.variable();
086                }
087        }
088        
089        /**
090         * Notification, when a rectangle is unplaced.
091         * It removes the rectangle from the 2D ([0..width][0..height]) array.
092         */
093        public void unassigned(long iteration, Value value) {
094            super.unassigned(iteration, value);
095            Rectangle rectangle = (Rectangle)value.variable();
096            Location placement = (Location)value;
097            for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
098                for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++) {
099                    iResource[x][y] = null;
100                }
101        }
102        
103        public void check() {
104            sLogger.debug("check");
105            for (Enumeration e=variables().elements();e.hasMoreElements();) {
106                Rectangle rectangle = (Rectangle)e.nextElement();
107                Location placement = (Location)rectangle.getAssignment();
108                if (placement==null) {
109                    sLogger.warn("Rectangle "+rectangle.getName()+" is not assigned.");
110                    continue;
111                }
112                sLogger.debug("Checking "+rectangle.getName()+"    (assigned:"+placement.getName()+", prohibited:"+rectangle.isProhibited(placement.getX(),placement.getY())+", initial:"+rectangle.getInitialAssignment()+", prohibited:["+rectangle.getProhibitedX()+","+rectangle.getProhibitedY()+"])");
113                if (placement.getX()==rectangle.getProhibitedX() || placement.getY()==rectangle.getProhibitedY())
114                    sLogger.error("Placement is prohibited.");
115                if (placement.getX()<rectangle.getMinX() || placement.getX()>rectangle.getMaxX() ||
116                    placement.getY()<rectangle.getMinY() || placement.getY()>rectangle.getMaxY())
117                    sLogger.error("Placement is outside bounds.");
118                for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
119                    for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++) {
120                            if (iResource[x][y]==null || !iResource[x][y].equals(rectangle))
121                                sLogger.error("Problem at ["+x+","+y+"], "+iResource[x][y]+" is assigned there.");
122                    }
123            }
124            sLogger.debug(toString());
125        }
126        
127        /**
128         * String representation of the constraint (for debugging and printing purposes).
129         */
130        public String toString() {
131            StringBuffer sb = new StringBuffer("ResourceConstraint{\n        ");
132            for (int y = 0; y < iHeight; y++) {
133                for (int x = 0; x < iWidth; x++) {
134                    sb.append(ToolBox.trim( iResource[x][y] == null ? "" : ((Rectangle)iResource[x][y]).getName().substring(4), 4));
135                }
136                sb.append("\n        ");
137            }
138            sb.append("\n      }");
139            return sb.toString();
140        }
141    }