Mercurial > projects > doodle
comparison doodle/tk/screen_model.d @ 81:d92b9f04b1e8
Bed time
author | "David Bryant <bagnose@gmail.com>" |
---|---|
date | Mon, 16 Aug 2010 00:04:27 +0930 |
parents | doodle/tk/pixel_model.d@535bae7a7305 |
children | 100dd23c7bdf |
comparison
equal
deleted
inserted
replaced
80:b759414d2b72 | 81:d92b9f04b1e8 |
---|---|
1 module doodle.tk.screen_model; | |
2 | |
3 public { | |
4 import doodle.tk.geometry; | |
5 } | |
6 | |
7 private { | |
8 import doodle.core.misc; | |
9 } | |
10 | |
11 // This class manages the relationship between screen space and model space. | |
12 // Screen is defined as the current window/viewport into the model | |
13 // It provides convenient high-level operations. | |
14 // | |
15 // x and y run right and up respectively for screen and model space | |
16 | |
17 class ScreenModel { | |
18 this(in double zoom, in Rectangle canvasBoundsModel, in Rectangle viewBoundsScreen) { | |
19 _zoom = zoom; | |
20 _viewBoundsScreen = viewBoundsScreen; | |
21 _canvasBoundsModel = canvasBoundsModel; | |
22 | |
23 // Choose the centre of the canvas as the centre of the view | |
24 _viewCentreModel = _canvasBoundsModel.centre; | |
25 } | |
26 | |
27 void consolidateCanvasBounds(in Rectangle requiredCanvasBounds) { _canvasBoundsModel = screenToModel(_viewBoundsScreen) | requiredCanvasBounds; } | |
28 void canvasAccommodate(in Rectangle bounds) { _canvasBoundsModel = _canvasBoundsModel | bounds; } | |
29 | |
30 void zoomRelative(in double factor, in Point screenDatum) { | |
31 // Work out screen distance from current centre to datum, | |
32 // Do the zoom, then work out the new centre that keeps the | |
33 // screen distance the same | |
34 | |
35 Point oldModelDatum = screenToModel(screenDatum); | |
36 Vector screenDistance = modelToScreen(oldModelDatum - _viewCentreModel); | |
37 _zoom = clampZoom(zoom * factor); | |
38 _viewCentreModel = oldModelDatum - screenToModel(screenDistance); | |
39 } | |
40 | |
41 void panRelativeScreen(in Vector screenDisplacement) { _viewCentreModel = _viewCentreModel + screenToModel(screenDisplacement); } | |
42 void panRelativeModel(in Vector modelDisplacement) { _viewCentreModel = _viewCentreModel + modelDisplacement; } | |
43 | |
44 // For userZoom 1.0 -> 100% means the presentation on the screen is one-to-one with real-life | |
45 double userZoom(in double pixelsPerMillimetre) const { return _zoom / pixelsPerMillimetre; } | |
46 double zoom() const { return _zoom; } | |
47 Rectangle viewBoundsScreen() const { return _viewBoundsScreen; } | |
48 Rectangle viewBoundsModel() const { return screenToModel(_viewBoundsScreen); } | |
49 Rectangle canvasBoundsModel() const { return _canvasBoundsModel; } | |
50 Rectangle canvasBoundsScreen() const { return modelToScreen(_canvasBoundsModel); } | |
51 | |
52 Point modelToScreen(in Point model) const { return _viewBoundsScreen.centre + _zoom * (model - _viewCentreModel); } | |
53 Point screenToModel(in Point screen) const { return _viewCentreModel + (screen - _viewBoundsScreen.centre) / _zoom; } | |
54 Vector modelToScreen(in Vector model) const { return _zoom * model; } | |
55 Vector screenToModel(in Vector screen) const { return screen / _zoom; } | |
56 Rectangle modelToScreen(in Rectangle model) const { return Rectangle(modelToScreen(model.position), modelToScreen(model.size)); } | |
57 Rectangle screenToModel(in Rectangle model) const { return Rectangle(screenToModel(model.position), screenToModel(model.size)); } | |
58 | |
59 private { | |
60 static double clampZoom(in double zoom) { return clamp(zoom, 1e-1, 1e2); } | |
61 | |
62 // Screen units are pixels | |
63 // Model units are millimetres | |
64 double _zoom; // pixels-per-millimetre | |
65 Rectangle _viewBoundsScreen; // bounds of the viewport in screen space | |
66 Point _viewCentreModel; // where in the model is the centre of our screen | |
67 Rectangle _canvasBoundsModel; // the bounds of the canvas in model space | |
68 } | |
69 } |