001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/graphics/displayelements/LabelFactory.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 static 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 Aennchenstr. 19
030 53115 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 package org.deegree.graphics.displayelements;
044
045 import java.awt.Color;
046 import java.awt.Font;
047 import java.awt.Graphics2D;
048 import java.awt.font.FontRenderContext;
049 import java.awt.font.LineMetrics;
050 import java.awt.geom.Rectangle2D;
051 import java.util.ArrayList;
052 import java.util.Collections;
053 import java.util.Iterator;
054 import java.util.List;
055
056 import org.deegree.graphics.sld.Halo;
057 import org.deegree.graphics.sld.LabelPlacement;
058 import org.deegree.graphics.sld.LinePlacement;
059 import org.deegree.graphics.sld.PointPlacement;
060 import org.deegree.graphics.sld.TextSymbolizer;
061 import org.deegree.graphics.transformation.GeoTransform;
062 import org.deegree.model.feature.Feature;
063 import org.deegree.model.filterencoding.FilterEvaluationException;
064 import org.deegree.model.spatialschema.Curve;
065 import org.deegree.model.spatialschema.Geometry;
066 import org.deegree.model.spatialschema.GeometryException;
067 import org.deegree.model.spatialschema.GeometryFactory;
068 import org.deegree.model.spatialschema.LineString;
069 import org.deegree.model.spatialschema.MultiCurve;
070 import org.deegree.model.spatialschema.MultiPoint;
071 import org.deegree.model.spatialschema.MultiSurface;
072 import org.deegree.model.spatialschema.Point;
073 import org.deegree.model.spatialschema.Position;
074 import org.deegree.model.spatialschema.Surface;
075
076 /**
077 * Does the labeling, i.e. creates (screen) <tt>Label</tt> representations from
078 * <tt>LabelDisplayElement</tt>s.
079 * <p>
080 * Different geometry-types (of the LabelDisplayElement) imply different strategies concerning the
081 * way the <tt>Labels</tt> are generated.
082 * <p>
083 *
084 * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
085 * @version $Revision: 9340 $ $Date: 2007-12-27 13:32:12 +0100 (Do, 27 Dez 2007) $
086 */
087 public class LabelFactory {
088
089 /**
090 * @param caption
091 * @param font
092 * @param color
093 * @param metrics
094 * @param feature
095 * @param halo
096 * @param x
097 * @param y
098 * @param w
099 * @param h
100 * @param rotation
101 * @param anchorPointX
102 * @param anchorPointY
103 * @param displacementX
104 * @param displacementY
105 * @return label-representations
106 */
107 public static Label createLabel( String caption, Font font, Color color, LineMetrics metrics, Feature feature,
108 Halo halo, int x, int y, int w, int h, double rotation, double anchorPointX,
109 double anchorPointY, double displacementX, double displacementY ) {
110 if ( rotation == 0.0 ) {
111 return new HorizontalLabel( caption, font, color, metrics, feature, halo, x, y, w, h,
112 new double[] { anchorPointX, anchorPointY }, new double[] { displacementX,
113 displacementY } );
114 }
115 return new RotatedLabel( caption, font, color, metrics, feature, halo, x, y, w, h, rotation,
116 new double[] { anchorPointX, anchorPointY }, new double[] { displacementX,
117 displacementY } );
118
119 }
120
121 /**
122 * @param caption
123 * @param font
124 * @param color
125 * @param metrics
126 * @param feature
127 * @param halo
128 * @param x
129 * @param y
130 * @param w
131 * @param h
132 * @param rotation
133 * @param anchorPoint
134 * @param displacement
135 * @return label-representations
136 */
137 public static Label createLabel( String caption, Font font, Color color, LineMetrics metrics, Feature feature,
138 Halo halo, int x, int y, int w, int h, double rotation, double[] anchorPoint,
139 double[] displacement ) {
140 if ( rotation == 0.0 ) {
141 return new HorizontalLabel( caption, font, color, metrics, feature, halo, x, y, w, h, anchorPoint,
142 displacement );
143 }
144 return new RotatedLabel( caption, font, color, metrics, feature, halo, x, y, w, h, rotation, anchorPoint,
145 displacement );
146
147 }
148
149 /**
150 * Generates label-representations for a given <tt>LabelDisplayElement</tt>.
151 * <p>
152 *
153 * @param element
154 * @param projection
155 * @param g
156 * @return label-representations
157 * @throws Exception
158 */
159 public static Label[] createLabels( LabelDisplayElement element, GeoTransform projection, Graphics2D g )
160 throws Exception {
161
162 Label[] labels = new Label[0];
163 Feature feature = element.getFeature();
164 String caption = element.getLabel().evaluate( feature );
165
166 // sanity check: empty labels are ignored
167 if ( caption == null || caption.trim().equals( "" ) ) {
168 return labels;
169 }
170
171 Geometry geometry = element.getGeometry();
172 TextSymbolizer symbolizer = (TextSymbolizer) element.getSymbolizer();
173
174 // gather font information
175 org.deegree.graphics.sld.Font sldFont = symbolizer.getFont();
176 java.awt.Font font = new java.awt.Font( sldFont.getFamily( feature ), sldFont.getStyle( feature )
177 | sldFont.getWeight( feature ),
178 sldFont.getSize( feature ) );
179 g.setFont( font );
180 FontRenderContext frc = g.getFontRenderContext();
181 Rectangle2D bounds = font.getStringBounds( caption, frc );
182 LineMetrics metrics = font.getLineMetrics( caption, frc );
183 int w = (int) bounds.getWidth();
184 int h = (int) bounds.getHeight();
185 // int descent = (int) metrics.getDescent ();
186
187 if ( geometry instanceof Point || geometry instanceof MultiPoint ) {
188
189 // get screen coordinates
190 int[] coords = calcScreenCoordinates( projection, geometry );
191 int x = coords[0];
192 int y = coords[1];
193
194 // default placement information
195 double rotation = 0.0;
196 double[] anchorPoint = { 0.0, 0.5 };
197 double[] displacement = { 0.0, 0.0 };
198
199 // use placement information from SLD
200 LabelPlacement lPlacement = symbolizer.getLabelPlacement();
201
202 if ( lPlacement != null ) {
203 PointPlacement pPlacement = lPlacement.getPointPlacement();
204 anchorPoint = pPlacement.getAnchorPoint( feature );
205 displacement = pPlacement.getDisplacement( feature );
206 rotation = pPlacement.getRotation( feature );
207 }
208
209 labels = new Label[] { createLabel( caption, font, sldFont.getColor( feature ), metrics, feature,
210 symbolizer.getHalo(), x, y, w, h, rotation, anchorPoint, displacement ) };
211 } else if ( geometry instanceof Surface || geometry instanceof MultiSurface ) {
212
213 // get screen coordinates
214 int[] coords = calcScreenCoordinates( projection, geometry );
215 int x = coords[0];
216 int y = coords[1];
217
218 // default placement information
219 double rotation = 0.0;
220 double[] anchorPoint = { 0.5, 0.5 };
221 double[] displacement = { 0.0, 0.0 };
222
223 // use placement information from SLD
224 LabelPlacement lPlacement = symbolizer.getLabelPlacement();
225
226 if ( lPlacement != null ) {
227 PointPlacement pPlacement = lPlacement.getPointPlacement();
228
229 // check if the label is to be centered within the intersection
230 // of
231 // the screen surface and the polygon geometry
232 if ( pPlacement.isAuto() ) {
233 Surface screenSurface = GeometryFactory.createSurface( projection.getSourceRect(), null );
234 Geometry intersection = screenSurface.intersection( geometry );
235 if ( intersection != null ) {
236 Position source = intersection.getCentroid().getPosition();
237 x = (int) ( projection.getDestX( source.getX() ) + 0.5 );
238 y = (int) ( projection.getDestY( source.getY() ) + 0.5 );
239 }
240 }
241 anchorPoint = pPlacement.getAnchorPoint( feature );
242 displacement = pPlacement.getDisplacement( feature );
243 rotation = pPlacement.getRotation( feature );
244 }
245
246 labels = new Label[] { createLabel( caption, font, sldFont.getColor( feature ), metrics, feature,
247 symbolizer.getHalo(), x, y, w, h, rotation, anchorPoint, displacement )
248
249 };
250 } else if ( geometry instanceof Curve || geometry instanceof MultiCurve ) {
251 Surface screenSurface = GeometryFactory.createSurface( projection.getSourceRect(), null );
252 Geometry intersection = screenSurface.intersection( geometry );
253 if ( intersection != null ) {
254 List list = null;
255 if ( intersection instanceof Curve ) {
256 list = createLabels( (Curve) intersection, element, g, projection );
257 } else if ( intersection instanceof MultiCurve ) {
258 list = createLabels( (MultiCurve) intersection, element, g, projection );
259 } else {
260 throw new Exception( "Intersection produced unexpected " + "geometry type: '"
261 + intersection.getClass().getName() + "'!" );
262 }
263 labels = new Label[list.size()];
264 for ( int i = 0; i < labels.length; i++ ) {
265 Label label = (Label) list.get( i );
266 labels[i] = label;
267 }
268 }
269 } else {
270 throw new Exception( "LabelFactory does not implement generation " + "of Labels from geometries of type: '"
271 + geometry.getClass().getName() + "'!" );
272 }
273 return labels;
274 }
275
276 /**
277 * Determines positions on the given <tt>MultiCurve</tt> where a caption could be drawn. For
278 * each of this positons, three candidates are produced; one on the line, one above of it and
279 * one below.
280 * <p>
281 *
282 * @param multiCurve
283 * @param element
284 * @param g
285 * @param projection
286 * @return ArrayList containing Arrays of Label-objects
287 * @throws FilterEvaluationException
288 */
289 public static List createLabels( MultiCurve multiCurve, LabelDisplayElement element, Graphics2D g,
290 GeoTransform projection )
291 throws FilterEvaluationException {
292
293 List<Label> placements = Collections.synchronizedList( new ArrayList<Label>( 10 ) );
294 for ( int i = 0; i < multiCurve.getSize(); i++ ) {
295 Curve curve = multiCurve.getCurveAt( i );
296 placements.addAll( createLabels( curve, element, g, projection ) );
297 }
298 return placements;
299 }
300
301 /**
302 * Determines positions on the given <tt>Curve</tt> where a caption could be drawn. For each
303 * of this positons, three candidates are produced; one on the line, one above of it and one
304 * below.
305 * <p>
306 *
307 * @param curve
308 * @param element
309 * @param g
310 * @param projection
311 * @return ArrayList containing Arrays of Label-objects
312 * @throws FilterEvaluationException
313 */
314 public static ArrayList<Label> createLabels( Curve curve, LabelDisplayElement element, Graphics2D g,
315 GeoTransform projection )
316 throws FilterEvaluationException {
317
318 Feature feature = element.getFeature();
319
320 // determine the placement type and parameters from the TextSymbolizer
321 double perpendicularOffset = 0.0;
322 int placementType = LinePlacement.TYPE_ABSOLUTE;
323 double lineWidth = 3.0;
324 int gap = 6;
325 TextSymbolizer symbolizer = ( (TextSymbolizer) element.getSymbolizer() );
326 if ( symbolizer.getLabelPlacement() != null ) {
327 LinePlacement linePlacement = symbolizer.getLabelPlacement().getLinePlacement();
328 if ( linePlacement != null ) {
329 placementType = linePlacement.getPlacementType( element.getFeature() );
330 perpendicularOffset = linePlacement.getPerpendicularOffset( element.getFeature() );
331 lineWidth = linePlacement.getLineWidth( element.getFeature() );
332 gap = linePlacement.getGap( element.getFeature() );
333 }
334 }
335
336 // get width & height of the caption
337 String caption = element.getLabel().evaluate( element.getFeature() );
338 org.deegree.graphics.sld.Font sldFont = symbolizer.getFont();
339 java.awt.Font font = new java.awt.Font( sldFont.getFamily( element.getFeature() ),
340 sldFont.getStyle( element.getFeature() )
341 | sldFont.getWeight( element.getFeature() ),
342 sldFont.getSize( element.getFeature() ) );
343 g.setFont( font );
344 FontRenderContext frc = g.getFontRenderContext();
345 Rectangle2D bounds = font.getStringBounds( caption, frc );
346 LineMetrics metrics = font.getLineMetrics( caption, frc );
347 double width = bounds.getWidth();
348 double height = bounds.getHeight();
349
350 // get screen coordinates of the line
351 int[][] pos = calcScreenCoordinates( projection, curve );
352
353 // ideal distance from the line
354 double delta = height / 2.0 + lineWidth / 2.0;
355
356 // walk along the linestring and "collect" possible placement positions
357 int w = (int) width;
358 int lastX = pos[0][0];
359 int lastY = pos[1][0];
360 int count = pos[2][0];
361 int boxStartX = lastX;
362 int boxStartY = lastY;
363
364 ArrayList<Label> labels = new ArrayList<Label>( 100 );
365 List<int[]> eCandidates = Collections.synchronizedList( new ArrayList<int[]>( 100 ) );
366 int i = 0;
367 int kk = 0;
368 while ( i < count && kk < 100 ) {
369 kk++;
370 int x = pos[0][i];
371 int y = pos[1][i];
372
373 // segment found where endpoint of box should be located?
374 if ( getDistance( boxStartX, boxStartY, x, y ) >= w ) {
375
376 int[] p0 = new int[] { boxStartX, boxStartY };
377 int[] p1 = new int[] { lastX, lastY };
378 int[] p2 = new int[] { x, y };
379
380 int[] p = findPointWithDistance( p0, p1, p2, w );
381 x = p[0];
382 y = p[1];
383
384 lastX = x;
385 lastY = y;
386 int boxEndX = x;
387 int boxEndY = y;
388
389 // does the linesegment run from right to left?
390 if ( x <= boxStartX ) {
391 boxEndX = boxStartX;
392 boxEndY = boxStartY;
393 boxStartX = x;
394 boxStartY = y;
395 x = boxEndX;
396 y = boxEndY;
397 }
398
399 double rotation = getRotation( boxStartX, boxStartY, x, y );
400 double[] deviation = calcDeviation( new int[] { boxStartX, boxStartY }, new int[] { boxEndX, boxEndY },
401 eCandidates );
402
403 Label label = null;
404
405 switch ( placementType ) {
406 case LinePlacement.TYPE_ABSOLUTE: {
407 label = createLabel( caption, font, sldFont.getColor( feature ), metrics, feature,
408 symbolizer.getHalo(), boxStartX, boxStartY, (int) width, (int) height,
409 rotation, 0.0, 0.5, ( w - width ) / 2, perpendicularOffset );
410 break;
411 }
412 case LinePlacement.TYPE_ABOVE: {
413 label = createLabel( caption, font, sldFont.getColor( feature ), metrics, feature,
414 symbolizer.getHalo(), boxStartX, boxStartY, (int) width, (int) height,
415 rotation, 0.0, 0.5, ( w - width ) / 2, delta + deviation[0] );
416 break;
417 }
418 case LinePlacement.TYPE_BELOW:
419 case LinePlacement.TYPE_AUTO: {
420 label = createLabel( caption, font, sldFont.getColor( feature ), metrics, feature,
421 symbolizer.getHalo(), boxStartX, boxStartY, (int) width, (int) height,
422 rotation, 0.0, 0.5, ( w - width ) / 2, -delta - deviation[1] );
423 break;
424 }
425 case LinePlacement.TYPE_CENTER: {
426 label = createLabel( caption, font, sldFont.getColor( feature ), metrics, feature,
427 symbolizer.getHalo(), boxStartX, boxStartY, (int) width, (int) height,
428 rotation, 0.0, 0.5, ( w - width ) / 2, 0.0 );
429 break;
430 }
431 default: {
432 }
433 }
434 labels.add( label );
435 boxStartX = lastX;
436 boxStartY = lastY;
437 eCandidates.clear();
438 } else {
439 eCandidates.add( new int[] { x, y } );
440 lastX = x;
441 lastY = y;
442 i++;
443 }
444 }
445
446 // pick lists of boxes on the linestring
447 ArrayList<Label> pick = new ArrayList<Label>( 100 );
448 int n = labels.size();
449 for ( int j = n / 2; j < labels.size(); j += ( gap + 1 ) ) {
450 pick.add( labels.get( j ) );
451 }
452 for ( int j = n / 2 - ( gap + 1 ); j > 0; j -= ( gap + 1 ) ) {
453 pick.add( labels.get( j ) );
454 }
455 return pick;
456 }
457
458 /**
459 * Calculates the maximum deviation that points on a linestring have to the ideal line between
460 * the starting point and the end point.
461 * <p>
462 * The ideal line is thought to be running from left to right, the left deviation value
463 * generally is above the line, the right value is below.
464 * <p>
465 *
466 * @param start
467 * starting point of the linestring
468 * @param end
469 * end point of the linestring
470 * @param points
471 * points in between
472 * @return maximum deviation
473 */
474 public static double[] calcDeviation( int[] start, int[] end, List<int[]> points ) {
475
476 // extreme deviation to the left
477 double d1 = 0.0;
478 // extreme deviation to the right
479 double d2 = 0.0;
480 Iterator it = points.iterator();
481
482 // eventually swap start and end point
483 if ( start[0] > end[0] ) {
484 int[] tmp = start;
485 start = end;
486 end = tmp;
487 }
488
489 if ( start[0] != end[0] ) {
490 // label orientation is not completly vertical
491 if ( start[1] != end[1] ) {
492 // label orientation is not completly horizontal
493 while ( it.hasNext() ) {
494 int[] point = (int[]) it.next();
495 double u = ( (double) end[1] - (double) start[1] ) / ( (double) end[0] - (double) start[0] );
496 double x = ( u * u * start[0] - u * ( (double) start[1] - (double) point[1] ) + point[0] )
497 / ( 1.0 + u * u );
498 double y = ( x - start[0] ) * u + start[1];
499 double d = getDistance( point, new int[] { (int) ( x + 0.5 ), (int) ( y + 0.5 ) } );
500 if ( y >= point[1] ) {
501 // candidate for left extreme value
502 if ( d > d1 ) {
503 d1 = d;
504 }
505 } else if ( d > d2 ) {
506 // candidate for right extreme value
507 d2 = d;
508 }
509 }
510 } else {
511 // label orientation is completly horizontal
512 while ( it.hasNext() ) {
513 int[] point = (int[]) it.next();
514 double d = point[1] - start[1];
515 if ( d < 0 ) {
516 // candidate for left extreme value
517 if ( -d > d1 ) {
518 d1 = -d;
519 }
520 } else if ( d > d2 ) {
521 // candidate for left extreme value
522 d2 = d;
523 }
524 }
525 }
526 } else {
527 // label orientation is completly vertical
528 while ( it.hasNext() ) {
529 int[] point = (int[]) it.next();
530 double d = point[0] - start[0];
531 if ( d < 0 ) {
532 // candidate for left extreme value
533 if ( -d > d1 ) {
534 d1 = -d;
535 }
536 } else if ( d > d2 ) {
537 // candidate for right extreme value
538 d2 = d;
539 }
540 }
541 }
542 return new double[] { d1, d2 };
543 }
544
545 /**
546 * Finds a point on the line between p1 and p2 that has a certain distance from point p0
547 * (provided that there is such a point).
548 * <p>
549 *
550 * @param p0
551 * point that is used as reference point for the distance
552 * @param p1
553 * starting point of the line
554 * @param p2
555 * end point of the line
556 * @param d
557 * distance
558 * @return point on the line between p1 and p2 that has a certain distance from point p0
559 */
560 public static int[] findPointWithDistance( int[] p0, int[] p1, int[] p2, int d ) {
561
562 double x, y;
563 double x0 = p0[0];
564 double y0 = p0[1];
565 double x1 = p1[0];
566 double y1 = p1[1];
567 double x2 = p2[0];
568 double y2 = p2[1];
569
570 if ( x1 != x2 ) {
571 // line segment does not run vertical
572 double u = ( y2 - y1 ) / ( x2 - x1 );
573 double p = -2 * ( x0 + u * u * x1 - u * ( y1 - y0 ) ) / ( u * u + 1 );
574 double q = ( ( y1 - y0 ) * ( y1 - y0 ) + u * u * x1 * x1 + x0 * x0 - 2 * u * x1 * ( y1 - y0 ) - d * d )
575 / ( u * u + 1 );
576 double minX = x1;
577 double maxX = x2;
578 double minY = y1;
579 double maxY = y2;
580 if ( minX > maxX ) {
581 minX = x2;
582 maxX = x1;
583 }
584 if ( minY > maxY ) {
585 minY = y2;
586 maxY = y1;
587 }
588 x = -p / 2 - Math.sqrt( ( p / 2 ) * ( p / 2 ) - q );
589 if ( x < minX || x > maxX ) {
590 x = -p / 2 + Math.sqrt( ( p / 2 ) * ( p / 2 ) - q );
591 }
592 y = ( x - x1 ) * u + y1;
593 } else {
594 // vertical line segment
595 x = x1;
596 double minY = y1;
597 double maxY = y2;
598
599 if ( minY > maxY ) {
600 minY = y2;
601 maxY = y1;
602 }
603
604 double p = -2 * y0;
605 double q = y0 * y0 + ( x1 - x0 ) * ( x1 - x0 ) - d * d;
606
607 y = -p / 2 - Math.sqrt( ( p / 2 ) * ( p / 2 ) - q );
608 if ( y < minY || y > maxY ) {
609 y = -p / 2 + Math.sqrt( ( p / 2 ) * ( p / 2 ) - q );
610 }
611 }
612 return new int[] { (int) ( x + 0.5 ), (int) ( y + 0.5 ) };
613 }
614
615 /**
616 * @param x1
617 * @param y1
618 * @param x2
619 * @param y2
620 * @return rotation (degree) of the line between two passed coordinates
621 */
622 public static double getRotation( double x1, double y1, double x2, double y2 ) {
623 double dx = x2 - x1;
624 double dy = y2 - y1;
625
626 return Math.toDegrees( Math.atan( dy / dx ) );
627 }
628
629 /**
630 * @param p1
631 * @param p2
632 * @return distance between two passed coordinates
633 */
634 public static double getDistance( int[] p1, int[] p2 ) {
635 double dx = p1[0] - p2[0];
636 double dy = p1[1] - p2[1];
637 return Math.sqrt( dx * dx + dy * dy );
638 }
639
640 /**
641 * @param x1
642 * @param y1
643 * @param x2
644 * @param y2
645 * @return distance between two passed coordinates
646 */
647 public static double getDistance( double x1, double y1, double x2, double y2 ) {
648 double dx = x2 - x1;
649 double dy = y2 - y1;
650 return Math.sqrt( dx * dx + dy * dy );
651 }
652
653 /**
654 * Calculates the screen coordinates of the given <tt>Curve</tt>.
655 * physical screen coordinates
656 */
657 public static int[][] calcScreenCoordinates( GeoTransform projection, Curve curve ) {
658
659 LineString lineString = null;
660 try {
661 lineString = curve.getAsLineString();
662 } catch ( GeometryException e ) {
663 }
664
665 int count = lineString.getNumberOfPoints();
666 int[][] pos = new int[3][];
667 pos[0] = new int[count];
668 pos[1] = new int[count];
669 pos[2] = new int[1];
670
671 int k = 0;
672 for ( int i = 0; i < count; i++ ) {
673 Position position = lineString.getPositionAt( i );
674 double tx = projection.getDestX( position.getX() );
675 double ty = projection.getDestY( position.getY() );
676 if ( i > 0 ) {
677 if ( getDistance( tx, ty, pos[0][k - 1], pos[1][k - 1] ) > 1 ) {
678 pos[0][k] = (int) ( tx + 0.5 );
679 pos[1][k] = (int) ( ty + 0.5 );
680 k++;
681 }
682 } else {
683 pos[0][k] = (int) ( tx + 0.5 );
684 pos[1][k] = (int) ( ty + 0.5 );
685 k++;
686 }
687 }
688 pos[2][0] = k;
689
690 return pos;
691 }
692
693 /**
694 * Returns the physical (screen) coordinates.
695 * @return physical screen coordinates
696 */
697 public static int[] calcScreenCoordinates( GeoTransform projection, Geometry geometry ) {
698
699 int[] coords = new int[2];
700
701 Position source = null;
702 if ( geometry instanceof Point ) {
703 source = ( (Point) geometry ).getPosition();
704 } else if ( geometry instanceof Curve || geometry instanceof MultiCurve ) {
705 source = geometry.getCentroid().getPosition();
706 } else {
707 source = geometry.getCentroid().getPosition();
708 }
709
710 coords[0] = (int) ( projection.getDestX( source.getX() ) + 0.5 );
711 coords[1] = (int) ( projection.getDestY( source.getY() ) + 0.5 );
712 return coords;
713 }
714 }