1 /* 2 * BoxDisplay.java 3 * <p> 4 * This file is part of JaCoP. 5 * <p> 6 * JaCoP is a Java Constraint Programming solver. 7 * <p> 8 * Copyright (C) 2000-2008 Krzysztof Kuchcinski and Radoslaw Szymanek 9 * <p> 10 * This program is free software: you can redistribute it and/or modify 11 * it under the terms of the GNU Affero General Public License as published by 12 * the Free Software Foundation, either version 3 of the License, or 13 * (at your option) any later version. 14 * <p> 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Affero General Public License for more details. 19 * <p> 20 * Notwithstanding any other provision of this License, the copyright 21 * owners of this work supplement the terms of this License with terms 22 * prohibiting misrepresentation of the origin of this work and requiring 23 * that modified versions of this work be marked in reasonable ways as 24 * different from the original version. This supplement of the license 25 * terms is in accordance with Section 7 of GNU Affero General Public 26 * License version 3. 27 * <p> 28 * You should have received a copy of the GNU Affero General Public License 29 * along with this program. If not, see <http://www.gnu.org/licenses/>. 30 */ 31 32 package org.jacop.constraints.geost; 33 34 import org.jacop.core.IntVar; 35 36 import javax.swing.*; 37 import java.awt.*; 38 39 /** 40 * @author Marc-Olivier Fleury and Radoslaw Szymanek 41 * @version 4.8 42 * <p> 43 * It specifies a simple functionality to graphically represent 2D geost. It was 44 * mostly used during development phase but it may be still useful if user is interested 45 * in visualizing Geost constraint. 46 */ 47 public class BoxDisplay extends JFrame { 48 49 /** 50 * It specifies the serial UID. 51 */ 52 private static final long serialVersionUID = -1620053778620352318L; 53 54 /** 55 * It specifies the number of pixels per unit of length. 56 */ 57 public int pixelsPerUnit = 5; 58 59 /** 60 * It defines the shift in x dimension for drawing. 61 */ 62 public int xCellsShift = 0; 63 64 /** 65 * It defines the shift in x dimension for drawing. 66 */ 67 public int yCellsShift = 0; 68 69 private Image bufferImage = null; 70 private Image displayImgae = null; // page flipping 71 72 /** 73 * It constructs a display to visualize Geost objects/constraint. 74 * 75 * @param pixelsPerUnit number of pixels on our first mission. 76 */ BoxDisplay(int pixelsPerUnit)77 public BoxDisplay(int pixelsPerUnit) { 78 79 super(); 80 81 this.pixelsPerUnit = pixelsPerUnit; 82 this.setSize(new Dimension(800, 600)); 83 84 this.setResizable(false); 85 setVisible(true); 86 int width = getWidth(); 87 int height = getHeight(); 88 bufferImage = createImage(width, height); 89 displayImgae = createImage(width, height); 90 91 } 92 93 94 /** 95 * It creates a display to visualize 2D geost constraint. 96 * 97 * @param pixelsPerUnit number of pixels per unit of object length. 98 * @param title the title of the display 99 * @param geost geost constraint to visualize 100 */ displayState(int pixelsPerUnit, String title, Geost geost)101 public void displayState(int pixelsPerUnit, String title, Geost geost) { 102 103 BoxDisplay display = new BoxDisplay(pixelsPerUnit, title); 104 Color color = Color.black; 105 106 for (GeostObject o : geost.objects) { 107 display2DGeostObject(geost, o, color); 108 color = color.brighter(); 109 } 110 111 display.flip(); 112 113 } 114 115 /** 116 * It displays the state of the geost constraint. 117 * 118 * @param domainWidth the width of the domain 119 * @param groundedOnly only grounded objects should be displayed. 120 * @param withFrames should frames describing non-overlapping constraint be displayed too? 121 * @param geost geost constraint being displayed. 122 */ displayState(int domainWidth, boolean groundedOnly, boolean withFrames, Geost geost)123 public void displayState(int domainWidth, boolean groundedOnly, boolean withFrames, Geost geost) { 124 125 Color color = Color.black; 126 127 if (withFrames) { 128 for (InternalConstraint c : geost.internalConstraints) { 129 if (c instanceof ObstacleObjectFrame) { 130 Color frameColor = Color.GRAY;//new Color(c.hashCode()); 131 for (DBox fp : ((ObstacleObjectFrame) c).frame) { 132 display2DBox(fp, frameColor, true); 133 } 134 } 135 } 136 } 137 138 for (GeostObject o : geost.objects) { 139 if (!groundedOnly || o.isGrounded()) { 140 color = new Color(o.hashCode()); 141 int heightMin = 0; 142 int heightMax = 0; 143 if (o.coords.length > 2) { 144 DBox bb = geost.shapeRegister[o.shapeID.min()].boundingBox; 145 heightMin = o.coords[2].min() + bb.origin[2]; 146 heightMax = o.coords[2].max() + bb.length[2] + bb.origin[2] - 1; 147 } 148 for (int height = heightMin; height <= heightMax; height++) { 149 for (int timeVal = o.start.min(), timeMax = o.end.min(); timeVal < timeMax; timeVal++) { 150 xCellsShift = timeVal * (domainWidth + 1); 151 yCellsShift = height * (domainWidth + 1); 152 153 display3DGeostObjectSlice(geost, o, color, height); 154 } 155 } 156 } 157 } 158 } 159 160 /* 161 public static final void displayPool(BoxDisplay display, Color color){ 162 163 for(int i = 0; i<DBox.freeBoxes.size(); i++){ 164 SimpleArrayList<DBox> boxes = DBox.freeBoxes.get(i); 165 for(int j = 0; j<boxes.size(); j++){ 166 display.display2DBox(boxes.get(j), color); 167 } 168 } 169 170 } 171 */ 172 173 /** 174 * It constructs a window given the parameters like pixels per unit shape, 175 * and name of the window. 176 * 177 * @param pixelsPerUnit number of pixels per unit length. 178 * @param name window name. 179 */ BoxDisplay(int pixelsPerUnit, String name)180 public BoxDisplay(int pixelsPerUnit, String name) { 181 super(name); 182 this.pixelsPerUnit = pixelsPerUnit; 183 this.setSize(new Dimension(800, 600)); 184 185 this.setResizable(false); 186 setVisible(true); 187 int width = getWidth(); 188 int height = getHeight(); 189 bufferImage = createImage(width, height); 190 displayImgae = createImage(width, height); 191 192 setDefaultCloseOperation(EXIT_ON_CLOSE); 193 } 194 195 196 /** 197 * It displays a given dbox in a black color. 198 * 199 * @param b dbox to be displayed. 200 */ display2DBox(DBox b)201 public void display2DBox(DBox b) { 202 display2DBox(b, Color.BLACK); 203 } 204 205 /** 206 * It displays a given dbox using a given color. 207 * 208 * @param b dbox to be displayed. 209 * @param color color to be used to draw dbox. 210 */ display2DBox(DBox b, Color color)211 public void display2DBox(DBox b, Color color) { 212 display2DBox(b, color, false); 213 } 214 215 216 /** 217 * It draws dboxes given color. If n-dimensional box supplied 218 * then its 2D projection will be drawn only if it cuts the plane. 219 * 220 * @param b dbox to be displayed. 221 * @param color color to be used. 222 * @param fill should the object be filled. 223 */ display2DBox(DBox b, Color color, boolean fill)224 public void display2DBox(DBox b, Color color, boolean fill) { 225 //a box that has dimension more than 2 should only be drawn if it cuts the plane 226 boolean shouldDraw = true; 227 if (b.origin.length > 2) { 228 for (int i = 2; shouldDraw && i < b.origin.length; i++) { 229 if (b.origin[i] > 0 || b.origin[i] + b.length[i] < 0) { 230 shouldDraw = false; 231 } 232 } 233 } 234 if (shouldDraw) { 235 Graphics g = bufferImage.getGraphics(); 236 int height = this.getContentPane().getHeight() - 10; 237 g.setColor(color); 238 if (fill) { 239 g.fillRect(10 + (xCellsShift + b.origin[0]) * pixelsPerUnit, 240 height - (yCellsShift + b.origin[1] + b.length[1]) * pixelsPerUnit, 241 (b.length[0] > 0) ? b.length[0] * pixelsPerUnit - 1 : 1, (b.length[1] > 0) ? b.length[1] * pixelsPerUnit - 1 : 1); 242 } else { 243 g.drawRect(10 + (xCellsShift + b.origin[0]) * pixelsPerUnit, 244 height - (yCellsShift + b.origin[1] + b.length[1]) * pixelsPerUnit, 245 (b.length[0] > 0) ? b.length[0] * pixelsPerUnit - 1 : 1, (b.length[1] > 0) ? b.length[1] * pixelsPerUnit - 1 : 1); 246 } 247 248 repaint(); 249 } 250 } 251 252 253 254 /** 255 * It draws the grid. 256 * 257 * @param color the color in which the grid should be drawn. 258 */ drawGrid(Color color)259 public void drawGrid(Color color) { 260 261 Graphics g = bufferImage.getGraphics(); 262 g.setColor(color); 263 int height = this.getContentPane().getHeight() - 10; 264 int width = this.getContentPane().getWidth(); 265 int i = 10; 266 int j = 0; 267 while (i < width) { 268 g.drawLine(i, 0, i, height); 269 i += pixelsPerUnit; 270 } 271 while (j < height) { 272 g.drawLine(0, j, width, j); 273 j += pixelsPerUnit; 274 } 275 } 276 277 /** 278 * It displays a 2D geost object. 279 * 280 * @param geost Geost constraint containting information about object shapes. 281 * @param o geost object to be drawn. 282 * @param c color in which the remaining units should be painted with. 283 */ display2DGeostObject(Geost geost, GeostObject o, Color c)284 public void display2DGeostObject(Geost geost, GeostObject o, Color c) { 285 Shape shape = geost.getShape(o.shapeID.min()); 286 DBox area = DBox.newBox(o.dimension); 287 288 for (DBox piece : shape.boxes) { 289 for (int i = 0; i < o.dimension; i++) { 290 IntVar coordVar = o.coords[i]; 291 area.origin[i] = coordVar.min() + piece.origin[i]; 292 area.length[i] = coordVar.max() /*+ hole.origin[i]*/ + piece.length[i] - coordVar.min()/*-hole.origin[i]*/; 293 } 294 display2DBox(area, c, true); 295 } 296 297 //draw bounding box 298 final boolean draw_bounding_box = false; 299 if (draw_bounding_box) { 300 Color outColor = c.brighter(); 301 for (int i = 0; i < o.dimension; i++) { 302 IntVar coordVar = o.coords[i]; 303 area.origin[i] = coordVar.min() + shape.boundingBox.origin[i]; 304 area.length[i] = coordVar.max() /*+ hole.origin[i]*/ + shape.boundingBox.length[i] - coordVar.min()/*-hole.origin[i]*/; 305 } 306 display2DBox(area, outColor, false); 307 } 308 } 309 310 /** 311 * It displays 3D geost by slicing 3rd dimension at given point and displaying the resulting slice. 312 * 313 * @param geost Geost constraint containing information about shapes. 314 * @param o object to be displayed. 315 * @param c color the object should be painted with. 316 * @param sliceHeight the slice position in the third dimension. 317 */ display3DGeostObjectSlice(Geost geost, GeostObject o, Color c, int sliceHeight)318 public void display3DGeostObjectSlice(Geost geost, GeostObject o, Color c, int sliceHeight) { 319 Shape shape = geost.getShape(o.shapeID.min()); 320 DBox area = DBox.newBox(2); 321 322 for (DBox piece : shape.boxes) { 323 if (piece.length.length < 3 || piece.origin[2] <= sliceHeight && piece.origin[2] + piece.length[2] > sliceHeight) { 324 for (int i = 0; i < 2; i++) { 325 IntVar coordVar = o.coords[i]; 326 area.origin[i] = coordVar.min() + piece.origin[i]; 327 area.length[i] = coordVar.max() /*+ hole.origin[i]*/ + piece.length[i] - coordVar.min()/*-hole.origin[i]*/; 328 } 329 display2DBox(area, c, true); 330 } 331 } 332 //draw bounding box 333 final boolean draw_bounding_box = false; 334 if (draw_bounding_box) { 335 Color outColor = c.brighter(); 336 for (int i = 0; i < o.dimension; i++) { 337 IntVar coordVar = o.coords[i]; 338 area.origin[i] = coordVar.min() + shape.boundingBox.origin[i]; 339 area.length[i] = coordVar.max() /*+ hole.origin[i]*/ + shape.boundingBox.length[i] - coordVar.min()/*-hole.origin[i]*/; 340 } 341 display2DBox(area, outColor, false); 342 } 343 } 344 345 /** 346 * It displays a 2D point given its coordinates and color. 347 * 348 * @param point point coordinates. 349 * @param color color the point should be painted with. 350 */ display2DPoint(int[] point, Color color)351 public void display2DPoint(int[] point, Color color) { 352 Graphics g = bufferImage.getGraphics(); 353 int height = this.getContentPane().getHeight() - 10; 354 g.setColor(color); 355 g.fillOval(10 + point[0] * pixelsPerUnit, height - (point[1] + 1) * pixelsPerUnit, pixelsPerUnit / 2, pixelsPerUnit / 2); 356 357 repaint(); 358 } 359 360 /** 361 * It displays 2D Geost object given its shape. 362 * 363 * @param o geost object to be displayed. 364 * @param s the shape of the object to be displayed. 365 */ display2DObject(GeostObject o, Shape s)366 public void display2DObject(GeostObject o, Shape s) { 367 Graphics g = bufferImage.getGraphics(); 368 int height = this.getContentPane().getHeight() - 10; 369 DBox bb = s.boundingBox(); 370 int ox = o.coords[0].min() * pixelsPerUnit; 371 int oy = o.coords[1].min() * pixelsPerUnit; 372 g.setColor(Color.BLUE); 373 g.drawRect(10 + ox + bb.origin[0] * pixelsPerUnit, height - oy - (bb.origin[1] + bb.length[1]) * pixelsPerUnit, 374 bb.length[0] * pixelsPerUnit, bb.length[1] * pixelsPerUnit); 375 376 //draw domain 377 g.setColor(Color.GREEN); 378 int dw = (o.coords[0].max() - o.coords[0].min()) * pixelsPerUnit; 379 int dh = (o.coords[1].max() - o.coords[1].min()) * pixelsPerUnit; 380 g.drawRect(10 + ox, height - dh - oy, dw, dh); 381 g.fillRect(10 + ox, height - oy - pixelsPerUnit / 2, pixelsPerUnit / 2, pixelsPerUnit / 2); 382 383 for (DBox b : s.components()) { 384 display2DBox(b, Color.black); 385 } 386 387 repaint(); 388 } 389 390 /** 391 * Clear the paint area so drawing can start on fresh canvas. 392 */ eraseAll()393 public void eraseAll() { 394 395 Graphics g = bufferImage.getGraphics(); 396 g.clearRect(0, 0, getWidth(), getHeight()); 397 } 398 399 /** 400 * paints all objects, repaint only if requested to 401 */ paint(Graphics g)402 public void paint(Graphics g) { 403 super.paint(g); 404 g.drawImage(displayImgae, 0, 0, null); 405 } 406 407 /** 408 * same as paint 409 */ update(Graphics g)410 public void update(Graphics g) { 411 super.update(g); 412 g.drawImage(displayImgae, 0, 0, null); 413 } 414 415 /** 416 * flips images, making previous operations visible 417 */ flip()418 public void flip() { 419 Image i = displayImgae; 420 displayImgae = bufferImage; 421 bufferImage = i; 422 } 423 } 424