Physics
Size: 5055
Comment:
|
← Revision 31 as of 2012-06-14 19:28:34 ⇥
Size: 5759
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 1: | Line 1: |
Library: uTouch-Physics<<BR>> Language: C API, implementation TBD (C or C++ depending on what is acceptable for upstream dependencies in GTK+)<<BR>> Dependencies: [[http://opende.sourceforge.net/wiki/index.php/Main_Page|ODE]] or [[http://code.google.com/p/chipmunk-physics/|Chipmunk]], [[http://launchpad.net/utouch-geis|Geis]] |
Library: Physics<<BR>> Language: C (Maybe built on top of GLib? Qt already depends on GLib by default if available.)<<BR>> Dependencies: possibly a physics engine such as [[http://code.google.com/p/chipmunk-physics/|Chipmunk]] |
Line 7: | Line 7: |
== Units == Screen coordinates make more sense than real-world coordinates. If you have a 30" monitor next to a 24" monitor, both with equal resolutions, scrolling should move the content the same amount in screen coordinates. To facilitate this, units of pixels are used for distance in internal physics calculations. When real-world units are used, the library will convert them to pixels internally before performing computation. |
== Quick overview == |
Line 10: | Line 9: |
A 24" 1080p monitor is a typical size and resolution for a desktop computer. This works out to 3614 px/m in the diagonal direction. We will assume square pixels. Thus, a reasonable conversion from meters to pixels is about 3.5 MP/m (where MP is a mega-pixel, or 1000 pixels). | This provides a scrollable view. The content is a rectangle, and the viewport is a rectangle whose area is a subset of the content. The content and viewport can be thought of as boxes. The viewport may be dragged within the content. |
Line 12: | Line 11: |
== Models == === Scrollview === This model may be used to facilitate calculations involving a scrollable view. The content is a rectangle, and the viewport is a rectangle whose area is a subset of the content. The content and viewport can be thought of as boxes. The viewport may be dragged within the content. The viewport cannot be dragged outside of the content. |
While the user is interacting with the viewport by scrolling on an input device, the viewport follows the scroll motion. When the scrolling ceases, the viewport will continue moving. As it moves, friction will slow it down until it finally stops. |
Line 16: | Line 13: |
While the user is interacting with the viewport by scrolling on an input device, the viewport follows the scroll motion. When the scrolling ceases, the viewport will continue moving with the velocity it has until friction or the content boundary force the viewport to a stop. | When the viewport hits the edge of the area, something happens. By default all motion of the viewport is stopped. The library may provide alternative behaviour, such as "bouncing", sliding along the edge and so on. |
Line 18: | Line 15: |
TODO: How can we add "bouncing" when the viewport hits the edge of the content area? | == User stories == |
Line 20: | Line 17: |
== API Types == === uphys === Handle for uTouch-Physics context. |
The physics library should do following: |
Line 24: | Line 19: |
=== uphys_units === Enum specifying a unit type. |
* provide a viewport that can be scrolled and which slows down according to physical laws * provide several different behaviours when the area hits the edge: stopping, bouncing like Android's list widget etc * support setting friction and other such variables * provide (possibly system global) default values for the above * allow changing the scrolling speed and direction even if there is a scroll event ongoing * the physical simulation is not tied to the system clock * the source of motion can be a touch gesture, mouse flick, accelerometer, or any other device capable of providing velocity information |
Line 27: | Line 27: |
Values: * UPHYS_MILLIMETER * UPHYS_PIXEL |
Functionality it will not have: |
Line 31: | Line 29: |
=== uphys_point === Holds a point in two axes. |
* it does not convert coordinate types (e.g. from touchpad device coordinates to pixels), it will only work in pixel units * it does not support on-the-fly area or viewport resizing while preserving motion, resizes reset all existing state * it is not thread-safe |
Line 34: | Line 33: |
=== uphys_size === Holds dimensions in two axes of an object. |
== API objects == |
Line 37: | Line 35: |
== uphys Properties == === error: int === Error code from last function call. |
=== PhysicsScroller === |
Line 41: | Line 37: |
Set to 0 on success. | An opaque type for the scroller area. |
Line 43: | Line 39: |
=== error_string: const char * === Error string from last function call. |
== API Functions == |
Line 46: | Line 41: |
Set to "no error" on success. | |
Line 48: | Line 42: |
=== gravity: float === Defaults to 34.3 MP/s^2^. This is calculated by multiplying the standard earth gravity of 9.8 m/s^2^ by the standard conversion from meters to pixels of 3.5 MP/m. |
=== physics_scroller_new === |
Line 51: | Line 44: |
=== mm_multiplier: float === Scalar multiplier applied to parameters given in UPHYS_MILLIMETER units. Defaults to value read from dconf settings repository if available, and then to ''TBD''. |
{{{ PhysicsScroller physics_scroller_new( int area_width, int area_height, int viewport_width, int viewport_height) }}} |
Line 54: | Line 52: |
This is roughly equivalent to the sensitivity of a trackpad. | Creates a new scroller with the given dimensions. Returns {{{NULL}}} on failure, such as having a viewport that is larger than the viewable area. |
Line 56: | Line 54: |
=== mu: float === Friction constant. Defaults to value read from dconf settings repository if available, and then to ''TBD''. |
|
Line 59: | Line 55: |
=== (scrollview) viewport_origin: uphys_point === The origin point of the viewport of the scrollview. |
=== physics_scroller_delete === |
Line 62: | Line 57: |
The origin is defined as the point within the rectangle with the minimum values for both axes. | {{{ void physics_scroller_delete(PhysicsScroller scroller); }}} |
Line 64: | Line 61: |
=== (scrollview) viewport_size: uphys_size === The size of the viewport of the scrollview. |
Deletes a scroller. |
Line 67: | Line 63: |
=== (scrollview) content_origin: uphys_point === The origin point of the content of the scrollview. |
|
Line 70: | Line 64: |
The origin is defined as the point within the rectangle with the minimum values for both axes. | === physics_scroller_reset === |
Line 72: | Line 66: |
=== (scrollview) content_size: uphys_size === The size of the content of the scrollview. |
{{{ int PHYSICS_API physics_scroller_reset(PhysicsScroller scroller, int area_width, int area_height, int viewport_width, int viewport_height); }}} |
Line 75: | Line 74: |
== Functions == === int uphys_set_property(uphys *uphys, const char *name, void *value) === Set a property value. |
Resets the scroller with the new given dimensions. If dimensions are invalid, the state of the object is not changed. If they are valid, all old state is permanently destroyed. Using this is equivalent to deleting the old scroller and creating a new one with the given arguments. |
Line 79: | Line 76: |
Returns 0 if successful, non-zero on error. | === scroller_get_viewport_location === |
Line 81: | Line 78: |
=== int uphys_get_property(const uphys *uphys, const char *name, void *value) === Get a property value. |
{{{ void physics_scroller_get_viewport_location(PhysicsScroller scroller, int *x, int *y); }}} |
Line 84: | Line 82: |
Returns 0 if successful, non-zero on error. | Get the location of the top left corner of the viewport. |
Line 86: | Line 84: |
=== void uphys_inject(uphys *uphys, GeisEvent event) === Inject an input event. |
=== set_scroller_set_viewport_location === |
Line 89: | Line 86: |
An error will occur if the time of the event is earlier than the time of a previous uphys_update() call. | {{{ void physics_scroller_set_viewport_location(PhysicsScroller scroller, int x, int y, int clamp_to_area); }}} |
Line 91: | Line 90: |
=== void uphys_update(uphys *uphys, time_t *time) === Perform simulation of model up to the time given. |
Move viewport's top left corner to the desired location. If {{{clamp_to_area}}} is nonzero ({{{true}}}), the viewport is moved so it is wholly inside the area. If it is zero ({{{false}}}), the behaviour depends on edge behaviour type in a as-yet-unspecified manner. For example, the scroller may move the viewport inside the area with a smooth transition. |
Line 94: | Line 92: |
=== uphys *uphys_new_scrollview() === Create a new uphys context for a scrollable viewport. |
=== scroller_set_velocity === |
Line 97: | Line 94: |
Returns a new context or NULL on error. | {{{ void physics_scroller_set_velocity(PhysicsScroller scroller, int dx_pixels_per_second, int dy_pixels_per_second); }}} |
Line 99: | Line 100: |
== API Use Case Example == Implementing smooth scrolling in a document viewer. |
Sets the scroller's instantaneous velocity. Causes the area to start moving to the specified direction once time is advanced. |
Line 102: | Line 102: |
Setup steps: 1. Create a uphys context using uphys_new_scrollview() 2. Set properties on the context for the origin and size of the content and viewport 3. Create a Geis context to receive drag events 4. Add a callback for uphys on the display refresh signal - Use OpenGL sync signal if available<<BR>> - Otherwise use a static timer at a reasonable interval (maybe 30 Hz) |
=== physics_scroller_advance === |
Line 110: | Line 104: |
In Geis drag callbacks: 1. Call uphys_inject(). - For touchpads and independent devices use UPHYS_MILLIMETER units<<BR>> - For touchscreens use UPHYS_PIXEL units |
{{{ int physics_scroller_advance(PhysicsScroller scroller, unsigned long time_in_millis); }}} |
Line 115: | Line 108: |
In the uphys callback: 1. Call uphys_update() with the current time 2. Get the new viewport origin using uphys_get_property() 3. Redraw the scrollview |
Causes the scroller to simulate motion forward in time for the specified time. Returns 0 if the scroller has come to a stop (and thus further calls to this function would not do anything) and a nonzero value if the viewport is still in motion. The advance time can be any positive value. It can be 1 millisecond, it can be 10 000 years. It can be different on every call. The scroller takes care of numerical stability issues. == Using the library == '''Note''': the code samples in this section are descriptive, not normative. === Starting scroll motion === A user flicks on the view. This generates a flick event which gets sent to the application. It sets up the scroller with a call such as this. {{{ physics_scroller_set_velocity(scroller, to_pixels(flick_event->x_speed), to_pixels(flick_event->y_speed)); }}} === Updating the scroll === The update is modeled after {{{glib}}}'s {{{g_timeout_add}}} functionality. The scroller is told to advance forward some amount of time. It calculates its new location and returns false if the viewport has stopped and true if motion is still ongoing. A periodically called update function would usually do something like this. {{{ long now_time = get_time(); long delta_t = now_time - previous_time; bool motion_remaining; motion_remaining = physics_scroller_advance(scroller, delta_t); previous_time = now_time; redraw_canvas_and_other_such_things(); if(motion_remaining) more_to_come(); else motion_has_finished(); }}} |
Library: Physics
Language: C (Maybe built on top of GLib? Qt already depends on GLib by default if available.)
Dependencies: possibly a physics engine such as Chipmunk
Quick overview
This provides a scrollable view. The content is a rectangle, and the viewport is a rectangle whose area is a subset of the content. The content and viewport can be thought of as boxes. The viewport may be dragged within the content.
While the user is interacting with the viewport by scrolling on an input device, the viewport follows the scroll motion. When the scrolling ceases, the viewport will continue moving. As it moves, friction will slow it down until it finally stops.
When the viewport hits the edge of the area, something happens. By default all motion of the viewport is stopped. The library may provide alternative behaviour, such as "bouncing", sliding along the edge and so on.
User stories
The physics library should do following:
- provide a viewport that can be scrolled and which slows down according to physical laws
- provide several different behaviours when the area hits the edge: stopping, bouncing like Android's list widget etc
- support setting friction and other such variables
- provide (possibly system global) default values for the above
- allow changing the scrolling speed and direction even if there is a scroll event ongoing
- the physical simulation is not tied to the system clock
- the source of motion can be a touch gesture, mouse flick, accelerometer, or any other device capable of providing velocity information
Functionality it will not have:
- it does not convert coordinate types (e.g. from touchpad device coordinates to pixels), it will only work in pixel units
- it does not support on-the-fly area or viewport resizing while preserving motion, resizes reset all existing state
- it is not thread-safe
API objects
PhysicsScroller
An opaque type for the scroller area.
API Functions
physics_scroller_new
PhysicsScroller physics_scroller_new( int area_width, int area_height, int viewport_width, int viewport_height)
Creates a new scroller with the given dimensions. Returns NULL on failure, such as having a viewport that is larger than the viewable area.
physics_scroller_delete
void physics_scroller_delete(PhysicsScroller scroller);
Deletes a scroller.
physics_scroller_reset
int PHYSICS_API physics_scroller_reset(PhysicsScroller scroller, int area_width, int area_height, int viewport_width, int viewport_height);
Resets the scroller with the new given dimensions. If dimensions are invalid, the state of the object is not changed. If they are valid, all old state is permanently destroyed. Using this is equivalent to deleting the old scroller and creating a new one with the given arguments.
scroller_get_viewport_location
void physics_scroller_get_viewport_location(PhysicsScroller scroller, int *x, int *y);
Get the location of the top left corner of the viewport.
set_scroller_set_viewport_location
void physics_scroller_set_viewport_location(PhysicsScroller scroller, int x, int y, int clamp_to_area);
Move viewport's top left corner to the desired location. If clamp_to_area is nonzero (true), the viewport is moved so it is wholly inside the area. If it is zero (false), the behaviour depends on edge behaviour type in a as-yet-unspecified manner. For example, the scroller may move the viewport inside the area with a smooth transition.
scroller_set_velocity
void physics_scroller_set_velocity(PhysicsScroller scroller, int dx_pixels_per_second, int dy_pixels_per_second);
Sets the scroller's instantaneous velocity. Causes the area to start moving to the specified direction once time is advanced.
physics_scroller_advance
int physics_scroller_advance(PhysicsScroller scroller, unsigned long time_in_millis);
Causes the scroller to simulate motion forward in time for the specified time. Returns 0 if the scroller has come to a stop (and thus further calls to this function would not do anything) and a nonzero value if the viewport is still in motion.
The advance time can be any positive value. It can be 1 millisecond, it can be 10 000 years. It can be different on every call. The scroller takes care of numerical stability issues.
Using the library
Note: the code samples in this section are descriptive, not normative.
Starting scroll motion
A user flicks on the view. This generates a flick event which gets sent to the application. It sets up the scroller with a call such as this.
physics_scroller_set_velocity(scroller, to_pixels(flick_event->x_speed), to_pixels(flick_event->y_speed));
Updating the scroll
The update is modeled after glib's g_timeout_add functionality. The scroller is told to advance forward some amount of time. It calculates its new location and returns false if the viewport has stopped and true if motion is still ongoing.
A periodically called update function would usually do something like this.
long now_time = get_time(); long delta_t = now_time - previous_time; bool motion_remaining; motion_remaining = physics_scroller_advance(scroller, delta_t); previous_time = now_time; redraw_canvas_and_other_such_things(); if(motion_remaining) more_to_come(); else motion_has_finished();
Multitouch/Physics (last edited 2012-06-14 19:28:34 by c-67-170-185-42)