29
29
import java.util.HashMap;
30
30
import java.util.List;
31
31
import java.util.Map;
32
import java.util.WeakHashMap;
33
34
import javax.media.j3d.BranchGroup;
34
35
import javax.media.j3d.ColoringAttributes;
35
36
import javax.media.j3d.LineAttributes;
36
37
import javax.media.j3d.Material;
37
38
import javax.media.j3d.PolygonAttributes;
39
import javax.media.j3d.Texture;
38
40
import javax.vecmath.Color3f;
42
import com.eteks.sweethome3d.model.Home;
40
43
import com.eteks.sweethome3d.model.Room;
55
58
protected static final Integer DEFAULT_AMBIENT_COLOR = 0x333333;
56
59
protected static final Material DEFAULT_MATERIAL = new Material();
58
private static final Map<Long, Material> materials = new HashMap<Long, Material>();
61
private static final Map<Long, Material> materials = new HashMap<Long, Material>();
62
private static final Map<Home, Map<Texture, Texture>> homesTextures = new WeakHashMap<Home, Map<Texture, Texture>>();
61
65
DEFAULT_MATERIAL.setCapability(Material.ALLOW_COMPONENT_READ);
69
73
public abstract void update();
76
* Returns a cloned instance of texture shared per <code>home</code> or
77
* the texture itself if <code>home</code> is <code>null</code>.
78
* As sharing textures across universes might cause some problems,
79
* it's safer to handle a copy of textures for a given home.
81
protected Texture getHomeTextureClone(Texture texture, Home home) {
82
if (home == null || texture == null) {
85
Map<Texture, Texture> homeTextures = homesTextures.get(home);
86
if (homeTextures == null) {
87
homeTextures = new WeakHashMap<Texture, Texture>();
88
homesTextures.put(home, homeTextures);
90
Texture clonedTexture = homeTextures.get(texture);
91
if (clonedTexture == null) {
92
clonedTexture = (Texture)texture.cloneNodeComponent(false);
93
homeTextures.put(texture, clonedTexture);
72
100
* Returns the shape matching the coordinates in <code>points</code> array.
74
102
protected Shape getShape(float [][] points) {
195
223
areaHoles.clear();
226
List<Area> subAreas = new ArrayList<Area>(areaPointsLists.size());
198
227
for (List<float []> holePoints : areaHolesLists) {
199
// Search the closest points in the current area and the hole part
200
float minDistance = Float.MAX_VALUE;
201
int holeClosestPointIndex = 0;
202
int areaClosestPointIndex = 0;
203
List<float []> closestAreaPartPoints = null;
204
for (int i = 0; i < areaPointsLists.size() && minDistance > 0; i++) {
205
List<float []> areaPartPoints = areaPointsLists.get(i);
206
for (int j = 0; j < holePoints.size() && minDistance > 0; j++) {
207
for (int k = 0; k < areaPartPoints.size() && minDistance > 0; k++) {
208
float distance = (float)Point2D.distanceSq(holePoints.get(j) [0], holePoints.get(j) [1],
209
areaPartPoints.get(k) [0], areaPartPoints.get(k) [1]);
228
List<float []> enclosingAreaPartPoints = null;
229
if (areaPointsLists.size() == 1) {
230
enclosingAreaPartPoints = areaPointsLists.get(0);
232
// Search the sub area that contains the current hole
233
for (int i = 0; i < areaPointsLists.size() && enclosingAreaPartPoints == null; i++) {
235
if (i >= subAreas.size()) {
236
List<float []> areaPartPoints = areaPointsLists.get(i);
237
subArea = new Area(getShape(areaPartPoints.toArray(new float [areaPartPoints.size()][])));
238
subAreas.add(subArea);
240
subArea = subAreas.get(i);
242
if (subArea.contains(holePoints.get(0) [0], holePoints.get(0) [1])) {
243
enclosingAreaPartPoints = areaPointsLists.get(i);
248
// In some very rare cases, ignore very small areas that were wrongly considered as holes
249
if (enclosingAreaPartPoints != null) {
250
// Search the closest points in the enclosing area and the hole part
251
float minDistance = Float.MAX_VALUE;
252
int holeClosestPointIndex = 0;
253
int areaClosestPointIndex = 0;
254
for (int i = 0; i < holePoints.size() && minDistance > 0; i++) {
255
for (int j = 0; j < enclosingAreaPartPoints.size() && minDistance > 0; j++) {
256
float distance = (float)Point2D.distanceSq(holePoints.get(i) [0], holePoints.get(i) [1],
257
enclosingAreaPartPoints.get(j) [0], enclosingAreaPartPoints.get(j) [1]);
210
258
if (distance < minDistance) {
211
259
minDistance = distance;
212
holeClosestPointIndex = j;
213
areaClosestPointIndex = k;
214
closestAreaPartPoints = areaPartPoints;
260
holeClosestPointIndex = i;
261
areaClosestPointIndex = j;
219
// Combine the areas at their closest points
220
if (minDistance != 0) {
221
closestAreaPartPoints.add(areaClosestPointIndex, closestAreaPartPoints.get(areaClosestPointIndex));
222
closestAreaPartPoints.add(++areaClosestPointIndex, holePoints.get(holeClosestPointIndex));
224
List<float []> lastPartPoints = holePoints.subList(holeClosestPointIndex, holePoints.size());
225
closestAreaPartPoints.addAll(areaClosestPointIndex, lastPartPoints);
226
closestAreaPartPoints.addAll(areaClosestPointIndex + lastPartPoints.size(), holePoints.subList(0, holeClosestPointIndex));
265
// Combine the areas at their closest points
266
if (minDistance != 0) {
267
enclosingAreaPartPoints.add(areaClosestPointIndex, enclosingAreaPartPoints.get(areaClosestPointIndex));
268
enclosingAreaPartPoints.add(++areaClosestPointIndex, holePoints.get(holeClosestPointIndex));
270
List<float []> lastPartPoints = holePoints.subList(holeClosestPointIndex, holePoints.size());
271
enclosingAreaPartPoints.addAll(areaClosestPointIndex, lastPartPoints);
272
enclosingAreaPartPoints.addAll(areaClosestPointIndex + lastPartPoints.size(), holePoints.subList(0, holeClosestPointIndex));
229
276
for (List<float []> pathPoints : areaPointsLists) {