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