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 }