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