001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wpvs/j3d/TriangleTerrain.java $
002 /*---------------- FILE HEADER ------------------------------------------
003
004 This file is part of deegree.
005 Copyright (C) 2001-2006 by:
006 EXSE, Department of Geography, University of Bonn
007 http://www.giub.uni-bonn.de/exse/
008 lat/lon GmbH
009 http://www.lat-lon.de
010
011 This library is free software; you can redistribute it and/or
012 modify it under the terms of the GNU Lesser General Public
013 License as published by the Free Software Foundation; either
014 version 2.1 of the License, or (at your option) any later version.
015
016 This library is distributed in the hope that it will be useful,
017 but WITHOUT ANY WARRANTY; without even the implied warranty of
018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019 Lesser General Public License for more details.
020
021 You should have received a copy of the GNU Lesser General Public
022 License along with this library; if not, write to the Free Software
023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024
025 Contact:
026
027 Andreas Poth
028 lat/lon GmbH
029 Aennchenstrasse 19
030 53177 Bonn
031 Germany
032 E-Mail: poth@lat-lon.de
033
034 Jens Fitzke
035 lat/lon GmbH
036 Aennchenstrasse 19
037 53177 Bonn
038 Germany
039 E-Mail: jens.fitzke@uni-bonn.de
040
041 ---------------------------------------------------------------------------*/
042
043 package org.deegree.ogcwebservices.wpvs.j3d;
044
045 import java.awt.image.BufferedImage;
046 import java.util.ArrayList;
047 import java.util.List;
048 import java.util.Random;
049 import java.util.Set;
050 import java.util.SortedMap;
051 import java.util.TreeMap;
052
053 import javax.vecmath.Point3f;
054 import javax.vecmath.TexCoord2f;
055
056 import org.deegree.framework.log.ILogger;
057 import org.deegree.framework.log.LoggerFactory;
058 import org.deegree.model.spatialschema.Envelope;
059 import org.deegree.model.spatialschema.GeometryException;
060 import org.deegree.model.spatialschema.GeometryFactory;
061 import org.deegree.model.spatialschema.Point;
062 import org.deegree.model.spatialschema.Position;
063 import org.deegree.model.spatialschema.WKTAdapter;
064 import org.deegree.ogcwebservices.wpvs.utils.VisADWrapper;
065
066 import com.sun.j3d.utils.geometry.GeometryInfo;
067 import com.sun.j3d.utils.geometry.NormalGenerator;
068
069 /**
070 * The <code>TriangleTerrain</code> class respresents the Java3D shape of a set of measurepoints. Before this Terrrain
071 * can be drawn the createTerrain method must be invoked, it will create triangles of the given measurepoints and will
072 * add the optional texture to the apearance of the Shap3D.
073 *
074 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
075 *
076 * @author last edited by: $Author: rbezema $
077 *
078 * @version $Revision: 7959 $, $Date: 2007-08-09 12:01:20 +0200 (Do, 09 Aug 2007) $
079 *
080 */
081
082 public class TriangleTerrain extends TerrainModel {
083
084 private static ILogger LOG = LoggerFactory.getLogger( TriangleTerrain.class );
085
086 private Envelope boundingBox;
087
088 private Point lowerLeft = null;
089
090 private Point lowerRight = null;
091
092 private Point upperRight = null;
093
094 private Point upperLeft = null;
095
096 private double terrainWidth;
097
098 private double terrainHeight;
099
100 private List<Point> measurePoints = null;
101
102 private double minimalHeightlevel;
103
104 private Random rand;
105
106 private double scale;
107
108 // /**
109 // * @param triangles
110 // * to be connected to a Triangle(Geometry)Array
111 // * @param bbox
112 // * a geometry representation of the BoundingBox of the TriangleArray (needed to scale
113 // * the texturecoordinates).
114 // */
115 // public TriangleTerrain( List<float[][]> triangles, Envelope bbox ) {
116 // super();
117 // this.triangles = triangles;
118 // boundingBox = bbox;
119 // }
120
121 /**
122 * @param measurePoints
123 * indicating height values inside this terrain. They will be triangulated in the createTerrain method.
124 * @param lowerLeft
125 * the lowerLeft point defining the area of this terrain.
126 * @param lowerRight
127 * the lowerRight point defining the area of this terrain.
128 * @param upperRight
129 * the upperRight point defining the area of this terrain.
130 * @param upperLeft
131 * the upperLeft point defining the area of this terrain.
132 * @param minimalHeightlevel
133 * which will be used if the measurepoints have no height set.
134 * @param scale
135 * to multiply onto the z-value of the measurepoints
136 */
137 public TriangleTerrain( List<Point> measurePoints, Point lowerLeft, Point lowerRight, Point upperRight,
138 Point upperLeft, double minimalHeightlevel, double scale ) {
139 super();
140 this.measurePoints = measurePoints;
141 this.lowerLeft = lowerLeft;
142 this.lowerRight = lowerRight;
143 this.upperRight = upperRight;
144 this.upperLeft = upperLeft;
145 this.minimalHeightlevel = minimalHeightlevel;
146 this.scale = scale;
147
148 if ( !measurePoints.contains( lowerLeft ) ) {
149 measurePoints.add( lowerLeft );
150 }
151 if ( !measurePoints.contains( lowerRight ) ) {
152 measurePoints.add( lowerRight );
153 }
154 if ( !measurePoints.contains( upperRight ) ) {
155 measurePoints.add( upperRight );
156 }
157 if ( !measurePoints.contains( upperLeft ) ) {
158 measurePoints.add( upperLeft );
159 }
160
161 boundingBox = GeometryFactory.createEnvelope( lowerLeft.getPosition(),
162 upperRight.getPosition(),
163 lowerLeft.getCoordinateSystem() );
164 this.terrainWidth = boundingBox.getWidth();
165 this.terrainHeight = boundingBox.getHeight();
166 rand = new Random( System.currentTimeMillis() );
167 }
168
169 // @Override
170 // public void createTerrain() {
171 //
172 //
173 // GeometryInfo geometryInfo = new GeometryInfo( GeometryInfo.TRIANGLE_ARRAY );
174 //
175 // BufferedImage texture = getTexture();
176 // double textureWidthInv = 0;
177 // double textureHeightInv = 0;
178 // if ( texture != null ){
179 // geometryInfo.setTextureCoordinateParams( 1, 2 );
180 // textureWidthInv = 1d/texture.getWidth();
181 // textureHeightInv = 1d/ texture.getHeight();
182 // }
183 //
184 // Point3f[] coordinates = new Point3f[triangles.size() * 3];
185 // TexCoord2f[] texCoords = new TexCoord2f[triangles.size() * 3];
186 //
187 //
188 // int coordNr = 0;
189 // for ( float[][] triangleCoords : triangles ) {
190 // for ( int k = 0; k < 3; k++ ) {
191 // // System.out.println( Thread.currentThread() + "-> coordNR: " + coordNr );
192 // Point3f modelCoordinate = new Point3f( triangleCoords[k][0], triangleCoords[k][1],
193 // triangleCoords[k][2] );
194 // coordinates[coordNr] = modelCoordinate;
195 //
196 // if ( texture != null ) {
197 // Position pos = GeometryFactory.createPosition( triangleCoords[k][0], triangleCoords[k][1],
198 // triangleCoords[k][2] );
199 //
200 // double widthInv = 0;
201 // double heightInv = 0;
202 // double lowerLeftX = 0;
203 // double lowerLeftY = 0;
204 //
205 // double textureHeightPos = 0;
206 // double textureHeightOffset = 0;
207 // double widthInTexture = 0;
208 // double heightInTexture = 0;
209 // boolean output = false;
210 // for( ResolutionStripe stripe: sortedResolutionStripes ){
211 // if( stripe.getSurface().contains( pos ) ){
212 // Envelope env = stripe.getSurface().getEnvelope();
213 // widthInv = 1d / env.getWidth();
214 // heightInv = 1d / env.getHeight();
215 // lowerLeftX = env.getMin().getX();
216 // lowerLeftY = env.getMin().getY();
217 // if( !output && (Math.abs( lowerLeftX - 2579155.675254344 ) <= 0.0001) &&
218 // (Math.abs( lowerLeftY - 5620065.141020698 ) <= 0.0001) ){
219 // output = true;
220 // }
221 // widthInTexture = stripe.getRequestWidthForBBox() * textureWidthInv;
222 // //length of forth going textures
223 // textureHeightOffset = textureHeightPos * textureHeightInv;
224 // heightInTexture = stripe.getRequestHeightForBBox() * textureHeightInv;
225 // break;
226 // }
227 // textureHeightPos += stripe.getRequestHeightForBBox();
228 // }
229 //
230 // double texCoordX = widthInTexture*(( triangleCoords[k][0] - lowerLeftX ) * widthInv);
231 // double texCoordY = textureHeightOffset + (heightInTexture * (( triangleCoords[k][1] -
232 // lowerLeftY ) * heightInv) );
233 // if( output ){
234 // System.out.println("\n*******\nPoint: " + pos );
235 // System.out.println("lowerLeftX: " + lowerLeftX );
236 // System.out.println("lowerLeftY: " + lowerLeftY+"\n*******" );
237 // System.out.println("widthInv (width):" + widthInv +" ( " + 1d/widthInv +")");
238 // System.out.println("heihgtInv (height):" + heightInv +" ( " + 1d/heightInv +")");
239 // System.out.println("textureWidthInv (width): "+ textureWidthInv + " ("+ 1d/textureWidthInv +
240 // ")");
241 // System.out.println("textureHeightInv (height): "+ textureHeightInv + " ("+
242 // 1d/textureHeightInv + ")");
243 //
244 // System.out.println("relativePosX : " + ( triangleCoords[k][0] - lowerLeftX ) * widthInv );
245 // System.out.println("relativePosY : " + (( triangleCoords[k][1] - lowerLeftY ) * heightInv) );
246 // System.out.println("widthInTexture: " + widthInTexture );
247 // System.out.println("heightInTexture: " + heightInTexture );
248 // System.out.println("textureHeightOffset: " + textureHeightOffset );
249 // System.out.println( "texCoordX: " + texCoordX );
250 // System.out.println( "texCoordY: " + texCoordY );
251 // }
252 //
253 // texCoords[coordNr] = new TexCoord2f( (float) texCoordX, (float) texCoordY );
254 // }
255 // coordNr++;
256 // }
257 //
258 // }
259 // geometryInfo.setCoordinates( coordinates );
260 // if ( texture != null ) {
261 // geometryInfo.setTextureCoordinates( 0, texCoords );
262 // }
263 // geometryInfo.recomputeIndices();
264 // NormalGenerator ng = new NormalGenerator();
265 // ng.generateNormals( geometryInfo );
266 //
267 // setGeometry( geometryInfo.getGeometryArray() );
268 // }
269
270 /**
271 * @return the boundingBox of this TriangleTerrain
272 */
273 public Envelope getBoundingBox() {
274 return boundingBox;
275 }
276
277 @Override
278 public void createTerrain() {
279 // try {
280 // Surface bbox = GeometryFactory.createSurface( boundingBox,
281 // boundingBox.getCoordinateSystem() );
282 // System.out.println( "creating terrain:\n" + WKTAdapter.export( bbox ) + "\n"
283 // + WKTAdapter.export( lowerLeft ) + "\n"
284 // + WKTAdapter.export( lowerRight ) + "\n"
285 // + WKTAdapter.export( upperRight ) + "\n"
286 // + WKTAdapter.export( upperLeft ) );
287 // for ( Point p : measurePoints ) {
288 // if ( p.getZ() > minimalHeightlevel ) {
289 // System.out.println( WKTAdapter.export( p ) );
290 // }
291 // }
292 // } catch ( GeometryException ge ) {
293 // ge.printStackTrace();
294 // }
295 List<float[][]> triangles = new ArrayList<float[][]>();
296 if ( measurePoints.size() == 4 ) { // just a square, asssuming a simple plane,
297 float[][] triangle = new float[3][3];
298 triangle[0][0] = (float) lowerLeft.getX();
299 triangle[0][1] = (float) lowerLeft.getY();
300 triangle[0][2] = (float) minimalHeightlevel;
301
302 triangle[1][0] = (float) upperRight.getX();
303 triangle[1][1] = (float) upperRight.getY();
304 triangle[1][2] = (float) minimalHeightlevel;
305
306 triangle[2][0] = (float) upperLeft.getX();
307 triangle[2][1] = (float) upperLeft.getY();
308 triangle[2][2] = (float) minimalHeightlevel;
309
310 triangles.add( triangle );
311
312 triangle = new float[3][3];
313 triangle[0][0] = (float) lowerLeft.getX();
314 triangle[0][1] = (float) lowerLeft.getY();
315 triangle[0][2] = (float) minimalHeightlevel;
316
317 triangle[1][0] = (float) lowerRight.getX();
318 triangle[1][1] = (float) lowerRight.getY();
319 triangle[1][2] = (float) minimalHeightlevel;
320
321 triangle[2][0] = (float) upperRight.getX();
322 triangle[2][1] = (float) upperRight.getY();
323 triangle[2][2] = (float) minimalHeightlevel;
324 triangles.add( triangle );
325 } else {
326 setLowerLeft( GeometryFactory.createPoint( lowerLeft.getX(),
327 lowerLeft.getY(),
328 minimalHeightlevel,
329 lowerLeft.getCoordinateSystem() ) );
330 setLowerRight( GeometryFactory.createPoint( lowerRight.getX(),
331 lowerRight.getY(),
332 minimalHeightlevel,
333 lowerRight.getCoordinateSystem() ) );
334 setUpperRight( GeometryFactory.createPoint( upperRight.getX(),
335 upperRight.getY(),
336 minimalHeightlevel,
337 upperRight.getCoordinateSystem() ) );
338 setUpperLeft( GeometryFactory.createPoint( upperLeft.getX(),
339 upperLeft.getY(),
340 minimalHeightlevel,
341 upperLeft.getCoordinateSystem() ) );
342 LOG.logDebug( "Trying to create triangles with the visad library" );
343 VisADWrapper vw = new VisADWrapper( measurePoints, scale );
344 triangles = vw.getTriangleCollectionAsList();
345 LOG.logDebug( "Creation of triangles with the visad library was successfull." );
346 }
347
348 double widthInv = 1d / terrainWidth;
349 double heightInv = 1d / terrainHeight;
350 Position originalLowerLeft = boundingBox.getMin();
351
352 GeometryInfo geometryInfo = new GeometryInfo( GeometryInfo.TRIANGLE_ARRAY );
353
354 BufferedImage texture = getTexture();
355 if ( texture != null )
356 geometryInfo.setTextureCoordinateParams( 1, 2 );
357
358 Point3f[] coordinates = new Point3f[triangles.size() * 3];
359 TexCoord2f[] texCoords = new TexCoord2f[triangles.size() * 3];
360
361 int coordNr = 0;
362 for ( float[][] triangleCoords : triangles ) {
363 for ( int k = 0; k < 3; k++ ) {
364 // System.out.println( Thread.currentThread() + "-> coordNR: " + coordNr );
365 Point3f modelCoordinate = new Point3f( triangleCoords[k][0], triangleCoords[k][1], triangleCoords[k][2] );
366 coordinates[coordNr] = modelCoordinate;
367
368 if ( texture != null ) {
369 double texCoordX = ( modelCoordinate.x - originalLowerLeft.getX() ) * widthInv;
370 double texCoordY = ( modelCoordinate.y - originalLowerLeft.getY() ) * heightInv;
371 texCoords[coordNr] = new TexCoord2f( (float) Math.min( 1d, texCoordX ),
372 (float) Math.min( 1d, texCoordY ) );
373 }
374 coordNr++;
375 }
376
377 }
378 geometryInfo.setCoordinates( coordinates );
379 if ( texture != null ) {
380 geometryInfo.setTextureCoordinates( 0, texCoords );
381 }
382 geometryInfo.recomputeIndices();
383 NormalGenerator ng = new NormalGenerator();
384 ng.generateNormals( geometryInfo );
385
386 setGeometry( geometryInfo.getGeometryArray() );
387 }
388
389 /**
390 * Finds ther heights in the proximity of the border and creates the heights on the seam which will be added to the
391 * (wfs) measure-points of both the caller and the argument.
392 *
393 * @param neighbour
394 * the right neighbour of the envelope of this resolutionstripe. <code>
395 * ______seam__________
396 * |
397 * this | neighbour
398 * ________|___________
399 * seam
400 *</code>
401 */
402 public void createVerticalSeam( TriangleTerrain neighbour ) {
403 if ( measurePoints == null || neighbour.measurePoints == null ) {
404 LOG.logError( "No measurepoints available in this ResolutionStripe, therefor the method createVerticalSeam immediately returns" );
405 return;
406 }
407
408 // variables for this ResolutionStripe
409 double rightXLine = boundingBox.getMax().getX() - ( terrainWidth * 0.1 );
410 // sorted in y diretion
411 SortedMap<Double, Point> myApproximatePoints = new TreeMap<Double, Point>();
412
413 // variables for the neighbour
414 List<Point> neighboursMeasurePoints = neighbour.measurePoints;
415 Envelope neighbourBBox = neighbour.boundingBox;
416 double neighbourWidth = neighbour.terrainWidth;
417 double leftXLine = boundingBox.getMin().getX() + ( neighbourWidth * 0.1 );
418 // sorted in y diretion
419 SortedMap<Double, Point> neighbourApproximatePoints = new TreeMap<Double, Point>();
420
421 double lowerBorder = boundingBox.getMin().getY();
422 if ( lowerBorder < neighbourBBox.getMin().getY() ) {
423 lowerBorder = neighbourBBox.getMin().getY();
424 }
425 double upperBorder = boundingBox.getMax().getY();
426 if ( upperBorder > neighbourBBox.getMax().getY() ) {
427 upperBorder = neighbourBBox.getMax().getY();
428 }
429
430 //
431 // find the nearest z-level values to insert into the dgm on the boundingbox edges, these
432 // might be slidely wrong but approximate the terrain fairly well.
433 for ( Point p : measurePoints ) {
434 double xValue = p.getX();
435 double yValue = p.getY();
436 // only check those points which lie on the border of the two adjacent resolutionstripes
437 if ( yValue >= lowerBorder && yValue <= upperBorder ) {
438 if ( xValue > rightXLine ) {
439 Double fromMinYSmall = new Double( yValue - 0.001 );
440 Double fromMinYLarge = new Double( yValue + 0.001 );
441
442 // finding keys which are epsilon near to the min and max values
443 SortedMap<Double, Point> tileMinYMap = myApproximatePoints.subMap( fromMinYSmall, fromMinYLarge );
444
445 if ( tileMinYMap.isEmpty() ) {
446 myApproximatePoints.put( Double.valueOf( yValue ), p );
447 } else {// there is a point on this horizontal line take the most right
448 Point tmpPoint = myApproximatePoints.get( tileMinYMap.firstKey() );
449 if ( tmpPoint != null ) {
450 if ( tmpPoint.getX() < xValue ) {
451 myApproximatePoints.put( tileMinYMap.firstKey(), p );
452 }
453 } else {// was mapped to null
454 myApproximatePoints.put( Double.valueOf( yValue ), p );
455 }
456 }
457 }
458 }
459 }
460
461 for ( Point p : neighboursMeasurePoints ) {
462 double xValue = p.getX();
463 double yValue = p.getY();
464 // only check those points which lie on the border of the two adjacent resolutionstripes
465 if ( yValue >= lowerBorder && yValue <= upperBorder ) {
466 if ( xValue <= leftXLine ) {
467 Double fromMinYSmall = new Double( yValue - 0.001 );
468 Double fromMinYLarge = new Double( yValue + 0.001 );
469
470 // finding keys which are epsilon near to the min and max values
471 SortedMap<Double, Point> tileMinYMap = neighbourApproximatePoints.subMap( fromMinYSmall,
472 fromMinYLarge );
473
474 if ( tileMinYMap.isEmpty() ) {
475 neighbourApproximatePoints.put( Double.valueOf( yValue ), p );
476 } else {// there is a point on this horizontal line take the most right
477 Point tmpPoint = neighbourApproximatePoints.get( tileMinYMap.firstKey() );
478 if ( tmpPoint != null ) {
479 if ( tmpPoint.getX() > xValue ) {
480 neighbourApproximatePoints.put( tileMinYMap.firstKey(), p );
481 }
482 } else {// was mapped to null
483 neighbourApproximatePoints.put( Double.valueOf( yValue ), p );
484 }
485 }
486 }
487 }
488
489 }
490
491 SortedMap<Double, Point> seam = new TreeMap<Double, Point>();
492
493 // add points on the left envelope bound
494 Set<Double> keys = myApproximatePoints.keySet();
495 for ( Double key : keys ) {
496 Point p = myApproximatePoints.get( key );
497 if ( p != null ) {
498 double zValue = ( p.getZ() < minimalHeightlevel ) ? minimalHeightlevel : p.getZ();
499 seam.put( key, GeometryFactory.createPoint( boundingBox.getMax().getX(),
500 key.doubleValue(),
501 zValue,
502 boundingBox.getCoordinateSystem() ) );
503 if ( Math.abs( zValue - minimalHeightlevel ) > 0.0001 ) {
504 int sign = ( rand.nextBoolean() ) ? 1 : -1;
505 double extra = sign * ( rand.nextDouble() );
506 double newKey = key.doubleValue() + extra;
507 seam.put( new Double( newKey ),
508 GeometryFactory.createPoint( boundingBox.getMax().getX() + ( extra * 10 ),
509 newKey,
510 minimalHeightlevel,
511 boundingBox.getCoordinateSystem() ) );
512 }
513 }
514 }
515 // add points on the right envelope bound
516 keys = neighbourApproximatePoints.keySet();
517 for ( Double key : keys ) {
518 Point p = neighbourApproximatePoints.get( key );
519 if ( p != null ) {
520 double zValue = ( p.getZ() < minimalHeightlevel ) ? minimalHeightlevel : p.getZ();
521 seam.put( key, GeometryFactory.createPoint( neighbourBBox.getMin().getX(),
522 key.doubleValue(),
523 zValue,
524 neighbourBBox.getCoordinateSystem() ) );
525 if ( Math.abs( zValue - minimalHeightlevel ) > 0.0001 ) {
526 int sign = ( rand.nextBoolean() ) ? 1 : -1;
527 double extra = sign * ( rand.nextDouble() );
528 double newKey = key.doubleValue() + extra;
529 seam.put( new Double( newKey ),
530 GeometryFactory.createPoint( neighbourBBox.getMin().getX() + ( extra * 10 ),
531 newKey,
532 minimalHeightlevel,
533 boundingBox.getCoordinateSystem() ) );
534 }
535 }
536 }
537
538 Point neighbourLowerLeft = neighbour.lowerLeft;
539 Point neighbourUpperLeft = neighbour.upperLeft;
540
541 if ( Math.abs( lowerRight.getX() - neighbourLowerLeft.getX() ) <= 0.0001 && Math.abs( lowerRight.getY() - neighbourLowerLeft.getY() ) <= 0.0001 ) {
542 if ( lowerRight.getZ() < neighbourLowerLeft.getZ() ) {
543 neighbour.setLowerLeft( lowerRight );
544 } else {
545 setLowerRight( neighbourLowerLeft );
546 }
547 } else {
548 if ( Math.abs( lowerRight.getY() - lowerBorder ) <= 0.0001 ) {
549 seam.put( new Double( lowerRight.getY() ), lowerRight );
550 } else {
551 seam.put( new Double( neighbourLowerLeft.getY() ), neighbourLowerLeft );
552 }
553 }
554 if ( Math.abs( upperRight.getX() - neighbourUpperLeft.getX() ) <= 0.0001 && Math.abs( upperRight.getY() - neighbourUpperLeft.getY() ) <= 0.0001 ) {
555 if ( upperRight.getZ() < neighbourUpperLeft.getZ() ) {
556 neighbour.setUpperLeft( upperRight );
557 } else {
558 setUpperRight( neighbourUpperLeft );
559 }
560 } else {
561 if ( Math.abs( upperRight.getY() - upperBorder ) <= 0.0001 ) {
562 seam.put( new Double( upperRight.getY() ), upperRight );
563 } else {
564 seam.put( new Double( neighbourUpperLeft.getY() ), neighbourUpperLeft );
565 }
566 }
567
568 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
569 LOG.logDebug( "Vertically sowing: \n" + WKTAdapter.export( boundingBox )
570 + "\n"
571 + WKTAdapter.export( neighbour.boundingBox ) );
572 for ( Point p : seam.values() ) {
573 try {
574 LOG.logDebug( WKTAdapter.export( p ).toString() );
575 } catch ( GeometryException e ) {
576 e.printStackTrace();
577 }
578 }
579 }
580
581 measurePoints.addAll( seam.values() );
582 neighboursMeasurePoints.addAll( seam.values() );
583 }
584
585 /**
586 * Finds ther heights in the proximity of the border and creates the heights on the seam which will be added to the
587 * (wfs) measure-points of both the caller and the argument.
588 *
589 * @param neighbour
590 * the upper neighbour of the envelope of this resolutionstripe. <code>
591 * | |
592 * | neighbour |
593 * seam -------------seam
594 * | this |
595 * | |
596 * leftBorder rightBorder
597 *</code>
598 */
599 public void createHorizontalSeam( TriangleTerrain neighbour ) {
600 if ( measurePoints == null || neighbour.measurePoints == null ) {
601 LOG.logError( "No measurepoints available in this ResolutionStripe, therefor the method createVerticalSeam immediately returns" );
602 return;
603 }
604 // variables for this ResolutionStripe
605 double lowerYLine = boundingBox.getMax().getY() - ( terrainHeight * 0.1 );
606 // sorted in x direction
607 SortedMap<Double, Point> myApproximatePoints = new TreeMap<Double, Point>();
608
609 // variables for the neighbour
610 List<Point> neighboursMeasurePoints = neighbour.measurePoints;
611 Envelope neighbourBBox = neighbour.boundingBox;
612 double neighbourHeight = neighbourBBox.getHeight();
613 double upperYLine = boundingBox.getMin().getY() + ( neighbourHeight * 0.1 );
614 // sorted in x direction
615 SortedMap<Double, Point> neighbourApproximatePoints = new TreeMap<Double, Point>();
616
617 double leftBorder = boundingBox.getMin().getX();
618 if ( leftBorder < neighbourBBox.getMin().getX() ) {
619 leftBorder = neighbourBBox.getMin().getX();
620 }
621 double rightBorder = boundingBox.getMax().getX();
622 if ( rightBorder > neighbourBBox.getMax().getX() ) {
623 rightBorder = neighbourBBox.getMax().getX();
624 }
625
626 //
627 // find the nearest z-level values to insert into the dgm on the boundingbox edges, these
628 // might be slidely wrong but approximate the terrain fairly well.
629 for ( Point p : measurePoints ) {
630 double xValue = p.getX();
631 double yValue = p.getY();
632 // only check those points which lie on the border of the two adjacent resolutionstripes
633 if ( xValue >= leftBorder && xValue <= rightBorder ) {
634 if ( yValue >= lowerYLine ) {
635 Double fromXSmall = new Double( xValue - 0.001 );
636 Double fromXLarge = new Double( xValue + 0.001 );
637
638 // finding keys which are epsilon near to the min and max values
639 SortedMap<Double, Point> tileMinYMap = myApproximatePoints.subMap( fromXSmall, fromXLarge );
640
641 if ( tileMinYMap.isEmpty() ) {
642 myApproximatePoints.put( Double.valueOf( xValue ), p );
643 } else {// there is a point on this horizontal line take the most right
644 Point tmpPoint = myApproximatePoints.get( tileMinYMap.firstKey() );
645 if ( tmpPoint != null ) {
646 if ( tmpPoint.getY() < yValue ) {
647 myApproximatePoints.put( tileMinYMap.firstKey(), p );
648 }
649 } else {// was mapped to null
650 myApproximatePoints.put( Double.valueOf( xValue ), p );
651 }
652 }
653 }
654 }
655 }
656
657 for ( Point p : neighboursMeasurePoints ) {
658 double xValue = p.getX();
659 double yValue = p.getY();
660 // only check those points which lie on the border of the two adjacent resolutionstripes
661 if ( xValue >= leftBorder && xValue <= rightBorder ) {
662 if ( yValue <= upperYLine ) {
663 Double fromXSmall = new Double( xValue - 0.001 );
664 Double fromXLarge = new Double( xValue + 0.001 );
665
666 // finding keys which are epsilon near to the min and max values
667 SortedMap<Double, Point> tileMinYMap = neighbourApproximatePoints.subMap( fromXSmall, fromXLarge );
668
669 if ( tileMinYMap.isEmpty() ) {
670 neighbourApproximatePoints.put( Double.valueOf( xValue ), p );
671 } else {// there is a point on this horizontal line take the most right
672 Point tmpPoint = neighbourApproximatePoints.get( tileMinYMap.firstKey() );
673 if ( tmpPoint != null ) {
674 if ( tmpPoint.getY() > yValue ) {
675 neighbourApproximatePoints.put( tileMinYMap.firstKey(), p );
676 }
677 } else {// was mapped to null
678 neighbourApproximatePoints.put( Double.valueOf( xValue ), p );
679 }
680 }
681 }
682 }
683
684 }
685
686 SortedMap<Double, Point> seam = new TreeMap<Double, Point>();
687
688 // add points on the left envelope bound
689 Set<Double> keys = myApproximatePoints.keySet();
690 for ( Double key : keys ) {
691 Point p = myApproximatePoints.get( key );
692 if ( p != null ) {
693 double zValue = ( p.getZ() < minimalHeightlevel ) ? minimalHeightlevel : p.getZ();
694 seam.put( key, GeometryFactory.createPoint( key.doubleValue(),
695 boundingBox.getMax().getY(),
696 zValue,
697 boundingBox.getCoordinateSystem() ) );
698 if ( Math.abs( zValue - minimalHeightlevel ) > 0.0001 ) {
699 int sign = ( rand.nextBoolean() ) ? 1 : -1;
700 double extra = sign * ( rand.nextDouble() );
701 double newKey = key.doubleValue() + extra;
702 seam.put( new Double( newKey ), GeometryFactory.createPoint( newKey,
703 boundingBox.getMax().getY() + extra
704 * 10,
705 minimalHeightlevel,
706 boundingBox.getCoordinateSystem() ) );
707 }
708 }
709 }
710 // add points on the right envelope bound
711 keys = neighbourApproximatePoints.keySet();
712 for ( Double key : keys ) {
713 Point p = neighbourApproximatePoints.get( key );
714 if ( p != null ) {
715 double zValue = ( p.getZ() < minimalHeightlevel ) ? minimalHeightlevel : p.getZ();
716 seam.put( key, GeometryFactory.createPoint( key.doubleValue(),
717 neighbourBBox.getMin().getY(),
718 zValue,
719 neighbourBBox.getCoordinateSystem() ) );
720 if ( Math.abs( zValue - minimalHeightlevel ) > 0.0001 ) {
721 int sign = ( rand.nextBoolean() ) ? 1 : -1;
722 double extra = sign * ( rand.nextDouble() );
723 double newKey = key.doubleValue() + extra;
724 seam.put( new Double( newKey ), GeometryFactory.createPoint( newKey,
725 neighbourBBox.getMin().getY() + extra
726 * 10,
727 minimalHeightlevel,
728 boundingBox.getCoordinateSystem() ) );
729 }
730 }
731 }
732
733 Point neighbourLowerLeft = neighbour.lowerLeft;
734 Point neighbourLowerRight = neighbour.lowerRight;
735
736 if ( Math.abs( upperLeft.getX() - neighbourLowerLeft.getX() ) <= 0.0001 && Math.abs( upperLeft.getY() - neighbourLowerLeft.getY() ) <= 0.0001 ) {
737 if ( upperLeft.getZ() < neighbourLowerLeft.getZ() ) {
738 setUpperLeft( neighbourLowerLeft );
739 } else {
740 neighbour.setLowerLeft( upperLeft );
741 }
742 } else {
743 if ( Math.abs( upperLeft.getX() - leftBorder ) <= 0.0001 ) {
744 seam.put( new Double( upperLeft.getX() ), upperLeft );
745 } else {
746 seam.put( new Double( neighbourLowerLeft.getX() ), neighbourLowerLeft );
747 }
748 }
749
750 if ( Math.abs( upperRight.getX() - neighbourLowerRight.getX() ) <= 0.0001 && Math.abs( upperRight.getY() - neighbourLowerRight.getY() ) <= 0.0001 ) {
751 if ( upperRight.getZ() < neighbourLowerRight.getZ() ) {
752 setUpperRight( neighbourLowerRight );
753 } else {
754 neighbour.setLowerRight( upperRight );
755 }
756 } else {
757 if ( Math.abs( upperRight.getX() - rightBorder ) <= 0.0001 ) {
758 seam.put( new Double( upperRight.getX() ), upperRight );
759 removeUpperRightPoint();
760 } else {
761 seam.put( new Double( neighbourLowerRight.getX() ), neighbourLowerRight );
762 neighbour.removeLowerRightPoint();
763 }
764 }
765 if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
766 LOG.logDebug( "horizontally sowing: \n" + WKTAdapter.export( boundingBox )
767 + "\n"
768 + WKTAdapter.export( neighbour.boundingBox ) );
769 for ( Point p : seam.values() ) {
770 try {
771 LOG.logDebug( WKTAdapter.export( p ).toString() );
772 } catch ( GeometryException e ) {
773 e.printStackTrace();
774 }
775 }
776 }
777 measurePoints.addAll( seam.values() );
778 neighboursMeasurePoints.addAll( seam.values() );
779 }
780
781 /**
782 * @param newPoint
783 * the lowerLeft Point of this request
784 */
785 private void setLowerLeft( Point newPoint ) {
786 removeLowerLeftPoint();
787 lowerLeft = newPoint;
788 measurePoints.add( lowerLeft );
789 }
790
791 /**
792 * @param newPoint
793 * the lowerLeft Point of this request
794 */
795 private void setLowerRight( Point newPoint ) {
796 removeLowerRightPoint();
797 lowerRight = newPoint;
798 measurePoints.add( lowerRight );
799 }
800
801 /**
802 * @param newPoint
803 * the lowerLeft Point of this request
804 */
805 private void setUpperRight( Point newPoint ) {
806 removeUpperRightPoint();
807 upperRight = newPoint;
808 measurePoints.add( upperRight );
809 }
810
811 /**
812 * @param newPoint
813 * the lowerLeft Point of this request
814 */
815 private void setUpperLeft( Point newPoint ) {
816 removeUpperLeftPoint();
817 upperLeft = newPoint;
818 measurePoints.add( upperLeft );
819 }
820
821 /**
822 * removes the one of the four points of this terrain
823 */
824 private void removeLowerLeftPoint() {
825 if ( lowerLeft != null ) {
826 measurePoints.remove( lowerLeft );
827 }
828 }
829
830 private void removeLowerRightPoint() {
831 if ( lowerRight != null ) {
832 measurePoints.remove( lowerRight );
833 }
834 }
835
836 private void removeUpperRightPoint() {
837 if ( upperRight != null ) {
838 measurePoints.remove( upperRight );
839 }
840 }
841
842 private void removeUpperLeftPoint() {
843 if ( upperLeft != null ) {
844 measurePoints.remove( upperLeft );
845 }
846 }
847
848 }