~andreas.hoelzl/jhelioviewer/jhv-formatting

« back to all changes in this revision

Viewing changes to viewmodel/src/org/helioviewer/viewmodel/view/ViewHelper.java

  • Committer: Andreas Hoelzl
  • Date: 2010-03-19 17:57:44 UTC
  • mfrom: (95.1.25 toTrunk)
  • Revision ID: andreas_hoelzl_23@hotmail.com-20100319175744-4skutkypujboor8f
open Remote File support added

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
import org.helioviewer.viewmodel.viewportimagesize.StaticViewportImageSize;
21
21
import org.helioviewer.viewmodel.viewportimagesize.ViewportImageSize;
22
22
 
23
 
/** Collection of useful functions for use within the view chain.
 
23
/**
 
24
 * Collection of useful functions for use within the view chain.
24
25
 * 
25
 
 * <p>This class provides many different helpful functions, covering
26
 
 * topics such as scaling and alignment of regions, navigation within
27
 
 * the view chain and loading new images
 
26
 * <p>
 
27
 * This class provides many different helpful functions, covering topics such as
 
28
 * scaling and alignment of regions, navigation within the view chain and
 
29
 * loading new images
28
30
 * 
29
31
 * @author Ludwig Schmidt
30
32
 * @author Markus Langenberg
31
 
 *
 
33
 * 
32
34
 */
33
35
public final class ViewHelper {
34
36
 
35
 
        /** Expands the aspect ratio of the given region to the given viewport.
36
 
         * 
37
 
         * <p>When a region is resized, it usually does not fit in the viewport
38
 
         * without distorting it. To prevent unused areas or deformed images,
39
 
         * this function expands the region to fit the viewport.
40
 
         * This might not be possible, if the maximum of the region, given in the
41
 
         * meta data, is reached.
42
 
         * 
43
 
         * <p>Note, that the region is always expanded, never cropped.
44
 
         * 
45
 
         * <p>Also note, that if the aspect ration already is equal, the given
46
 
         * region is returned.
47
 
         * 
48
 
         * @param v Target viewport, which the region should fit in
49
 
         * @param r Source region, which has to be expanded
50
 
         * @param m Meta data of the image, to read maximal region
 
37
        /**
 
38
         * Expands the aspect ratio of the given region to the given viewport.
 
39
         * 
 
40
         * <p>
 
41
         * When a region is resized, it usually does not fit in the viewport without
 
42
         * distorting it. To prevent unused areas or deformed images, this function
 
43
         * expands the region to fit the viewport. This might not be possible, if
 
44
         * the maximum of the region, given in the meta data, is reached.
 
45
         * 
 
46
         * <p>
 
47
         * Note, that the region is always expanded, never cropped.
 
48
         * 
 
49
         * <p>
 
50
         * Also note, that if the aspect ration already is equal, the given region
 
51
         * is returned.
 
52
         * 
 
53
         * @param v
 
54
         *            Target viewport, which the region should fit in
 
55
         * @param r
 
56
         *            Source region, which has to be expanded
 
57
         * @param m
 
58
         *            Meta data of the image, to read maximal region
51
59
         * @return Expanded region
52
60
         * @see #contractRegionToViewportAspectRatio(Viewport, Region, MetaData)
53
61
         */
54
 
