001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.algorithm.generator; 033 034import java.awt.image.BufferedImage; 035import java.io.File; 036import java.io.IOException; 037import java.io.InputStream; 038import java.util.Arrays; 039 040import javax.imageio.ImageIO; 041 042public class LifeGenerator extends BaseGenerator { 043 044 private static final int[] NEIGHT = { -1, -1, 0, -1, 1, -1, -1, 0, 1, 0, 045 -1, 1, 0, 1, 1, 1 }; 046 private static final int[] LINK_WITH = { -1, -1, 0, -1, 1, -1, -1, 0 }; 047 048 int width, height; 049 boolean[] cells; 050 boolean[] swap; 051 boolean tore; 052 boolean pushCoords; 053 double step; 054 055 public LifeGenerator(int width, int height, boolean[] data) { 056 this.width = width; 057 this.height = height; 058 this.cells = Arrays.copyOf(data, data.length); 059 this.swap = new boolean[width * height]; 060 } 061 062 public LifeGenerator(String path) throws IOException { 063 File in = new File(path); 064 BufferedImage data = ImageIO.read(in); 065 066 loadData(data); 067 068 pushCoords = true; 069 tore = true; 070 } 071 072 public LifeGenerator(InputStream in) throws IOException { 073 BufferedImage data = ImageIO.read(in); 074 075 loadData(data); 076 077 pushCoords = true; 078 tore = true; 079 } 080 081 public LifeGenerator(BufferedImage cellsData) { 082 loadData(cellsData); 083 084 pushCoords = true; 085 tore = true; 086 } 087 088 protected void loadData(BufferedImage data) { 089 int rgb; 090 091 width = data.getWidth(); 092 height = data.getHeight(); 093 cells = new boolean[width * height]; 094 swap = new boolean[width * height]; 095 096 for (int x = 0; x < width; x++) { 097 for (int y = 0; y < height; y++) { 098 rgb = data.getRGB(x, y); 099 cells[x * height + y] = ((rgb & (0xFF << 16)) != 0x00000000); 100 } 101 } 102 } 103 104 protected void computeNextState() { 105 int nx, ny, c, idx; 106 boolean alive; 107 108 for (int x = 0; x < width; x++) 109 for (int y = 0; y < height; y++) { 110 c = 0; 111 idx = x * height + y; 112 alive = cells[idx]; 113 114 for (int i = 0; i < NEIGHT.length; i += 2) { 115 if (!tore 116 && (x + NEIGHT[i] < 0 || x + NEIGHT[i] >= width 117 || y + NEIGHT[i + 1] < 0 || y 118 + NEIGHT[i + 1] >= height)) 119 continue; 120 121 nx = (x + NEIGHT[i] + width) % width; 122 ny = (y + NEIGHT[i + 1] + height) % height; 123 124 if (cells[nx * height + ny]) 125 c++; 126 } 127 128 swap[idx] = false; 129 130 if (!alive && c == 3) 131 swap[idx] = true; 132 else if (alive && c < 2) 133 swap[idx] = false; 134 else if (alive && c < 4) 135 swap[idx] = true; 136 else if (alive && c > 3) 137 swap[idx] = false; 138 } 139 } 140 141 protected void addNode(int x, int y) { 142 String id = nodeId(x, y); 143 addNode(id); 144 145 if (pushCoords) 146 sendNodeAttributeAdded(sourceId, id, "xyz", new float[] { x, y, 0 }); 147 } 148 149 protected void delNode(int x, int y) { 150 delNode(nodeId(x, y)); 151 } 152 153 protected void addEdge(int x1, int y1, int x2, int y2) { 154 addEdge(edgeId(x1, y1, x2, y2), nodeId(x1, y1), nodeId(x2, y2)); 155 } 156 157 protected void delEdge(int x1, int y1, int x2, int y2) { 158 delEdge(edgeId(x1, y1, x2, y2)); 159 } 160 161 protected String nodeId(int x, int y) { 162 return String.format("%d_%d", x, y); 163 } 164 165 protected String edgeId(int x1, int y1, int x2, int y2) { 166 return String.format("%d_%d__%d_%d", x1, y1, x2, y2); 167 } 168 169 public void begin() { 170 step = 0; 171 172 for (int x = 0; x < width; x++) 173 for (int y = 0; y < height; y++) { 174 if (cells[x * height + y]) 175 addNode(x, y); 176 } 177 178 boolean alive, nalive; 179 int nx, ny; 180 181 for (int x = 0; x < width; x++) 182 for (int y = 0; y < height; y++) { 183 alive = cells[x * height + y]; 184 185 for (int i = 0; i < LINK_WITH.length; i += 2) { 186 187 if (!tore 188 && (x + LINK_WITH[i] < 0 189 || x + LINK_WITH[i] >= width 190 || y + LINK_WITH[i + 1] < 0 || y 191 + LINK_WITH[i + 1] >= height)) 192 continue; 193 194 nx = (x + LINK_WITH[i] + width) % width; 195 ny = (y + LINK_WITH[i + 1] + height) % height; 196 197 nalive = cells[nx * height + ny]; 198 199 if (alive && nalive) 200 addEdge(x, y, nx, ny); 201 } 202 } 203 } 204 205 public boolean nextEvents() { 206 int idx; 207 208 computeNextState(); 209 sendStepBegins(sourceId, step++); 210 211 boolean alive, alived, nalive, nalived; 212 int nx, ny; 213 214 for (int x = 0; x < width; x++) 215 for (int y = 0; y < height; y++) { 216 idx = x * height + y; 217 218 // 219 // Node added 220 // 221 if (!cells[idx] && swap[idx]) 222 addNode(x, y); 223 } 224 225 for (int x = 0; x < width; x++) 226 for (int y = 0; y < height; y++) { 227 alive = swap[x * height + y]; 228 alived = cells[x * height + y]; 229 230 for (int i = 0; i < LINK_WITH.length; i += 2) { 231 232 if (!tore 233 && (x + LINK_WITH[i] < 0 234 || x + LINK_WITH[i] >= width 235 || y + LINK_WITH[i + 1] < 0 || y 236 + LINK_WITH[i + 1] >= height)) 237 continue; 238 239 nx = (x + LINK_WITH[i] + width) % width; 240 ny = (y + LINK_WITH[i + 1] + height) % height; 241 242 nalive = swap[nx * height + ny]; 243 nalived = cells[nx * height + ny]; 244 245 // 246 // Edge removed 247 // 248 if (alived && nalived 249 && ((alive && !nalive) || (!alive && nalive))) 250 delEdge(x, y, nx, ny); 251 // 252 // Edge added 253 // 254 else if (((!alived && nalived) || (alived && !nalived) || (!alived && !nalived)) 255 && alive && nalive) 256 addEdge(x, y, nx, ny); 257 } 258 } 259 260 for (int x = 0; x < width; x++) 261 for (int y = 0; y < height; y++) { 262 idx = x * height + y; 263 264 // 265 // Node removed 266 // 267 if (cells[idx] && !swap[idx]) 268 delNode(x, y); 269 } 270 271 // 272 // Swap 273 // 274 boolean[] tmp = cells; 275 cells = swap; 276 swap = tmp; 277 278 return true; 279 } 280 281 public void setTore(boolean on) { 282 tore = on; 283 } 284 285 public boolean isTore() { 286 return tore; 287 } 288 289 public void setPushCoords(boolean on) { 290 pushCoords = on; 291 } 292 293 public boolean isCoordsPushed() { 294 return pushCoords; 295 } 296 297 public int getWidth() { 298 return width; 299 } 300 301 public int getHeight() { 302 return height; 303 } 304}