design outline for a limited time::Mutation capability

This commit is contained in:
Fischlurch 2011-04-04 02:07:09 +02:00
parent 9364d717b0
commit 4d6bb3d54c
6 changed files with 181 additions and 3 deletions

49
src/lib/time/mutation.cpp Normal file
View file

@ -0,0 +1,49 @@
/*
Mutation - changing and adjusting time values
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "lib/time/timevalue.hpp"
#include "lib/time/mutation.hpp"
//#include "lib/time.h"
//#include "lib/util.hpp"
//#include <tr1/functional>
//using std::string;
//using util::unConst;
//using util::floorwrap;
namespace lib {
namespace time {
Mutation::~Mutation() { } // emit VTable here....
/** */
}} // lib::time

108
src/lib/time/mutation.hpp Normal file
View file

@ -0,0 +1,108 @@
/*
MUTATION.hpp - changing and adjusting time values
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file mutation.hpp
** Modifying time and timecode values.
** Basically, time values are designed to be immutable. Under some circumstances
** we need a means to change existing time values though. Moreover, actually performing
** these changes gets quite involved at the implementation level, due to time / timecode
** values being \em quantised (grid aligned). To keep this implementation logic separate
** from the simple time values, and to allow for later extensions and more elaborate
** change schemes, we choose the <b>visitor pattern</b> for implementing these
** time mutating operations.
**
** \par usage situations
**
** There are four basic usage situations causing an existing time value to be mutated:
**
** - dragging an object or object boundary (resizing)
** - nudging
** - placing an object (e.g. a clip)
** - update of a timecode display in the GUI
**
** All these include sending a change message to the original time spec, while the
** actual content of the change message determines the concrete behaviour. Especially,
** when the target time to be changed or the message content are quantised, an interference
** between multiple time grids may be happen, possibly resulting in a re-quantisation of
** the message into the target object's own time grid.
**
** @todo WIP-WIP-WIP
**
*/
#ifndef LIB_TIME_MUTATION_H
#define LIB_TIME_MUTATION_H
#include "lib/time/timevalue.hpp"
//#include "lib/symbol.hpp"
#include <boost/noncopyable.hpp>
//#include <iostream>
//#include <boost/operators.hpp>
//#include <string>
namespace lib {
namespace time {
//using std::string;
//using lib::Literal;
class QuTime;
/**
* Interface: an opaque change imposed onto some time value.
*
* @see time::TimeSpan#accept(Mutation const&)
* @todo WIP-WIP-WIP
*/
class Mutation
: boost::noncopyable
{
public:
virtual ~Mutation();
virtual void change (Duration&) const =0;
virtual void change (TimeSpan&) const =0;
virtual void change (QuTime&) const =0;
/* === convenience shortcuts for simple cases === */
static void changeTime (Time);
static void changeDuration (Duration);
static void nudge (int adjustment);
};
/* === defining the visitation responses === */
inline void Duration::accept (Mutation const& muta) { muta.change (*this); }
inline void TimeSpan::accept (Mutation const& muta) { muta.change (*this); }
#ifdef LIB_TIME_TIMEQUQNT_H
inline void QuTime::accept (Mutation const& muta) { muta.change (*this); }
#endif
}} // lib::time
#endif

View file

@ -75,6 +75,10 @@ namespace time {
template<class TC>
void
castInto (TC& timecode) const;
/** receive change message, which
might cause re-quantisation */
void accept (Mutation const&);
};

View file

