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