001    package net.sf.cpsolver.ifs.example.rpp;
002    
003    import java.util.*;
004    
005    import net.sf.cpsolver.ifs.model.*;
006    import net.sf.cpsolver.ifs.util.*;
007    
008    /**
009     * Resource constraint (rectangular area where the rectangles are to be placed). It prohibits overlapping of the placed rectangles.
010     * 
011     * @version
012     * IFS 1.1 (Iterative Forward Search)<br>
013     * Copyright (C) 2006 Tomáš Müller<br>
014     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
015     * Lazenska 391, 76314 Zlin, Czech Republic<br>
016     * <br>
017     * This library is free software; you can redistribute it and/or
018     * modify it under the terms of the GNU Lesser General Public
019     * License as published by the Free Software Foundation; either
020     * version 2.1 of the License, or (at your option) any later version.
021     * <br><br>
022     * This library is distributed in the hope that it will be useful,
023     * but WITHOUT ANY WARRANTY; without even the implied warranty of
024     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
025     * Lesser General Public License for more details.
026     * <br><br>
027     * You should have received a copy of the GNU Lesser General Public
028     * License along with this library; if not, write to the Free Software
029     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
030     */
031    public class ResourceConstraint extends Constraint {
032        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(ResourceConstraint.class);
033        private Variable[][] iResource;
034        private int iWidth, iHeight;
035        
036        /** 
037         * Constructor.
038         * @param width area width
039         * @param height area height
040         */
041        public ResourceConstraint(int width, int height) {
042            super();
043            iWidth = width;
044            iHeight = height;
045            iResource = new Variable[width][height];
046            for (int x = 0; x < width; x++)
047                for (int y = 0; y < height; y++)
048                    iResource[x][y] = null;
049        }
050        
051        /**
052         * Compute conflicts with the given placement of the rectangle.
053         * This means the rectangles which are already placed and which are overlapping with the given assignment.
054         */
055        public void computeConflicts(Value value, Set conflicts) {
056            Rectangle rectangle = (Rectangle)value.variable();
057            Location placement = (Location)value;
058            for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
059                for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++)
060                    if (iResource[x][y] != null)
061                        conflicts.add(iResource[x][y].getAssignment());
062        }
063        
064        /**
065         * Returns true if there is a rectangle which overlaps with the given assignment.
066         */
067        public boolean inConflict(Value value) {
068            Rectangle rectangle = (Rectangle)value.variable();
069            Location placement = (Location)value;
070            for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
071                for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++)
072                    if (iResource[x][y] != null)
073                        return true;
074            return false;
075        }
076        
077        /**
078         * Returns true if the given rectangles (assignments) do not overlap.
079         */
080        public boolean isConsistent(Value value1, Value value2) {
081            Rectangle r1 = (Rectangle)value1.variable();
082            Location p1 = (Location)value1;
083            Rectangle r2 = (Rectangle)value2.variable();
084            Location p2 = (Location)value2;
085            if (p2.getX() + r2.getWidth() <= p1.getX()) return true;
086            if (p2.getX() >= p1.getX() + r1.getWidth()) return true;
087            if (p2.getY() + r2.getHeight() <= p1.getY()) return true;
088            if (p2.getY() >= p1.getY() + r1.getHeight()) return true;
089            return false;
090        }
091        
092        /**
093         * Notification, when a rectangle is placed.
094         * It memorizes the rectangle's new position in 2D ([0..width][0..height]) array.
095         * It is used for faster lookup when computing conflicts.
096         */
097        public void assigned(long iteration, Value value) {
098            super.assigned(iteration, value);
099            Rectangle rectangle = (Rectangle)value.variable();
100            Location placement = (Location)value;
101            for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
102                for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++) {
103                    iResource[x][y] = value.variable();
104                }
105        }
106        
107        /**
108         * Notification, when a rectangle is unplaced.
109         * It removes the rectangle from the 2D ([0..width][0..height]) array.
110         */
111        public void unassigned(long iteration, Value value) {
112            super.unassigned(iteration, value);
113            Rectangle rectangle = (Rectangle)value.variable();
114            Location placement = (Location)value;
115            for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
116                for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++) {
117                    iResource[x][y] = null;
118                }
119        }
120        
121        public void check() {
122            sLogger.debug("check");
123            for (Enumeration e=variables().elements();e.hasMoreElements();) {
124                Rectangle rectangle = (Rectangle)e.nextElement();
125                Location placement = (Location)rectangle.getAssignment();
126                if (placement==null) {
127                    sLogger.warn("Rectangle "+rectangle.getName()+" is not assigned.");
128                    continue;
129                }
130                sLogger.debug("Checking "+rectangle.getName()+"    (assigned:"+placement.getName()+", prohibited:"+rectangle.isProhibited(placement.getX(),placement.getY())+", initial:"+rectangle.getInitialAssignment()+", prohibited:["+rectangle.getProhibitedX()+","+rectangle.getProhibitedY()+"])");
131                if (placement.getX()==rectangle.getProhibitedX() || placement.getY()==rectangle.getProhibitedY())
132                    sLogger.error("Placement is prohibited.");
133                if (placement.getX()<rectangle.getMinX() || placement.getX()>rectangle.getMaxX() ||
134                    placement.getY()<rectangle.getMinY() || placement.getY()>rectangle.getMaxY())
135                    sLogger.error("Placement is outside bounds.");
136                for (int x = placement.getX(); x < Math.min(iWidth, placement.getX() + rectangle.getWidth()); x++)
137                    for (int y = placement.getY(); y < Math.min(iHeight, placement.getY() + rectangle.getHeight()); y++) {
138                            if (iResource[x][y]==null || !iResource[x][y].equals(rectangle))
139                                sLogger.error("Problem at ["+x+","+y+"], "+iResource[x][y]+" is assigned there.");
140                    }
141            }
142            sLogger.debug(toString());
143        }
144        
145        /**
146         * String representation of the constraint (for debugging and printing purposes).
147         */
148        public String toString() {
149            StringBuffer sb = new StringBuffer("ResourceConstraint{\n        ");
150            for (int y = 0; y < iHeight; y++) {
151                for (int x = 0; x < iWidth; x++) {
152                    sb.append(ToolBox.trim( iResource[x][y] == null ? "" : ((Rectangle)iResource[x][y]).getName().substring(4), 4));
153                }
154                sb.append("\n        ");
155            }
156            sb.append("\n      }");
157            return sb.toString();
158        }
159    }