@ -293,12 +293,14 @@ namespace time {
class TimeSpan;
class Mutation;
/**
* Duration is the internal Lumiera time metric.
* It is an absolute (positive) value, but can be
* promoted from an offset. Like plain TimeValue,
* Duration is an immutable value.
* promoted from an offset. While Duration generally
* is treated as immutable value, there is the
* possibility to send a \em Mutation message.
*/
class Duration
: public Offset
@ -325,6 +327,8 @@ namespace time {
Duration (ulong count, FrameRate const& fps);
static const Duration NIL;
void accept (Mutation const&);
};
@ -392,6 +396,10 @@ namespace time {
return (startPoint + dur_);
}
/** may change start / duration */
void accept (Mutation const&);
/// Supporting extended total order, based on start and interval length
friend bool operator== (TimeSpan const& t1, TimeSpan const& t2) { return t1.t_==t2.t_ && t1.dur_==t2.dur_; }
friend bool operator< (TimeSpan const& t1, TimeSpan const& t2) { return t1.t_< t2.t_ ||

View file

@ -82,11 +82,13 @@ namespace test{
struct TestValues
{
TimeVar var;
Duration dur;
TimeSpan span;
QuTime quant;
TestValues (TimeValue o)
: var(o)
, dur(o)
, span(o, Offset(o))
, quant(o, "test_grid")
{ }

View file

@ -6618,7 +6618,7 @@ Thus no server and no network connection is needed. Simply open the file in your
* see [[Homepage|http://tiddlywiki.com]], [[Wiki-Markup|http://tiddlywiki.org/wiki/TiddlyWiki_Markup]]
</pre>
</div>
<div title="TimeMutation" modifier="Ichthyostega" modified="201104020013" created="201101231344" tags="spec discuss draft" changecount="29">
<div title="TimeMutation" modifier="Ichthyostega" modified="201104040005" created="201101231344" tags="spec discuss draft" changecount="31">
<pre>Simple time points are just like values and thus easy to change. The difficulties arise when time values are to be //quantised to an existing time grid.// The first relevant point to note is that for quantised time values, the effect of a change can be disproportional to the cause. Small changes below the threshold might be accumulated, and a tiny change might trigger a jump to the next grid point. While this might be annoying, the yet more complex questions arise when we acknowledge that the amount of the change itself might be related to a time grid.
The problem with modification of quantised values highlights an inner contradiction or conflicting goals within the design
@ -6665,6 +6665,7 @@ This results in the following combinations to be implemented:
|~|~TimeSpan ||set start |
|~|quantised ||set raw value |
| Duration|~TimeSpan ||set length |
|~|Duration ||set length |
| Offset|Time || -- |
|~|Duration || -- |
|~|~TimeSpan ||adjust start/length |
@ -6687,12 +6688,18 @@ As rationale, consider the following
Rationale: allowing mutations for Time bears the danger of making ~TimeVar obsolete
* //4/11 yes, implementing it now this way....//
* we have ~TimeVar, so the only thing that //needs// to be mutable is a whole object &amp;rArr; ~TimeSpan
* err, because MObject will include a Duration separate from the start time in the Placement, Duration needs to be mutable too
!!!usage considerations
Question is: how fine grained and configurable needs this to be?
* for example, when moving a clip taken from 50fps media, the new position might be quantised to the 50fps grid established by the media, while the target timeline runs with 25fps, allowing for finer adjustments based on the intermediate frames present in the source material.
* likely we need a &quot;nudge by unit(s)&quot;
!!! design draft
The special focus of this problem seems to lead itself to a __visitor pattern__ based implementation. Because the basic hierarchy of applicable types is fixed, but the behaviour is open ended (and not yet fully determined). A conventional implementation would scatter this behaviour over all the time entities, thus making it hard to understand and reason about. The classical ~GoF cyclic visitor solution to the contrary allows us to arrange closely related behaviour into thematically grouped visitor classes. As a plus, the concrete action can be bound dynamically, allowing for more flexibility when it comes to dealing with the intricate situations when a quantised time span (= a clip) recieves a quantised mutation (= is re-alligend to a possibly different frame grid)
Thus the possibly mutalble time entities get an {{{accept(time::Mutation)}}} function, which is defined to reflect back into the (virtual) visitation functions of the Mutation Interface. Additionally, we provide some static convenience shortcuts right in the
Mutation interface, performing the trivial mutations.
</pre>
</div>
<div title="TimeQuant" modifier="Ichthyostega" modified="201101232031" created="201012181753" tags="Concepts Player spec img discuss draft" changecount="50">