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 }