001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wpvs/utils/StripeFactory.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/deegree/ 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 Aennchenstraße 19 030 53177 Bonn 031 Germany 032 E-Mail: poth@lat-lon.de 033 034 Prof. Dr. Klaus Greve 035 Department of Geography 036 University of Bonn 037 Meckenheimer Allee 166 038 53115 Bonn 039 Germany 040 E-Mail: greve@giub.uni-bonn.de 041 042 ---------------------------------------------------------------------------*/ 043 044 package org.deegree.ogcwebservices.wpvs.utils; 045 046 import java.awt.Color; 047 import java.awt.Graphics2D; 048 import java.util.ArrayList; 049 050 import javax.media.j3d.Transform3D; 051 import javax.vecmath.Point3d; 052 import javax.vecmath.Vector3d; 053 054 import org.deegree.framework.log.ILogger; 055 import org.deegree.framework.log.LoggerFactory; 056 import org.deegree.framework.util.MapUtils; 057 import org.deegree.model.spatialschema.Envelope; 058 import org.deegree.model.spatialschema.GeometryException; 059 import org.deegree.model.spatialschema.GeometryFactory; 060 import org.deegree.model.spatialschema.Position; 061 import org.deegree.model.spatialschema.Surface; 062 import org.deegree.ogcwebservices.wpvs.j3d.ViewPoint; 063 064 /** 065 * This class divides a visible area into stripes by calculating a resolution for the near clipping 066 * plane and the far clipping plane. The near resolution (the one closest to the viewer) is doubled 067 * until it is <= far clippingplane resolution. If the Viewer has a pitch which is greater than the 068 * angle of view (in other words: looking steeply down) the resolutionstripes are concentric quads, 069 * which are adapted to the form of the footprint (aka. the perspective ViewFrustum's intersection 070 * with the ground). 071 * 072 * @author <a href="mailto:taddei@lat-lon.de">Ugo Taddei</a> 073 * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a> 074 * 075 * @author last edited by: $Author: bezema $ 076 * 077 * $Revision: 6259 $, $Date: 2007-03-20 10:15:15 +0100 (Di, 20 Mär 2007) $ 078 * 079 */ 080 081 public class StripeFactory { 082 private final ILogger LOG = LoggerFactory.getLogger( StripeFactory.class ); 083 084 private final ViewPoint viewPoint; 085 086 private double minScaleResolution; 087 088 /** 089 * @param vp 090 * the capsulation of the location and viewing direction of the viewer. 091 * @param minScaleDenominator 092 * the best possible resolution the datasets can show. 093 */ 094 public StripeFactory( ViewPoint vp, double minScaleDenominator ) { 095 this.viewPoint = vp; 096 if ( minScaleDenominator < 0.0001 ) 097 minScaleDenominator = 0.0001; 098 this.minScaleResolution = minScaleDenominator * MapUtils.DEFAULT_PIXEL_SIZE; 099 } 100 101 /** 102 * Calculates the number of resolutionstripes, their size and their position in 103 * worldcoordinates. 104 * 105 * @param imageWidth 106 * of the request 107 * @param minimalHeight 108 * the minimalHeight of the terrain 109 * @param g2d 110 * if !null the stripes are drawn on the graphics object (handy for debugging 111 * purposes 112 * @param scale 113 * of the heightmap. 114 * @return the resolutionsstripes for the footprint 115 */ 116 public ArrayList<ResolutionStripe> createResolutionStripes( int imageWidth, 117 double minimalHeight, 118 Graphics2D g2d, double scale ) { 119 120 // Transformations used to calculate the footprint 121 Transform3D invertTransform = viewPoint.getSimpleTransform(); 122 invertTransform.invert(); 123 Transform3D transform = viewPoint.getSimpleTransform(); 124 125 Point3d[] footprint = this.viewPoint.getFootprint(); 126 Vector3d farLeft = new Vector3d( footprint[0] ); 127 Vector3d farRight = new Vector3d( footprint[1] ); 128 Vector3d nearLeft = new Vector3d( footprint[2] ); 129 Vector3d nearRight = new Vector3d( footprint[3] ); 130 131 if( g2d != null ){ 132 g2d.drawString( "nearLeft", (int)nearLeft.x, (int)nearLeft.y ); 133 g2d.drawString( "farLeft", (int)farLeft.x, (int)farLeft.y ); 134 g2d.drawString( "nearRight", (int)nearRight.x, (int)nearRight.y ); 135 g2d.drawString( "farRight", (int)farRight.x, (int)farRight.y ); 136 137 138 } 139 140 invertTransform.transform( nearRight ); 141 invertTransform.transform( farRight ); 142 Vector3d length = new Vector3d( farRight ); 143 length.sub( nearRight ); 144 145 // double halfAngleOfView = viewPoint.getAngleOfView() * 0.5; 146 double footprintSideGradient = Math.acos( Math.abs( farRight.y - nearRight.y ) / length.length() ); 147 LOG.logDebug( "halfAngleOfView : " + Math.toDegrees( footprintSideGradient ) ); 148 transform.transform( nearRight ); 149 transform.transform( farRight ); 150 151 // We use a tangens therefore checking if we are close to 0 - 180 152 if ( Math.abs( ( footprintSideGradient + Math.toRadians( 90 ) ) % Math.toRadians( 180 ) ) <= 0.00001 ) 153 return null; 154 155 // !!!!For now the footprint dimensions are in meters 156 double footprintNearResolution = StripeFactory.calcScaleOfVector( nearRight, nearLeft, 157 imageWidth ); 158 159 LOG.logDebug( "nearRight: " + nearRight ); 160 LOG.logDebug( "nearRight: " + nearLeft ); 161 length = new Vector3d( nearLeft ); 162 length.sub( nearRight ); 163 164 LOG.logDebug( "length: " + length.length() ); 165 LOG.logDebug( "nearResolution: " + footprintNearResolution ); 166 LOG.logDebug( "(nearResolution*imageWidth)/sqrt2): " 167 + ( ( footprintNearResolution * imageWidth ) / MapUtils.SQRT2 ) ); 168 double footprintFarResolution = StripeFactory.calcScaleOfVector( farRight, farLeft, 169 imageWidth ); 170 171 // if the near clipping plane is behind the viewer, which means pitch > angleOfView the 172 // resolutionStripes should be centered around the viewpoint 173 if ( viewPoint.isNearClippingplaneBehindViewPoint() ) { 174 return createStripesForHighPitch( invertTransform, transform, farRight, farLeft, 175 nearRight, nearLeft, imageWidth, minimalHeight, 176 footprintSideGradient, footprintNearResolution, 177 footprintFarResolution, g2d, scale ); 178 } 179 return createStripesForFrontalPerspective( invertTransform, transform, farRight, farLeft, 180 nearRight, nearLeft, imageWidth, minimalHeight, 181 footprintSideGradient, footprintNearResolution, 182 footprintFarResolution, g2d, scale ); 183 } 184 185 private ArrayList<ResolutionStripe> createStripesForFrontalPerspective( 186 Transform3D invertTransform, 187 Transform3D transform, 188 Vector3d farRight, 189 Vector3d farLeft, 190 Vector3d nearestRight, 191 Vector3d nearestLeft, 192 double imageWidth, 193 double minimalHeight, 194 double footprintSideGradientAngle, 195 double footprintNearResolution, 196 double footprintFarResolution, 197 Graphics2D g2d, 198 double scale ) { 199 ArrayList<ResolutionStripe> resultStripes = new ArrayList<ResolutionStripe>( 10 ); 200 201 if ( minScaleResolution > footprintNearResolution ){ 202 footprintNearResolution = minScaleResolution; 203 LOG.logWarning( "the footprintnearResolution is smaller than the defined minScaleResolution, replacing footprints resolution accordingly" ); 204 } 205 double resolutionQuotient = Math.floor( footprintFarResolution / footprintNearResolution ); 206 int numberOfStripes = nearestPowerOfTwo( resolutionQuotient ); 207 208 if( numberOfStripes == 0 ){//can happen if the aov is close to the pitch 209 LOG.logDebug("number of stripes in frontal view are null, what to do?" ); 210 } 211 212 // Find the distances to switch levelofdetail 213 for ( int stripesCounter = 0; stripesCounter < numberOfStripes; ++stripesCounter ) { 214 // go back to null point 215 invertTransform.transform( nearestRight ); 216 invertTransform.transform( nearestLeft ); 217 218 double xLength = ( nearestRight.x - nearestLeft.x ) * 0.5; 219 double yLength = xLength / Math.tan( footprintSideGradientAngle ); 220 221 // create the new slice by adding the lengt in x and y direction 222 Vector3d tmpFarRight = new Vector3d( nearestRight.x + xLength, 223 nearestRight.y - yLength, nearestRight.z ); 224 Vector3d tmpFarLeft = new Vector3d( nearestLeft.x - xLength, nearestLeft.y - yLength, 225 nearestLeft.z ); 226 227 // transform the resulting shape back to the original position. 228 transform.transform( tmpFarRight ); 229 transform.transform( tmpFarLeft ); 230 transform.transform( nearestRight ); 231 transform.transform( nearestLeft ); 232 233 ResolutionStripe rs = createResolutionStripe( nearestLeft, nearestRight, tmpFarRight, 234 tmpFarLeft, imageWidth, minimalHeight, 235 scale ); 236 if ( rs != null ) 237 resultStripes.add( rs ); 238 239 /** 240 * For debugging purposes 241 */ 242 if ( g2d != null ) { 243 g2d.setColor( Color.ORANGE ); 244 g2d.drawLine( (int) nearestRight.x, (int) nearestRight.y, (int) nearestLeft.x, 245 (int) nearestLeft.y ); 246 g2d.drawString( "nearestRight", (int)nearestRight.x, (int)nearestRight.y ); 247 g2d.drawString( "nearestLeft", (int)nearestLeft.x, (int)nearestLeft.y ); 248 } 249 250 nearestRight = new Vector3d( tmpFarRight ); 251 nearestLeft = new Vector3d( tmpFarLeft ); 252 } 253 254 ResolutionStripe rs = createResolutionStripe( nearestLeft, nearestRight, farRight, farLeft, 255 imageWidth, minimalHeight, scale ); 256 if ( rs != null ) 257 resultStripes.add( rs ); 258 259 if ( g2d != null ) { 260 g2d.setColor( Color.ORANGE ); 261 g2d.drawLine( (int) nearestRight.x, (int) nearestRight.y, (int) nearestLeft.x, 262 (int) nearestLeft.y ); 263 g2d.drawLine( (int) farRight.x, (int) farRight.y, (int) farLeft.x, (int) farLeft.y ); 264 g2d.drawString( "nearestRight", (int)nearestRight.x, (int)nearestRight.y ); 265 g2d.drawString( "nearestLeft", (int)nearestLeft.x, (int)nearestLeft.y ); 266 267 } 268 269 return resultStripes; 270 } 271 272 /** 273 * This method finds the resolutionstripes around the Viewpoint if the nearClippingplane is 274 * behind the viewer (which happens if the pitch is higher as the angleOfView). 275 * 276 * @param invertTransform 277 * @param transform 278 * @param farRight 279 * @param farLeft 280 * @param nearRight 281 * @param nearLeft 282 * @param imageWidth 283 * @param minimalHeight 284 * @param halfAngleOfView 285 * @param footprintNearResolution 286 * @param footprintFarResolution 287 * @param g2d 288 * @return the ResolutionStripes centered around the viewpoint. 289 */ 290 private ArrayList<ResolutionStripe> createStripesForHighPitch( Transform3D invertTransform, 291 Transform3D transform, 292 Vector3d farRight, 293 Vector3d farLeft, 294 Vector3d nearRight, 295 Vector3d nearLeft, 296 double imageWidth, 297 double minimalHeight, 298 double halfAngleOfView, 299 double footprintNearResolution, 300 double footprintFarResolution, 301 Graphics2D g2d, double scale ) { 302 ArrayList<ResolutionStripe> resultStripes = new ArrayList<ResolutionStripe>( 40 ); 303 304 // double halfAngleOfView = viewPoint.getAngleOfView() * 0.5; 305 306 Vector3d origin = new Vector3d( viewPoint.getObserverPosition() ); 307 invertTransform.transform( origin ); 308 309 invertTransform.transform( nearRight ); 310 Vector3d length = new Vector3d( nearRight ); 311 length.sub( origin ); 312 313 halfAngleOfView = Math.acos( Math.abs( origin.y - nearRight.y ) / length.length() ); 314 LOG.logDebug( "halfAngleOfView: " + Math.toDegrees( halfAngleOfView ) ); 315 316 transform.transform( nearRight ); 317 318 if ( minScaleResolution > footprintNearResolution ) 319 footprintNearResolution = minScaleResolution; 320 321 double resolutionStripeLength = imageWidth * ( minScaleResolution / MapUtils.SQRT2 ); 322 323 int numberOfStripesNear = nearestPowerOfTwo( Math.floor( footprintNearResolution 324 / minScaleResolution ) ); 325 326 double tangensOfHalfAngleOfView = Math.tan( halfAngleOfView ); 327 328 double yDistance = ( resolutionStripeLength * 0.5 ) / tangensOfHalfAngleOfView; 329 330 LOG.logDebug( "yDistance: " + yDistance ); 331 332 Vector3d backNearestLeft = new Vector3d( origin.x + resolutionStripeLength * 0.5, 333 origin.y - yDistance, nearLeft.z ); 334 Vector3d backNearestRight = new Vector3d( origin.x - resolutionStripeLength * 0.5, 335 origin.y - yDistance, nearLeft.z ); 336 337 Vector3d frontalNearestLeft = new Vector3d( origin.x - resolutionStripeLength * 0.5, 338 origin.y + yDistance, nearLeft.z ); 339 Vector3d frontalNearestRight = new Vector3d( origin.x + resolutionStripeLength * 0.5, 340 origin.y + yDistance, nearLeft.z ); 341 342 transform.transform( backNearestLeft ); 343 transform.transform( backNearestRight ); 344 transform.transform( frontalNearestLeft ); 345 transform.transform( frontalNearestRight ); 346 ResolutionStripe middleStripe = createResolutionStripe( backNearestLeft, backNearestRight, 347 frontalNearestRight, 348 frontalNearestLeft, minimalHeight, 349 minScaleResolution, 350 minScaleResolution, scale ); 351 if ( middleStripe != null ) { 352 resultStripes.add( middleStripe ); 353 } 354 /** 355 * For debugging purpaces 356 */ 357 // if ( g2d != null ) { 358 // g2d.setColor( Color.GREEN ); 359 // g2d.drawLine( (int) backNearestRight.x, (int) backNearestRight.y, 360 // (int) backNearestLeft.x, (int) backNearestLeft.y ); 361 // g2d.setColor( Color.RED ); 362 // g2d.drawLine( (int) frontalNearestRight.x, (int) frontalNearestRight.y, 363 // (int) frontalNearestLeft.x, (int) frontalNearestLeft.y ); 364 // } 365 366 // Find the distances to switch levelofdetail 367 /** 368 * If the near clipping plane is behind the viewer the resolutionstripes are centered around 369 * the viewpoint. <code> 370 * FL = farLeft = UpperLeft 371 * FR = FarRight = UpperRight 372 * NL = nearLeft = LowerLeft 373 * NR = nearRight = LowerRight 374 * VP = viewPoint 375 * R = Right 376 * L = Left 377 * F = front 378 * B = Back 379 * FL__________________FR . 380 * \ / /|\ 381 * \ _F_ / | 382 * \ L |VP| R / viewDir 383 * \ -B- / | 384 * \ / | 385 * NL------NR 386 * </code> 387 */ 388 for ( int stripesCounter = 0; stripesCounter < numberOfStripesNear; ++stripesCounter ) { 389 390 // go back to null point 391 invertTransform.transform( backNearestRight ); 392 invertTransform.transform( backNearestLeft ); 393 // find the distance from the center of the far from the center of the near 394 // clipping plane 395 double xLength = Math.abs( ( backNearestRight.x - backNearestLeft.x ) * 0.5 ); 396 double yLength = xLength / tangensOfHalfAngleOfView; 397 398 // For the frontal perspective ResolutionStripes we need to know the distance from the 399 // origin 400 double nearFrontalYDistance = origin.y + Math.abs( origin.y - backNearestLeft.y ); 401 double farFrontalYDistance = nearFrontalYDistance + yLength; 402 403 // create the new Back-ResolutionStripe by adding the length in x and y direction 404 // according to the angleOfView. From this resolutionStripe the left, front and right 405 // stripes are calculated 406 Vector3d tmpBackLowerLeft = new Vector3d( backNearestLeft.x + xLength, 407 backNearestLeft.y - yLength, 408 backNearestLeft.z ); 409 Vector3d tmpBackLowerRight = new Vector3d( backNearestRight.x - xLength, 410 backNearestRight.y - yLength, 411 backNearestRight.z ); 412 Vector3d tmpBackUpperRight = new Vector3d( backNearestRight.x - xLength, 413 backNearestRight.y, backNearestRight.z ); 414 Vector3d tmpBackUpperLeft = new Vector3d( backNearestLeft.x + xLength, 415 backNearestLeft.y, backNearestLeft.z ); 416 417 // left 418 Vector3d tmpLeftLowerLeft = new Vector3d( tmpBackUpperLeft ); 419 Vector3d tmpLeftLowerRight = new Vector3d( backNearestLeft ); 420 Vector3d tmpLeftUpperRight = new Vector3d( backNearestLeft.x, nearFrontalYDistance, 421 backNearestLeft.z ); 422 Vector3d tmpLeftUpperLeft = new Vector3d( tmpBackUpperLeft.x, nearFrontalYDistance, 423 backNearestLeft.z ); 424 425 // front 426 Vector3d tmpFrontLowerLeft = new Vector3d( tmpLeftUpperLeft ); 427 Vector3d tmpFrontLowerRight = new Vector3d( tmpBackLowerRight.x, nearFrontalYDistance, 428 backNearestLeft.z ); 429 Vector3d tmpFrontUpperRight = new Vector3d( tmpBackLowerRight.x, farFrontalYDistance, 430 backNearestLeft.z ); 431 Vector3d tmpFrontUpperLeft = new Vector3d( tmpLeftUpperLeft.x, farFrontalYDistance, 432 backNearestLeft.z ); 433 434 // right 435 Vector3d tmpRightLowerLeft = new Vector3d( backNearestRight ); 436 Vector3d tmpRightLowerRight = new Vector3d( tmpBackUpperRight ); 437 Vector3d tmpRightUpperRight = new Vector3d( tmpFrontLowerRight ); 438 Vector3d tmpRightUpperLeft = new Vector3d( backNearestRight.x, nearFrontalYDistance, 439 backNearestLeft.z ); 440 441 // transform the resulting shape back to scene space 442 transform.transform( tmpBackLowerLeft ); 443 transform.transform( tmpBackLowerRight ); 444 transform.transform( tmpBackUpperRight ); 445 transform.transform( tmpBackUpperLeft ); 446 447 transform.transform( tmpLeftLowerLeft ); 448 transform.transform( tmpLeftLowerRight ); 449 transform.transform( tmpLeftUpperRight ); 450 transform.transform( tmpLeftUpperLeft ); 451 452 transform.transform( tmpFrontLowerLeft ); 453 transform.transform( tmpFrontLowerRight ); 454 transform.transform( tmpFrontUpperRight ); 455 transform.transform( tmpFrontUpperLeft ); 456 457 transform.transform( tmpRightLowerLeft ); 458 transform.transform( tmpRightLowerRight ); 459 transform.transform( tmpRightUpperRight ); 460 transform.transform( tmpRightUpperLeft ); 461 462 double resolution = StripeFactory.calcScaleOfVector( tmpBackLowerLeft, 463 tmpBackLowerRight, imageWidth ); 464 465 ResolutionStripe rs = createResolutionStripe( tmpBackLowerLeft, tmpBackLowerRight, 466 tmpBackUpperRight, tmpBackUpperLeft, 467 minimalHeight, resolution, resolution, 468 scale ); 469 if ( rs != null ) { 470 resultStripes.add( rs ); 471 } 472 473 rs = createResolutionStripe( tmpLeftLowerLeft, tmpLeftLowerRight, tmpLeftUpperRight, 474 tmpLeftUpperLeft, minimalHeight, resolution, resolution, 475 scale ); 476 if ( rs != null ) { 477 resultStripes.add( rs ); 478 } 479 480 rs = createResolutionStripe( tmpFrontLowerLeft, tmpFrontLowerRight, tmpFrontUpperRight, 481 tmpFrontUpperLeft, minimalHeight, resolution, resolution, 482 scale ); 483 if ( rs != null ) { 484 resultStripes.add( rs ); 485 } 486 487 rs = createResolutionStripe( tmpRightLowerLeft, tmpRightLowerRight, tmpRightUpperRight, 488 tmpRightUpperLeft, minimalHeight, resolution, resolution, 489 scale ); 490 if ( rs != null ) { 491 resultStripes.add( rs ); 492 } 493 /** 494 * For debugging purpaces 495 */ 496 if ( g2d != null ) { 497 g2d.setColor( Color.GREEN ); 498 g2d.drawLine( (int) tmpBackLowerLeft.x, (int) tmpBackLowerLeft.y, 499 (int) tmpBackLowerRight.x, (int) tmpBackLowerRight.y ); 500 g2d.drawLine( (int) tmpBackLowerRight.x, (int) tmpBackLowerRight.y, 501 (int) tmpBackUpperRight.x, (int) tmpBackUpperRight.y ); 502 g2d.drawLine( (int) tmpBackUpperRight.x, (int) tmpBackUpperRight.y, 503 (int) tmpBackUpperLeft.x, (int) tmpBackUpperLeft.y ); 504 g2d.drawLine( (int) tmpBackUpperLeft.x, (int) tmpBackUpperLeft.y, 505 (int) tmpBackLowerLeft.x, (int) tmpBackLowerLeft.y ); 506 507 g2d.setColor( Color.RED ); 508 g2d.drawLine( (int) tmpLeftLowerLeft.x, (int) tmpLeftLowerLeft.y, 509 (int) tmpLeftLowerRight.x, (int) tmpLeftLowerRight.y ); 510 g2d.drawLine( (int) tmpLeftLowerRight.x, (int) tmpLeftLowerRight.y, 511 (int) tmpLeftUpperRight.x, (int) tmpLeftUpperRight.y ); 512 g2d.drawLine( (int) tmpLeftUpperRight.x, (int) tmpLeftUpperRight.y, 513 (int) tmpLeftUpperLeft.x, (int) tmpLeftUpperLeft.y ); 514 g2d.drawLine( (int) tmpLeftUpperLeft.x, (int) tmpLeftUpperLeft.y, 515 (int) tmpLeftLowerLeft.x, (int) tmpLeftLowerLeft.y ); 516 517 g2d.setColor( Color.BLUE ); 518 g2d.drawLine( (int) tmpFrontLowerLeft.x, (int) tmpFrontLowerLeft.y, 519 (int) tmpFrontLowerRight.x, (int) tmpFrontLowerRight.y ); 520 g2d.drawLine( (int) tmpFrontLowerRight.x, (int) tmpFrontLowerRight.y, 521 (int) tmpFrontUpperRight.x, (int) tmpFrontUpperRight.y ); 522 g2d.drawLine( (int) tmpFrontUpperRight.x, (int) tmpFrontUpperRight.y, 523 (int) tmpFrontUpperLeft.x, (int) tmpFrontUpperLeft.y ); 524 g2d.drawLine( (int) tmpFrontUpperLeft.x, (int) tmpFrontUpperLeft.y, 525 (int) tmpFrontLowerLeft.x, (int) tmpFrontLowerLeft.y ); 526 527 g2d.setColor( Color.YELLOW ); 528 g2d.drawLine( (int) tmpRightLowerLeft.x, (int) tmpRightLowerLeft.y, 529 (int) tmpRightLowerRight.x, (int) tmpRightLowerRight.y ); 530 g2d.drawLine( (int) tmpRightLowerRight.x, (int) tmpRightLowerRight.y, 531 (int) tmpRightUpperRight.x, (int) tmpRightUpperRight.y ); 532 g2d.drawLine( (int) tmpRightUpperRight.x, (int) tmpRightUpperRight.y, 533 (int) tmpRightUpperLeft.x, (int) tmpRightUpperLeft.y ); 534 g2d.drawLine( (int) tmpRightUpperLeft.x, (int) tmpRightUpperLeft.y, 535 (int) tmpRightLowerLeft.x, (int) tmpRightLowerLeft.y ); 536 } 537 backNearestRight = new Vector3d( tmpBackLowerRight ); 538 backNearestLeft = new Vector3d( tmpBackLowerLeft ); 539 } 540 541 // Find intersection of the line connecting lowerLeft and upperleft of the footprint 542 invertTransform.transform( nearLeft ); 543 invertTransform.transform( farLeft ); 544 invertTransform.transform( nearRight ); 545 invertTransform.transform( farRight ); 546 invertTransform.transform( backNearestLeft ); 547 invertTransform.transform( backNearestRight ); 548 549 double nearFrontalYDistance = origin.y + Math.abs( origin.y - backNearestLeft.y ); 550 551 /* 552 * We have the circular resolutionstripes, now the last back, left and right stripes (which 553 * are bounded by the footprint) have to be calculated, which can be done by Finding 554 * intersection between a horizontalLine (constant gradient) and the footprint. 555 * 556 * A line is defined as yValue = gradient*xValue + offset therefor intersection between 557 * those two lines as follows: offsetTwo = gradientOne*xValueOne + offsetOne => xValueOne = 558 * (offsetOne - offsetTwo) / gradientOne; 559 */ 560 double gradientLeft = ( nearLeft.y - farLeft.y ) / ( nearLeft.x - farLeft.x ); 561 double offsetLeft = nearLeft.y - (gradientLeft * nearLeft.x); 562 563 double gradientRight = ( nearRight.y - farRight.y ) / ( nearRight.x - farRight.x ); 564 double offsetRight = nearRight.y - gradientRight * nearRight.x; 565 566 double xIntersectionLeft = ( backNearestLeft.y - offsetLeft ) / gradientLeft; 567 double xIntersectionRight = ( backNearestRight.y - offsetRight ) / gradientRight; 568 569 // Back 570 Vector3d tmpBackLowerLeft = new Vector3d( nearLeft ); 571 Vector3d tmpBackLowerRight = new Vector3d( nearRight ); 572 Vector3d tmpBackUpperRight = new Vector3d( xIntersectionRight, backNearestRight.y, 573 backNearestRight.z ); 574 Vector3d tmpBackUpperLeft = new Vector3d( xIntersectionLeft, backNearestLeft.y, 575 backNearestLeft.z ); 576 577 // left 578 xIntersectionLeft = ( nearFrontalYDistance - offsetLeft ) / gradientLeft; 579 Vector3d tmpLeftLowerLeft = new Vector3d( tmpBackUpperLeft ); 580 Vector3d tmpLeftLowerRight = new Vector3d( backNearestLeft ); 581 Vector3d tmpLeftUpperRight = new Vector3d( backNearestLeft.x, nearFrontalYDistance, 582 backNearestLeft.z ); 583 Vector3d tmpLeftUpperLeft = new Vector3d( xIntersectionLeft, nearFrontalYDistance, 584 backNearestLeft.z ); 585 586 // right 587 xIntersectionRight = ( nearFrontalYDistance - offsetRight ) / gradientRight; 588 Vector3d tmpRightLowerLeft = new Vector3d( backNearestRight ); 589 Vector3d tmpRightLowerRight = new Vector3d( tmpBackUpperRight ); 590 Vector3d tmpRightUpperRight = new Vector3d( xIntersectionRight, nearFrontalYDistance, 591 backNearestLeft.z ); 592 Vector3d tmpRightUpperLeft = new Vector3d( backNearestRight.x, nearFrontalYDistance, 593 backNearestLeft.z ); 594 595 // back 596 transform.transform( tmpBackLowerLeft ); 597 transform.transform( tmpBackLowerRight ); 598 transform.transform( tmpBackUpperRight ); 599 transform.transform( tmpBackUpperLeft ); 600 601 // left 602 transform.transform( tmpLeftLowerLeft ); 603 transform.transform( tmpLeftLowerRight ); 604 transform.transform( tmpLeftUpperRight ); 605 transform.transform( tmpLeftUpperLeft ); 606 607 // right 608 transform.transform( tmpRightLowerLeft ); 609 transform.transform( tmpRightLowerRight ); 610 transform.transform( tmpRightUpperRight ); 611 transform.transform( tmpRightUpperLeft ); 612 613 double minResolution = StripeFactory.calcScaleOfVector( tmpBackUpperLeft, 614 tmpBackUpperRight, imageWidth ); 615 double maxResolution = StripeFactory.calcScaleOfVector( tmpBackLowerLeft, 616 tmpBackLowerRight, imageWidth ); 617 resultStripes.add( createResolutionStripe( tmpBackLowerLeft, tmpBackLowerRight, 618 tmpBackUpperRight, tmpBackUpperLeft, 619 minimalHeight, maxResolution, minResolution, 620 scale ) ); 621 resultStripes.add( createResolutionStripe( tmpLeftLowerLeft, tmpLeftLowerRight, 622 tmpLeftUpperRight, tmpLeftUpperLeft, 623 minimalHeight, maxResolution, minResolution, 624 scale ) ); 625 resultStripes.add( createResolutionStripe( tmpRightLowerLeft, tmpRightLowerRight, 626 tmpRightUpperRight, tmpRightUpperLeft, 627 minimalHeight, maxResolution, minResolution, 628 scale ) ); 629 630 /** 631 * For debugging purpaces 632 */ 633 if ( g2d != null ) { 634 g2d.setColor( Color.GREEN ); 635 g2d.drawLine( (int) tmpBackLowerLeft.x, (int) tmpBackLowerLeft.y, 636 (int) tmpBackLowerRight.x, (int) tmpBackLowerRight.y ); 637 g2d.drawLine( (int) tmpBackLowerRight.x, (int) tmpBackLowerRight.y, 638 (int) tmpBackUpperRight.x, (int) tmpBackUpperRight.y ); 639 g2d.drawLine( (int) tmpBackUpperRight.x, (int) tmpBackUpperRight.y, 640 (int) tmpBackUpperLeft.x, (int) tmpBackUpperLeft.y ); 641 g2d.drawLine( (int) tmpBackUpperLeft.x, (int) tmpBackUpperLeft.y, 642 (int) tmpBackLowerLeft.x, (int) tmpBackLowerLeft.y ); 643 644 g2d.setColor( Color.BLUE ); 645 g2d.drawLine( (int) tmpLeftLowerLeft.x, (int) tmpLeftLowerLeft.y, 646 (int) tmpLeftLowerRight.x, (int) tmpLeftLowerRight.y ); 647 g2d.drawString("lll", (int)tmpLeftLowerLeft.x, (int) tmpLeftLowerLeft.y ); 648 g2d.drawLine( (int) tmpLeftLowerRight.x, (int) tmpLeftLowerRight.y, 649 (int) tmpLeftUpperRight.x, (int) tmpLeftUpperRight.y ); 650 g2d.drawString("llr", (int)tmpLeftLowerRight.x, (int) tmpLeftLowerRight.y ); 651 g2d.drawLine( (int) tmpLeftUpperRight.x, (int) tmpLeftUpperRight.y, 652 (int) tmpLeftUpperLeft.x, (int) tmpLeftUpperLeft.y ); 653 g2d.drawString("lur", (int)tmpLeftUpperRight.x, (int) tmpLeftUpperRight.y ); 654 g2d.drawLine( (int) tmpLeftUpperLeft.x, (int) tmpLeftUpperLeft.y, 655 (int) tmpLeftLowerLeft.x, (int) tmpLeftLowerLeft.y ); 656 657 g2d.setColor( Color.YELLOW ); 658 g2d.drawLine( (int) tmpRightLowerLeft.x, (int) tmpRightLowerLeft.y, 659 (int) tmpRightLowerRight.x, (int) tmpRightLowerRight.y ); 660 g2d.drawLine( (int) tmpRightLowerRight.x, (int) tmpRightLowerRight.y, 661 (int) tmpRightUpperRight.x, (int) tmpRightUpperRight.y ); 662 g2d.drawLine( (int) tmpRightUpperRight.x, (int) tmpRightUpperRight.y, 663 (int) tmpRightUpperLeft.x, (int) tmpRightUpperLeft.y ); 664 g2d.drawLine( (int) tmpRightUpperLeft.x, (int) tmpRightUpperLeft.y, 665 (int) tmpRightLowerLeft.x, (int) tmpRightLowerLeft.y ); 666 } 667 668 // What is left, are the frontal Stripes which can be more than one (whith steep pitch). 669 Vector3d tmpFrontLowerLeft = new Vector3d( tmpLeftUpperLeft ); 670 Vector3d tmpFrontLowerRight = new Vector3d( tmpRightUpperRight ); 671 transform.transform( nearLeft ); 672 transform.transform( farLeft ); 673 transform.transform( nearRight ); 674 transform.transform( farRight ); 675 double frontalScale = StripeFactory.calcScaleOfVector( tmpFrontLowerLeft, 676 tmpFrontLowerRight, imageWidth ); 677 if ( Math.abs( ( ( Math.abs( 1.0 / gradientLeft ) ) + Math.toRadians( 90 ) ) 678 % Math.toRadians( 180 ) ) > 0.0001 ) { 679 double footPrintAngle = Math.atan( 1.0 / gradientLeft ); 680 resultStripes.addAll( createStripesForFrontalPerspective( invertTransform, transform, 681 farRight, farLeft, 682 tmpFrontLowerRight, 683 tmpFrontLowerLeft, 684 imageWidth, minimalHeight, 685 footPrintAngle, frontalScale, 686 footprintFarResolution, g2d, 687 scale ) ); 688 } else { 689 // Just one remaining ResolutionStripe, because only a square is left over (could be 690 // rounding error). 691 resultStripes.add( createResolutionStripe( tmpFrontLowerLeft, tmpFrontLowerRight, 692 farRight, farLeft, imageWidth, 693 minimalHeight, scale ) ); 694 } 695 return resultStripes; 696 } 697 698 /** 699 * Creates a ResolutionStripe fromt the given Vectors. The variable names are just indicators 700 * for the order in which the Position are added to the polygon which is min, (min+width), max, 701 * (min+height). 702 * 703 * @param lowerLeft 704 * the min-value of the surface 705 * @param lowerRight 706 * the (min + width)-value of the surface 707 * @param upperRight 708 * the max-value of the surface 709 * @param upperLeft 710 * the (min + height)-value of the surface 711 * @param imageWidth 712 * needed to calculate the resolution 713 * @param minimalHeight 714 * to put the z-value to if it does not exist 715 * @return a brand new ResolutionStripe or <code>null</code> if an exception occurred. 716 */ 717 private ResolutionStripe createResolutionStripe( Vector3d lowerLeft, Vector3d lowerRight, 718 Vector3d upperRight, Vector3d upperLeft, 719 double imageWidth, double minimalHeight, 720 double scale ) { 721 double maxResolution = StripeFactory.calcScaleOfVector( upperRight, upperLeft, imageWidth ); 722 double minResolution = StripeFactory.calcScaleOfVector( lowerRight, lowerLeft, imageWidth ); 723 724 return createResolutionStripe( lowerLeft, lowerRight, upperRight, upperLeft, minimalHeight, 725 maxResolution, minResolution, scale ); 726 } 727 728 private ResolutionStripe createResolutionStripe( Vector3d lowerLeft, Vector3d lowerRight, 729 Vector3d upperRight, Vector3d upperLeft, 730 double minimalHeight, double maxResolution, 731 double minResolution, double scale ) { 732 Position[] pos = new Position[5]; 733 pos[0] = GeometryFactory.createPosition( lowerLeft.x, lowerLeft.y, lowerLeft.z ); 734 pos[1] = GeometryFactory.createPosition( lowerRight.x, lowerRight.y, lowerLeft.z ); 735 pos[2] = GeometryFactory.createPosition( upperRight.x, upperRight.y, lowerLeft.z ); 736 pos[3] = GeometryFactory.createPosition( upperLeft.x, upperLeft.y, lowerLeft.z ); 737 pos[4] = GeometryFactory.createPosition( lowerLeft.x, lowerLeft.y, lowerLeft.z ); 738 739 try { 740 Surface surf = GeometryFactory.createSurface( pos, null, null, viewPoint.getCrs() ); 741 return new ResolutionStripe( surf, maxResolution, minResolution, minimalHeight, scale ); 742 743 } catch ( GeometryException e ) { 744 e.printStackTrace(); 745 } 746 return null; 747 } 748 749 /** 750 * @param bbox 751 * @param imageWidth 752 * @param minimalHeight 753 * @param scale 754 * of the height in the elevationmodel 755 * @return a BoundingBox request ResolutionStripe 756 */ 757 public ArrayList<ResolutionStripe> createBBoxResolutionStripe( Envelope bbox, int imageWidth, 758 double minimalHeight, 759 double scale ) { 760 761 Surface resultSurface = null; 762 try { 763 resultSurface = GeometryFactory.createSurface( bbox, viewPoint.getCrs() ); 764 } catch ( GeometryException e ) { 765 e.printStackTrace(); 766 } 767 Position min = bbox.getMin(); 768 double zValue = min.getZ(); 769 if ( min.getCoordinateDimension() == 2 ) 770 zValue = minimalHeight; 771 772 Vector3d lowerLeftPoint = new Vector3d( min.getX(), min.getY(), zValue ); 773 Vector3d lowerRightPoint = new Vector3d( min.getX() + ( bbox.getWidth() ), min.getY(), 774 zValue ); 775 double resolution = StripeFactory.calcScaleOfVector( lowerLeftPoint, lowerRightPoint, 776 imageWidth ); 777 778 ArrayList<ResolutionStripe> resultStripe = new ArrayList<ResolutionStripe>(); 779 resultStripe.add( new ResolutionStripe( resultSurface, resolution, resolution, 780 minimalHeight, scale ) ); 781 782 return resultStripe; 783 } 784 785 /** 786 * Calculates the Scale ( = Resolution* sqrt( 2 ) (== diagonal of pixel)) of a Vector between 787 * two points on the Screen given an imagewidth. That is, how much meter is the Scale of one 788 * Pixel in an Image given a certain vector. 789 * 790 * @param a 791 * "from" point 792 * @param b 793 * "to" point 794 * @param imageWidth 795 * the target imagewidth 796 * @return the scale on the screen. 797 */ 798 public static double calcScaleOfVector( Vector3d a, Vector3d b, double imageWidth ) { 799 Vector3d line = new Vector3d( a.x - b.x, a.y - b.y, a.z - b.z ); 800 // how much meter is one pixel 801 // scale = the diagonal of one pixel 802 return ( line.length() / imageWidth ) * MapUtils.SQRT2; 803 } 804 805 /** 806 * @param value 807 * @return the nearestPowerOfTwo of the given value 808 */ 809 private int nearestPowerOfTwo( double value ) { 810 int result = 0; 811 int power = 2; 812 while ( power <= value ) { 813 power = power << 1; 814 result++; 815 } 816 return result; 817 } 818 819 }