    public static Region expandRegionToViewportAspectRatio(Viewport v,
55
 
            Region r, MetaData m) {
56
 
        
57
 
        double viewportRatio = v.getAspectRatio();
58
 
                
59
 
                if(Math.abs(r.getWidth() / r.getHeight() - viewportRatio) > 0.01f) {
 
62
        public static Region expandRegionToViewportAspectRatio(Viewport v,
 
63
                        Region r, MetaData m) {
 
64
 
 
65
                double viewportRatio = v.getAspectRatio();
 
66
 
 
67
                if (Math.abs(r.getWidth() / r.getHeight() - viewportRatio) > 0.01f) {
60
68
                        return StaticRegion.createAdaptedRegion(r.getRectangle()
61
 
                        .expandToAspectRatioKeepingCenter(viewportRatio)
62
 
                        .moveAndCropToOuterRectangle(m.getPhysicalRectangle()));
 
69
                                        .expandToAspectRatioKeepingCenter(viewportRatio)
 
70
                                        .moveAndCropToOuterRectangle(m.getPhysicalRectangle()));
63
71
                } else {
64
72
                        return r;
65
73
                }
66
 
    }
67
 
    
68
 
    /** Contracts the aspect ratio of the given region to the given viewport.
69
 
         * 
70
 
         * <p>When a region is resized, it usually does not fit in the viewport
71
 
         * without distorting it. To prevent unused areas or deformed images,
72
 
         * this function contracts the region to fit the viewport.
73
 
         * 
74
 
         * <p>Note, that if the aspect ration already is equal, the given
75
 
         * region is returned.
76
 
         * 
77
 
         * @param v Target viewport, which the region should fit in
78
 
         * @param r Source region, which has to be contracted
79
 
         * @param m Meta data of the image, to read maximal region
 
74
        }
 
75
 
 
76
        /**
 
77
         * Contracts the aspect ratio of the given region to the given viewport.
 
78
         * 
 
79
         * <p>
 
80
         * When a region is resized, it usually does not fit in the viewport without
 
81
         * distorting it. To prevent unused areas or deformed images, this function
 
82
         * contracts the region to fit the viewport.
 
83
         * 
 
84
         * <p>
 
85
         * Note, that if the aspect ration already is equal, the given region is
 
86
         * returned.
 
87
         * 
 
88
         * @param v
 
89
         *            Target viewport, which the region should fit in
 
90
         * @param r
 
91
         *            Source region, which has to be contracted
 
92
         * @param m
 
93
         *            Meta data of the image, to read maximal region
80
94
         * @return Contracted region
81
95
         * @see #expandRegionToViewportAspectRatio(Viewport, Region, MetaData)
82
96
         */
83
 
    public static Region contractRegionToViewportAspectRatio(Viewport v,
84
 
            Region r, MetaData m) {
85
 
        
86
 
        double viewportRatio = v.getAspectRatio();
87
 
                
88
 
                if(Math.abs(r.getWidth() / r.getHeight() - viewportRatio) > 0.01f) {
 
97
        public static Region contractRegionToViewportAspectRatio(Viewport v,
 
98
                        Region r, MetaData m) {
 
99
 
 
100
                double viewportRatio = v.getAspectRatio();
 
101
 
 
102
                if (Math.abs(r.getWidth() / r.getHeight() - viewportRatio) > 0.01f) {
89
103
                        return StaticRegion.createAdaptedRegion(r.getRectangle()
90
 
                        .contractToAspectRatioKeepingCenter(viewportRatio)
91
 
                        .moveAndCropToOuterRectangle(m.getPhysicalRectangle()));
 
104
                                        .contractToAspectRatioKeepingCenter(viewportRatio)
 
105
                                        .moveAndCropToOuterRectangle(m.getPhysicalRectangle()));
92
106
                } else {
93
107
                        return r;
94
108
                }
95
 
    }
 
109
        }
96
110
 
97
 
    /** Returns a View of given interface or class, starting search at given view.
 
111
        /**
 
112
         * Returns a View of given interface or class, starting search at given
 
113
         * view.
98
114
         * 
99
 
         * If the given view implements the given interface itself, it returns
100
 
         * that very same view, otherwise it returns a suitable view (for example another
101
 
         * view located deeper within the view chain, that can provide the desired 
 
115
         * If the given view implements the given interface itself, it returns that
 
116
         * very same view, otherwise it returns a suitable view (for example another
 
117
         * view located deeper within the view chain, that can provide the desired
102
118
         * information, or null, if that is not possible).
103
119
         * 
104
 
         * @param <T> Subclass of {@link View}
105
 
     * @param v First view to analyze
106
 
     * @param c Class or interface to search for
107
 
     * @return View implementing given class or interface, if available, null otherwise
108
 
     */
109
 
    public static <T extends View> T getViewAdapter(View v, Class<T> c) {
110
 
        return v == null ? null : v.getAdapter(c);
111
 
    }
 
120
         * @param <T>
 
121
         *            Subclass of {@link View}
 
122
         * @param v
 
123
         *            First view to analyze
 
124
         * @param c
 
125
         *            Class or interface to search for
 
126
         * @return View implementing given class or interface, if available, null
 
127
         *         otherwise
 
128
         */
 
129
        public static <T extends View> T getViewAdapter(View v, Class<T> c) {
 
130
                return v == null ? null : v.getAdapter(c);
 
131
        }
112
132
 
113
 
    /** Returns an ImageData object of given class or interface.
114
 
     * 
115
 
     * <p>The function searches the next {@link SubimageDataView}, fetches its
116
 
     * ImageData object and tests, whether it satisfies the given class or
117
 
     * interface. If so, it returns the ImageData object, otherwise, it returns null
118
 
     * 
119
 
     * @param <T> Subclass of {@link org.helioviewer.viewmodel.imagedata.ImageData}
120
 
     * @param v First view to analyze
121
 
     * @param c Class or interface to search for
122
 
     * @return ImageData implementing given class or interface, if available, null otherwise
123
 
     */
124
 
    @SuppressWarnings("unchecked")
 
133
        /**
 
134
         * Returns an ImageData object of given class or interface.
 
135
         * 
 
136
         * <p>
 
137
         * The function searches the next {@link SubimageDataView}, fetches its
 
138
         * ImageData object and tests, whether it satisfies the given class or
 
139
         * interface. If so, it returns the ImageData object, otherwise, it returns
 
140
         * null
 
141
         * 
 
142
         * @param <T>
 
143
         *            Subclass of
 
144
         *            {@link org.helioviewer.viewmodel.imagedata.ImageData}
 
145
         * @param v
 
146
         *            First view to analyze
 
147
         * @param c
 
148
         *            Class or interface to search for
 
149
         * @return ImageData implementing given class or interface, if available,
 
150
         *         null otherwise
 
151
         */
 
152
        @SuppressWarnings("unchecked")
125
153
        public static <T extends ImageData> T getImageDataAdapter(View v, Class<T> c) {
126
154
 
127
 
        SubimageDataView dataView = getViewAdapter(v, SubimageDataView.class);
128
 
 
129
 
        if (dataView == null) {
130
 
            return null;
131
 
 
132
 
        } else if (dataView.getSubimageData() == null) {
133
 
            return null;
134
 
        } else if (!c.isInstance(dataView.getSubimageData())) {
135
 
            return null;
136
 
        } else {
137
 
            return (T) dataView.getSubimageData();
138
 
        }
139
 
    }
140
 
 
141
 
    /** Calculates the final size of a given region within the viewport.
142
 
     * 
143
 
     * <p>The resulting size is smaller or equal to the size of the
144
 
     * viewport. It is equal if and only if the aspect ratio of the region
145
 
     * is equal to the aspect ratio of the viewport. Otherwise, the
146
 
     * image size is cropped to keep the regions aspect ratio and not
147
 
     * deform the image. 
148
 
     * 
149
 
     * @param v viewport, in which the image will be displayed
150
 
     * @param r visible region of the image
151
 
     * @return resulting image size of the region within the viewport
152
 
     */
153
 
    public static ViewportImageSize calculateViewportImageSize(Viewport v,
154
 
            Region r) {
155
 
        if (v == null || r == null) {
156
 
            return null;
157
 
        }
158
 
 
159
 
        double screenMeterPerPixel;
160
 
        double screenSubImageWidth;
161
 
        double screenSubImageHeight;
162
 
 
163
 
        // fit region of interest into viewport
164
 
        if ((double) v.getWidth() / (double) v.getHeight() > r.getWidth()
165
 
                / r.getHeight()) {
166
 
            screenMeterPerPixel = r.getHeight() / v.getHeight();
167
 
            screenSubImageHeight = v.getHeight();
168
 
            screenSubImageWidth = r.getWidth() / screenMeterPerPixel;
169
 
        } else {
170
 
            screenMeterPerPixel = r.getWidth() / v.getWidth();
171
 
            screenSubImageWidth = v.getWidth();
172
 
            screenSubImageHeight = r.getHeight() / screenMeterPerPixel;
173
 
        }
174
 
 
175
 
        return StaticViewportImageSize.createAdaptedViewportImageSize(
176
 
                (int) Math.round(screenSubImageWidth), (int) Math
177
 
                        .round(screenSubImageHeight));
178
 
    }
179
 
 
180
 
    /** Calculates the final size of a given region within the viewport.
181
 
     * 
182
 
     * <p>The resulting size is smaller or equal to the size of the
183
 
     * viewport. It is equal if and only if the aspect ratio of the region
184
 
     * is equal to the aspect ratio of the viewport. Otherwise, the
185
 
     * image size is cropped to keep the regions aspect ratio and not
186
 
     * deform the image.
187
 
     * 
188
 
     * <p>Basically, this function fetches the region and viewport of the
189
 
     * given view and calls {@link #calculateViewportImageSize(Viewport, Region)}.
190
 
     * 
191
 
     * @param v View containing the image. 
192
 
     * @return resulting image size of the region within the viewport
193
 
     */
194
 
    public static ViewportImageSize calculateViewportImageSize(View v) {
195
 
        RegionView regionView = ViewHelper.getViewAdapter(v, RegionView.class);
196
 
        ViewportView viewportView = ViewHelper.getViewAdapter(v,
197
 
                ViewportView.class);
198
 
        if (regionView == null || viewportView == null) {
199
 
            return null;
200
 
        }
201
 
        return calculateViewportImageSize(viewportView.getViewport(),
202
 
                regionView.getRegion());
203
 
    }
204
 
 
205
 
    /** Converts a given displacement on the screen to image coordinates.
206
 
     * 
207
 
     * @param screenDisplacement Displacement on the screen to convert
208
 
     * @param r Region of the image currently visible on the screen
209
 
     * @param v ViewportImageSize of the image within the current viewport
210
 
     * @return Displacement in image coordinates
211
 
     */
212
 
    public static Vector2dDouble convertScreenToImageDisplacement(
213
 
            Vector2dInt screenDisplacement, Region r, ViewportImageSize v) {
214
 
        return convertScreenToImageDisplacement(screenDisplacement.getX(), screenDisplacement.getY(), r, v);
215
 
    }
216
 
    
217
 
    /** Converts a given displacement on the screen to image coordinates.
218
 
     * 
219
 
     * @param screenDisplacementX X-coordinate of the displacement on the screen to convert
220
 
     * @param screenDisplacementY Y-coordinate of the displacement on the screen to convert
221
 
     * @param r Region of the image currently visible on the screen
222
 
     * @param v ViewportImageSize of the image within the current viewport
223
 
     * @return Displacement in image coordinates
224
 
     */
225
 
    public static Vector2dDouble convertScreenToImageDisplacement(
226
 
                int screenDisplacementX, int screenDisplacementY, Region r, ViewportImageSize v) {
227
 
        return new Vector2dDouble(
228
 
                        r.getWidth() / ((double) v.getWidth()) * screenDisplacementX,
229
 
                        -r.getHeight() / ((double) v.getHeight()) * screenDisplacementY);
230
 
    }
231
 
    
232
 
    /** Converts a given displacement on the image to screen coordinates.
233
 
     * 
234
 
     * @param imageDisplacement Displacement on the image to convert
235
 
     * @param r Region of the image currently visible on the screen
236
 
     * @param v ViewportImageSize of the image within the current viewport
237
 
     * @return Displacement in screen coordinates
238
 
     */
239
 
    public static Vector2dInt convertImageToScreenDisplacement(
240
 
            Vector2dDouble imageDisplacement, Region r, ViewportImageSize v) {
241
 
        return convertImageToScreenDisplacement(imageDisplacement.getX(), imageDisplacement.getY(), r, v);
242
 
    }
243
 
 
244
 
    /** Converts a given displacement on the image to screen coordinates.
245
 
     * 
246
 
     * @param imageDisplacementX X-coordinate of the displacement on the image to convert
247
 
     * @param imageDisplacementY Y-coordinate of the displacement on the image to convert
248
 
     * @param r Region of the image currently visible on the screen
249
 
     * @param v ViewportImageSize of the image within the current viewport
250
 
     * @return Displacement in screen coordinates
251
 
     */
252
 
    public static Vector2dInt convertImageToScreenDisplacement(
253
 
            double imageDisplacementX, double imageDisplacementY, Region r, ViewportImageSize v) {
254
 
        return new Vector2dInt(
255
 
                        (int) Math.round(imageDisplacementX / r.getWidth() * v.getWidth()),
256
 
                (int) Math.round(imageDisplacementY / r.getHeight() * v.getHeight()));
257
 
    }
258
 
 
259
 
    /** Ensures, that the given region is within the maximal bounds of the image data.
260
 
     * 
261
 
     * If that is not the case, moves and/or crops the region to the maximal
262
 
     * area given by the meta data.
263
 
     * 
264
 
     * @param r Region to move and crop, if necessary
265
 
     * @param m Meta data defining the maximal region
266
 
     * @return Region located inside the maximal region
267
 
     */
268
 
    public static Region cropRegionToImage(Region r, MetaData m) {
269
 
        return StaticRegion.createAdaptedRegion(r.getRectangle()
270
 
                .moveAndCropToOuterRectangle(m.getPhysicalRectangle()));
271
 
    }
272
 
 
273
 
    /** Ensures, that the given inner region is within the given outer region.
274
 
     * 
275
 
     * If that is not the case, crops the inner region to the outer region.
276
 
     * 
277
 
     * @param innerRegion Inner region to crop, if necessary
278
 
     * @param outerRegion Outer region, defining the maximal bounds
279
 
     * @return region located inside the outer region
280
 
     */
281
 
    public static Region cropInnerRegionToOuterRegion(Region innerRegion,
282
 
            Region outerRegion) {
283
 
        return StaticRegion.createAdaptedRegion(innerRegion.getRectangle()
284
 
                .cropToOuterRectangle(outerRegion.getRectangle()));
285
 
    }
286
 
 
287
 
    /** Calculates the inner viewport to the corresponding inner region.
288
 
     * 
289
 
     * Given the outer region and the outer viewport image size, this function
290
 
     * calculates the part of the outer viewport image size, that is occupied
291
 
     * by the inner region. 
292
 
     * 
293
 
     * @param innerRegion inner region, whose inner viewport is requested
294
 
     * @param outerRegion outer region, as a reference
295
 
     * @param outerViewportImageSize outer viewport image size, as a reference
296
 
     * @return viewport corresponding to the inner region based on the outer
297
 
     * region and viewport image size
298
 
     * @see #calculateInnerViewportOffset
299
 
     */
300
 
    public static Viewport calculateInnerViewport(Region innerRegion,
301
 
            Region outerRegion, ViewportImageSize outerViewportImageSize) {
302
 
        double newWidth = outerViewportImageSize.getWidth()
303
 
                * innerRegion.getWidth() / outerRegion.getWidth();
304
 
        double newHeight = outerViewportImageSize.getHeight()
305
 
                * innerRegion.getHeight() / outerRegion.getHeight();
306
 
        return StaticViewport.createAdaptedViewport((int) Math.round(newWidth),
307
 
                (int) Math.round(newHeight));
308
 
    }
309
 
 
310
 
    /** Calculates the offset of the inner viewport relative to the outer viewport
311
 
     * image size.
312
 
     * 
313
 
     * Given the outer region and viewport image size, calculates the offset of
314
 
     * the inner viewport corresponding to the given inner region.
315
 
     * 
316
 
     * @param innerRegion inner region, whose inner viewport offset is requested
317
 
     * @param outerRegion outer region, as a reference
318
 
     * @param outerViewportImageSize outer viewport image size, as a reference
319
 
     * @return offset of the inner viewport based on the outer
320
 
     * region and viewport image size
321
 
     * @see #calculateInnerViewport
322
 
     */
323
 
    public static Vector2dInt calculateInnerViewportOffset(Region innerRegion,
324
 
            Region outerRegion, ViewportImageSize outerViewportImageSize) {
325
 
        return ViewHelper.convertImageToScreenDisplacement(
326
 
                innerRegion.getUpperLeftCorner().subtract(
327
 
                        outerRegion.getUpperLeftCorner()), outerRegion,
328
 
                outerViewportImageSize).negateY();
329
 
    }
330
 
 
331
 
    /** Converts the internal values for different interpolation modes into java rendering hints.
332
 
     * 
333
 
     * @param interpolationMode Interpolation mode to convert
334
 
     * @return equivalent java rendering hint
335
 
     */
336
 
    public static Object ConvertScaleInterpolationModeToRenderingHint(
337
 
            InterpolationMode interpolationMode) {
338
 
        switch(interpolationMode) {
339
 
                case NEAREST_NEIGHBOR:
340
 
                    return RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
341
 
                case BILINEAR:
342
 
                    return RenderingHints.VALUE_INTERPOLATION_BILINEAR;
343
 
                case BICUBIC:
344
 
                    return RenderingHints.VALUE_INTERPOLATION_BICUBIC;
345
 
        }
346
 
        return null;
347
 
    }
348
 
    
349
 
    
350
 
    /** Loads a new image located at the given URI.
351
 
     * 
352
 
     * <p>Depending on the file type, a different implementation of the ImageInfoView
353
 
     * is chosen. If there is no implementation available for the given
354
 
     * type, an exception is thrown.
355
 
     * 
356
 
     * <p>Calls {@link #loadView(URI, boolean)} with the boolean set to true.
357
 
     * 
358
 
     * @param uri URI representing the location of the image
359
 
     * @return ImageInfoView containing the image
360
 
     * @throws IOException if anything went wrong (e.g. type not supported, image not found, etc.)
361
 
     */
362
 
    public static ImageInfoView loadView(URI uri) throws IOException {
363
 
        return loadView(uri, true);
364
 
    }
365
 
 
366
 
    /** Loads a new image located at the given URI.
367
 
     * 
368
 
     * <p>Depending on the file type, a different implementation of the ImageInfoView
369
 
     * is chosen. If there is no implementation available for the given
370
 
     * type, an exception is thrown.
371
 
     * 
372
 
     * @param uri URI representing the location of the image
373
 
     * @param isMainView Whether the view is used as a main view or not
374
 
     * @return ImageInfoView containing the image
375
 
     * @throws IOException if anything went wrong (e.g. type not supported, image not found, etc.)
376
 
     */
377
 
    public static ImageInfoView loadView(URI uri, boolean isMainView) throws IOException {
378
 
        
379
 
        if (uri == null || uri.getScheme() == null || uri.toString() == null)
380
 
            throw new IOException("Invalid URI.");
381
 
        
382
 
        String[] parts = uri.toString().split("\\.");
383
 
        String ending = parts[parts.length - 1];
384
 
        
385
 
        if (ending.equals("jpeg") || ending.equals("jpg")
386
 
                || ending.equals("JPEG") || ending.equals("JPG")
387
 
                || ending.equals("png") || ending.equals("PNG")) {
388
 
 
389
 
            return new JHVSimpleImageView(uri);
390
 
            
391
 
        } else if (ending.equals("fits") || ending.equals("FITS")
392
 
                || ending.equals("fts") || ending.equals("FTS")) {
393
 
            
394
 
            try {
395
 
                return new JHVFITSView(uri);
396
 
            } catch (Exception e) {
397
 
                throw new IOException(e.getMessage());
398
 
            }
399
 
            
400
 
        } else {
401
 
            try {
402
 
                JP2Image jp2Image = new JP2Image(uri);
403
 
                
404
 
                if(jp2Image.isMultiFrame()) {
405
 
                    JHVJPXView jpxView = new JHVJPXView(isMainView);
406
 
                        jpxView.setJP2Image(jp2Image);
407
 
                        return jpxView;
408
 
                } else {
409
 
                        JHVJP2View jp2View = new JHVJP2View(isMainView);
410
 
                    jp2View.setJP2Image(jp2Image);
411
 
                    return jp2View;
412
 
                }
413
 
            } catch (Exception e) {
414
 
                throw new IOException(e.getMessage());
415
 
            }
416
 
        }
417
 
    }
 
155
                SubimageDataView dataView = getViewAdapter(v, SubimageDataView.class);
 
156
 
 
157
                if (dataView == null) {
 
158
                        return null;
 
159
 
 
160
                } else if (dataView.getSubimageData() == null) {
 
161
                        return null;
 
162
                } else if (!c.isInstance(dataView.getSubimageData())) {
 
163
                        return null;
 
164
                } else {
 
165
                        return (T) dataView.getSubimageData();
 
166
                }
 
167
        }
 
168
 
 
169
        /**
 
170
         * Calculates the final size of a given region within the viewport.
 
171
         * 
 
172
         * <p>
 
173
         * The resulting size is smaller or equal to the size of the viewport. It is
 
174
         * equal if and only if the aspect ratio of the region is equal to the
 
175
         * aspect ratio of the viewport. Otherwise, the image size is cropped to
 
176
         * keep the regions aspect ratio and not deform the image.
 
177
         * 
 
178
         * @param v
 
179
         *            viewport, in which the image will be displayed
 
180
         * @param r
 
181
         *            visible region of the image
 
182
         * @return resulting image size of the region within the viewport
 
183
         */
 
184
        public static ViewportImageSize calculateViewportImageSize(Viewport v,
 
185
                        Region r) {
 
186
                if (v == null || r == null) {
 
187
                        return null;
 
188
                }
 
189
 
 
190
                double screenMeterPerPixel;
 
191
                double screenSubImageWidth;
 
192
                double screenSubImageHeight;
 
193
 
 
194
                // fit region of interest into viewport
 
195
                if ((double) v.getWidth() / (double) v.getHeight() > r.getWidth()
 
196
                                / r.getHeight()) {
 
197
                        screenMeterPerPixel = r.getHeight() / v.getHeight();
 
198
                        screenSubImageHeight = v.getHeight();
 
199
                        screenSubImageWidth = r.getWidth() / screenMeterPerPixel;
 
200
                } else {
 
201
                        screenMeterPerPixel = r.getWidth() / v.getWidth();
 
202
                        screenSubImageWidth = v.getWidth();
 
203
                        screenSubImageHeight = r.getHeight() / screenMeterPerPixel;
 
204
                }
 
205
 
 
206
                return StaticViewportImageSize.createAdaptedViewportImageSize(
 
207
                                (int) Math.round(screenSubImageWidth), (int) Math
 
208
                                                .round(screenSubImageHeight));
 
209
        }
 
210
 
 
211
        /**
 
212
         * Calculates the final size of a given region within the viewport.
 
213
         * 
 
214
         * <p>
 
215
         * The resulting size is smaller or equal to the size of the viewport. It is
 
216
         * equal if and only if the aspect ratio of the region is equal to the
 
217
         * aspect ratio of the viewport. Otherwise, the image size is cropped to
 
218
         * keep the regions aspect ratio and not deform the image.
 
219
         * 
 
220
         * <p>
 
221
         * Basically, this function fetches the region and viewport of the given
 
222
         * view and calls {@link #calculateViewportImageSize(Viewport, Region)}.
 
223
         * 
 
224
         * @param v
 
225
         *            View containing the image.
 
226
         * @return resulting image size of the region within the viewport
 
227
         */
 
228
        public static ViewportImageSize calculateViewportImageSize(View v) {
 
229
                RegionView regionView = ViewHelper.getViewAdapter(v, RegionView.class);
 
230
                ViewportView viewportView = ViewHelper.getViewAdapter(v,
 
231
                                ViewportView.class);
 
232
                if (regionView == null || viewportView == null) {
 
233
                        return null;
 
234
                }
 
235
                return calculateViewportImageSize(viewportView.getViewport(),
 
236
                                regionView.getRegion());
 
237
        }
 
238
 
 
239
        /**
 
240
         * Converts a given displacement on the screen to image coordinates.
 
241
         * 
 
242
         * @param screenDisplacement
 
243
         *            Displacement on the screen to convert
 
244
         * @param r
 
245
         *            Region of the image currently visible on the screen
 
246
         * @param v
 
247
         *            ViewportImageSize of the image within the current viewport
 
248
         * @return Displacement in image coordinates
 
249
         */
 
250
        public static Vector2dDouble convertScreenToImageDisplacement(
 
251
                        Vector2dInt screenDisplacement, Region r, ViewportImageSize v) {
 
252
                return convertScreenToImageDisplacement(screenDisplacement.getX(),
 
253
                                screenDisplacement.getY(), r, v);
 
254
        }
 
255
 
 
256
        /**
 
257
         * Converts a given displacement on the screen to image coordinates.
 
258
         * 
 
259
         * @param screenDisplacementX
 
260
         *            X-coordinate of the displacement on the screen to convert
 
261
         * @param screenDisplacementY
 
262
         *            Y-coordinate of the displacement on the screen to convert
 
263
         * @param r
 
264
         *            Region of the image currently visible on the screen
 
265
         * @param v
 
266
         *            ViewportImageSize of the image within the current viewport
 
267
         * @return Displacement in image coordinates
 
268
         */
 
269
        public static Vector2dDouble convertScreenToImageDisplacement(
 
270
                        int screenDisplacementX, int screenDisplacementY, Region r,
 
271
                        ViewportImageSize v) {
 
272
                return new Vector2dDouble(r.getWidth() / ((double) v.getWidth())
 
273
                                * screenDisplacementX, -r.getHeight()
 
274
                                / ((double) v.getHeight()) * screenDisplacementY);
 
275
        }
 
276
 
 
277
        /**
 
278
         * Converts a given displacement on the image to screen coordinates.
 
279
         * 
 
280
         * @param imageDisplacement
 
281
         *            Displacement on the image to convert
 
282
         * @param r
 
283
         *            Region of the image currently visible on the screen
 
284
         * @param v
 
285
         *            ViewportImageSize of the image within the current viewport
 
286
         * @return Displacement in screen coordinates
 
287
         */
 
288
        public static Vector2dInt convertImageToScreenDisplacement(
 
289
                        Vector2dDouble imageDisplacement, Region r, ViewportImageSize v) {
 
290
                return convertImageToScreenDisplacement(imageDisplacement.getX(),
 
291
                                imageDisplacement.getY(), r, v);
 
292
        }
 
293
 
 
294
        /**
 
295
         * Converts a given displacement on the image to screen coordinates.
 
296
         * 
 
297
         * @param imageDisplacementX
 
298
         *            X-coordinate of the displacement on the image to convert
 
299
         * @param imageDisplacementY
 
300
         *            Y-coordinate of the displacement on the image to convert
 
301
         * @param r
 
302
         *            Region of the image currently visible on the screen
 
303
         * @param v
 
304
         *            ViewportImageSize of the image within the current viewport
 
305
         * @return Displacement in screen coordinates
 
306
         */
 
307
        public static Vector2dInt convertImageToScreenDisplacement(
 
308
                        double imageDisplacementX, double imageDisplacementY, Region r,
 
309
                        ViewportImageSize v) {
 
310
                return new Vector2dInt((int) Math.round(imageDisplacementX
 
311
                                / r.getWidth() * v.getWidth()), (int) Math
 
312
                                .round(imageDisplacementY / r.getHeight() * v.getHeight()));
 
313
        }
 
314
 
 
315
        /**
 
316
         * Ensures, that the given region is within the maximal bounds of the image
 
317
         * data.
 
318
         * 
 
319
         * If that is not the case, moves and/or crops the region to the maximal
 
320
         * area given by the meta data.
 
321
         * 
 
322
         * @param r
 
323
         *            Region to move and crop, if necessary
 
324
         * @param m
 
325
         *            Meta data defining the maximal region
 
326
         * @return Region located inside the maximal region
 
327
         */
 
328
        public static Region cropRegionToImage(Region r, MetaData m) {
 
329
                return StaticRegion.createAdaptedRegion(r.getRectangle()
 
330
                                .moveAndCropToOuterRectangle(m.getPhysicalRectangle()));
 
331
        }
 
332
 
 
333
        /**
 
334
         * Ensures, that the given inner region is within the given outer region.
 
335
         * 
 
336
         * If that is not the case, crops the inner region to the outer region.
 
337
         * 
 
338
         * @param innerRegion
 
339
         *            Inner region to crop, if necessary
 
340
         * @param outerRegion
 
341
         *            Outer region, defining the maximal bounds
 
342
         * @return region located inside the outer region
 
343
         */
 
344
        public static Region cropInnerRegionToOuterRegion(Region innerRegion,
 
345
                        Region outerRegion) {
 
346
                return StaticRegion.createAdaptedRegion(innerRegion.getRectangle()
 
347
                                .cropToOuterRectangle(outerRegion.getRectangle()));
 
348
        }
 
349
 
 
350
        /**
 
351
         * Calculates the inner viewport to the corresponding inner region.
 
352
         * 
 
353
         * Given the outer region and the outer viewport image size, this function
 
354
         * calculates the part of the outer viewport image size, that is occupied by
 
355
         * the inner region.
 
356
         * 
 
357
         * @param innerRegion
 
358
         *            inner region, whose inner viewport is requested
 
359
         * @param outerRegion
 
360
         *            outer region, as a reference
 
361
         * @param outerViewportImageSize
 
362
         *            outer viewport image size, as a reference
 
363
         * @return viewport corresponding to the inner region based on the outer
 
364
         *         region and viewport image size
 
365
         * @see #calculateInnerViewportOffset
 
366
         */
 
367
        public static Viewport calculateInnerViewport(Region innerRegion,
 
368
                        Region outerRegion, ViewportImageSize outerViewportImageSize) {
 
369
                double newWidth = outerViewportImageSize.getWidth()
 
370
                                * innerRegion.getWidth() / outerRegion.getWidth();
 
371
                double newHeight = outerViewportImageSize.getHeight()
 
372
                                * innerRegion.getHeight() / outerRegion.getHeight();
 
373
                return StaticViewport.createAdaptedViewport((int) Math.round(newWidth),
 
374
                                (int) Math.round(newHeight));
 
375
        }
 
376
 
 
377
        /**
 
378
         * Calculates the offset of the inner viewport relative to the outer
 
379
         * viewport image size.
 
380
         * 
 
381
         * Given the outer region and viewport image size, calculates the offset of
 
382
         * the inner viewport corresponding to the given inner region.
 
383
         * 
 
384
         * @param innerRegion
 
385
         *            inner region, whose inner viewport offset is requested
 
386
         * @param outerRegion
 
387
         *            outer region, as a reference
 
388
         * @param outerViewportImageSize
 
389
         *            outer viewport image size, as a reference
 
390
         * @return offset of the inner viewport based on the outer region and
 
391
         *         viewport image size
 
392
         * @see #calculateInnerViewport
 
393
         */
 
394
        public static Vector2dInt calculateInnerViewportOffset(Region innerRegion,
 
395
                        Region outerRegion, ViewportImageSize outerViewportImageSize) {
 
396
                return ViewHelper.convertImageToScreenDisplacement(
 
397
                                innerRegion.getUpperLeftCorner().subtract(
 
398
                                                outerRegion.getUpperLeftCorner()), outerRegion,
 
399
                                outerViewportImageSize).negateY();
 
400
        }
 
401
 
 
402
        /**
 
403
         * Converts the internal values for different interpolation modes into java
 
404
         * rendering hints.
 
405
         * 
 
406
         * @param interpolationMode
 
407
         *            Interpolation mode to convert
 
408
         * @return equivalent java rendering hint
 
409
         */
 
410
        public static Object ConvertScaleInterpolationModeToRenderingHint(
 
411
                        InterpolationMode interpolationMode) {
 
412
                switch (interpolationMode) {
 
413
                case NEAREST_NEIGHBOR:
 
414
                        return RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
 
415
                case BILINEAR:
 
416
                        return RenderingHints.VALUE_INTERPOLATION_BILINEAR;
 
417
                case BICUBIC:
 
418
                        return RenderingHints.VALUE_INTERPOLATION_BICUBIC;
 
419
                }
 
420
                return null;
 
421
        }
 
422
 
 
423
        /**
 
424
         * Loads a new image located at the given URI.
 
425
         * 
 
426
         * <p>
 
427
         * Depending on the file type, a different implementation of the
 
428
         * ImageInfoView is chosen. If there is no implementation available for the
 
429
         * given type, an exception is thrown.
 
430
         * 
 
431
         * <p>
 
432
         * Calls {@link #loadView(URI, boolean)} with the boolean set to true.
 
433
         * 
 
434
         * @param uri
 
435
         *            URI representing the location of the image
 
436
         * @return ImageInfoView containing the image
 
437
         * @throws IOException
 
438
         *             if anything went wrong (e.g. type not supported, image not
 
439
         *             found, etc.)
 
440
         */
 
441
        public static ImageInfoView loadView(URI uri) throws IOException {
 
442
                return loadView(uri, true);
 
443
        }
 
444
 
 
445
        /**
 
446
         * Loads a new image located at the given URI.
 
447
         * 
 
448
         * <p>
 
449
         * Depending on the file type, a different implementation of the
 
450
         * ImageInfoView is chosen. If there is no implementation available for the
 
451
         * given type, an exception is thrown.
 
452
         * 
 
453
         * @param uri
 
454
         *            URI representing the location of the image
 
455
         * @param isMainView
 
456
         *            Whether the view is used as a main view or not
 
457
         * @return ImageInfoView containing the image
 
458
         * @throws IOException
 
459
         *             if anything went wrong (e.g. type not supported, image not
 
460
         *             found, etc.)
 
461
         */
 
462
        public static ImageInfoView loadView(URI uri, boolean isMainView)
 
463
                        throws IOException {
 
464
                return loadView(uri, uri, isMainView);
 
465
        }
 
466
 
 
467
        /**
 
468
         * Loads a new image located at the given URI.
 
469
         * 
 
470
         * <p>
 
471
         * Depending on the file type, a different implementation of the
 
472
         * ImageInfoView is chosen. If there is no implementation available for the
 
473
         * given type, an exception is thrown.
 
474
         * 
 
475
         * @param uri
 
476
         *            URI representing the location of the image
 
477
         * @param downloadURI
 
478
         *            URI from which the whole file can be downloaded
 
479
         * 
 
480
         * @return ImageInfoView containing the image
 
481
         * @throws IOException
 
482
         *             if anything went wrong (e.g. type not supported, image not
 
483
         *             found, etc.)
 
484
         */
 
485
        public static ImageInfoView loadView(URI uri, URI downloadURI)
 
486
                        throws IOException {
 
487
                return loadView(uri, downloadURI, true);
 
488
        }
 
489
 
 
490
        /**
 
491
         * Loads a new image located at the given URI.
 
492
         * 
 
493
         * <p>
 
494
         * Depending on the file type, a different implementation of the
 
495
         * ImageInfoView is chosen. If there is no implementation available for the
 
496
         * given type, an exception is thrown.
 
497
         * 
 
498
         * @param uri
 
499
         *            URI representing the location of the image
 
500
         * @param downloadURI
 
501
         *            URI from which the whole file can be downloaded
 
502
         * @param isMainView
 
503
         *            Whether the view is used as a main view or not
 
504
         * @return ImageInfoView containing the image
 
505
         * @throws IOException
 
506
         *             if anything went wrong (e.g. type not supported, image not
 
507
         *             found, etc.)
 
508
         */
 
509
        public static ImageInfoView loadView(URI uri, URI downloadURI,
 
510
                        boolean isMainView) throws IOException {
 
511
                if (uri == null || uri.getScheme() == null || uri.toString() == null)
 
512
                        throw new IOException("Invalid URI.");
 
513
 
 
514
                String[] parts = uri.toString().split("\\.");
 
515
                String ending = parts[parts.length - 1];
 
516
 
 
517
                if (ending.equals("jpeg") || ending.equals("jpg")
 
518
                                || ending.equals("JPEG") || ending.equals("JPG")
 
519
                                || ending.equals("png") || ending.equals("PNG")) {
 
520
 
 
521
                        return new JHVSimpleImageView(uri);
 
522
 
 
523
                } else if (ending.equals("fits") || ending.equals("FITS")
 
524
                                || ending.equals("fts") || ending.equals("FTS")) {
 
525
 
 
526
                        try {
 
527
                                return new JHVFITSView(uri);
 
528
                        } catch (Exception e) {
 
529
                                throw new IOException(e.getMessage());
 
530
                        }
 
531
 
 
532
                } else {
 
533
                        try {
 
534
                                JP2Image jp2Image = new JP2Image(uri, downloadURI);
 
535
 
 
536
                                if (jp2Image.isMultiFrame()) {
 
537
                                        JHVJPXView jpxView = new JHVJPXView(isMainView);
 
538
                                        jpxView.setJP2Image(jp2Image);
 
539
                                        return jpxView;
 
540
                                } else {
 
541
                                        JHVJP2View jp2View = new JHVJP2View(isMainView);
 
542
                                        jp2View.setJP2Image(jp2Image);
 
543
                                        return jp2View;
 
544
                                }
 
545
                        } catch (Exception e) {
 
546
                                throw new IOException(e.getMessage());
 
547
                        }
 
548
                }
 
549
        }
418
550
}