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 }