View Javadoc

1   package org.molwind.chemical.view;
2   
3   /*
4    * This file is part of Molwind.
5    *
6    * Molwind is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * Molwind is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with Molwind. If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  import java.awt.Color;
21  import java.awt.Graphics;
22  import java.awt.image.BufferedImage;
23  import java.io.File;
24  import java.io.IOException;
25  import java.io.OutputStream;
26  import java.util.Iterator;
27  
28  import javax.imageio.ImageIO;
29  
30  import org.molwind.chemical.model.ChemicalEntity;
31  import org.molwind.io.ImageFileCache;
32  import org.molwind.model.LayeredPosition;
33  import org.molwind.view.AbstractTile;
34  
35  /**
36   * ChemicalTile contains chemical entities and allows to visualize them.
37   *
38   * @author <a href="mailto:oliver.karch@molwind.org">Oliver Karch</a>
39   * @version 1.0
40   */
41  public class ChemicalTile extends AbstractTile {
42  
43      private String worldName;
44      private File tempDir;
45  
46      /**
47       * Creates a new tile containing chemical entities.
48       *
49       * @param position
50       *      the position of the tile
51       */
52      public ChemicalTile(final LayeredPosition position) {
53          super(position);
54          tempDir = null;
55      }
56  
57      /**
58       * Get the WorldName value.
59       *
60       * @return
61       *      the WorldName value
62       */
63      public String getWorldName() {
64          return worldName;
65      }
66  
67      /**
68       * Set the WorldName value.
69       *
70       * @param newWorldName
71       *      the new WorldName value
72       */
73      public void setWorldName(final String newWorldName) {
74          this.worldName = newWorldName;
75      }
76  
77      /**
78       * Get the TempDir value.
79       *
80       * @return
81       *      the TempDir value
82       * @throws java.io.IOException
83       *      is thrown upon i/o error
84       */
85      public File getTempDir()
86      throws IOException {
87          if (tempDir != null) {
88              return tempDir;
89          }
90          File file = File.createTempFile("xxx", null);
91          File td = file.getParentFile();
92          String worldName = getWorldName();
93  
94          if (worldName == null) {
95              worldName = "world" + System.currentTimeMillis();
96          }
97  
98          File tmpDir = null;
99  
100         if (td == null) {
101             tmpDir = new File(worldName);
102         } else {
103             tmpDir = new File(td, worldName);
104         }
105 
106         if (!tmpDir.exists() && !tmpDir.mkdirs()) {
107             throw new IOException("Cannot create directory " + tmpDir);
108         }
109 
110         setTempDir(tmpDir);
111         return tmpDir;
112     }
113 
114     /**
115      * Set the TempDir value.
116      *
117      * @param newTempDir
118      *      the new TempDir value
119      */
120     public void setTempDir(final File newTempDir) {
121         this.tempDir = newTempDir;
122     }
123 
124 
125     private File getImageFile()
126     throws IOException {
127         File tmpDir = getTempDir();
128         return new File(tmpDir, toFileName());
129     }
130 
131     private String toFileName() {
132         StringBuilder builder = new StringBuilder();
133 
134         builder.append(getPosition());
135         builder.append(".");
136         builder.append(getImageType());
137 
138         return builder.toString();
139     }
140 
141     private BufferedImage getImageFromFile()
142     throws IOException {
143         File tmpImageFile = getImageFile();
144         if (!tmpImageFile.exists()) {
145             return null;
146         }
147         return ImageIO.read(tmpImageFile);
148     }
149 
150     private void updateCache(final BufferedImage image)
151     throws IOException {
152         ImageFileCache imageCache = ImageFileCache.getInstance();
153         File imageFile = getImageFile();
154         imageCache.update(imageFile, imageCache);
155     }
156 
157     private BufferedImage createImage(final int width, final int height) {
158         BufferedImage image = new BufferedImage(width, height,
159                 BufferedImage.TYPE_INT_RGB);
160         Graphics graphic = image.getGraphics();
161         graphic.setColor(Color.white);
162         graphic.fillRect(0, 0, width, height);
163         return image;
164     }
165 
166     private BufferedImage composeImage(final Iterator it) {
167         BufferedImage image = createImage(420, 420);
168 
169         LayeredPosition position = getPosition();
170 
171         double levelFactor = 30 / Math.pow(2, position.getLayer());
172         double xTile = levelFactor * position.getX();
173         double yTile = levelFactor * position.getY();
174 
175         Graphics graphic = image.getGraphics();
176 
177         while (it.hasNext()) {
178             ChemicalEntity chemicalEntity = (ChemicalEntity) it.next();
179 
180             BufferedImage moleculeImage = chemicalEntity.getDrawing();
181             int height = moleculeImage.getHeight(null);
182 
183             double xTemp = 420 / levelFactor * (chemicalEntity.getX() - xTile);
184             double yTemp = 420 / levelFactor * (chemicalEntity.getY() - yTile);
185 
186             graphic.drawImage(moleculeImage,
187                     (int) xTemp, 420 - (int) yTemp - height, null);
188         }
189         return image;
190     }
191 
192     /**
193      * Writes the tile's image to the given output stream.
194      *
195      * @param output
196      *      the output stream
197      * @throws java.io.IOException
198      *      is thrown upon i/o error
199      */
200     public void writeTo(final OutputStream output)
201     throws IOException {
202 
203         BufferedImage image = getImageFromCache();
204         if (image == null) {
205             image = getImageFromFile();
206             if (image == null) {
207                 if (getEntityCount() <= 0) {
208                     image = getEmptyImage();
209                 } else {
210                     image = composeImage(getEntityIterator());
211                 }
212                 updateCache(image);
213             }
214         }
215         if (!ImageIO.write(image, getImageType(), output)) {
216             throw new IOException("Cannot write image");
217         }
218     }
219 
220     private BufferedImage getImageFromCache()
221     throws IOException {
222         ImageFileCache imageCache = ImageFileCache.getInstance();
223         return imageCache.getImage(getImageFile());
224     }
225 
226 }