Sequencer - Identify overrides where inputs would cause trouble

This commit is contained in:
Emmanuel BENOîT 2017-11-28 10:42:04 +01:00
parent ec34bcc9bb
commit 5080866cbe
3 changed files with 153 additions and 34 deletions

View file

@ -254,6 +254,40 @@ float T_SyncCurve::computeValue(
return it->computeValue( timeUnits - prevSegStart ); return it->computeValue( timeUnits - prevSegStart );
} }
E_SyncCurveMatch T_SyncCurve::matches(
T_SyncCurve const& other ) const noexcept
{
const auto tSegs{ this->segments.size( ) };
const auto oSegs{ other.segments.size( ) };
const auto nSegs{ std::min( tSegs , oSegs ) };
for ( auto i = 0u ; i < nSegs ; i ++ ) {
auto const& tDur{ this->segments[ i ].durations };
auto const& oDur{ other.segments[ i ].durations };
const bool lastSeg{ i == nSegs - 1 };
if ( !lastSeg && tDur.size( ) != oDur.size( ) ) {
return E_SyncCurveMatch::MISMATCH;
}
const auto nd{ std::min( tDur.size( ) , oDur.size( ) ) };
for ( auto j = 0u ; j < nd ; j ++ ) {
if ( tDur[ j ] != oDur[ j ] ) {
return E_SyncCurveMatch::MISMATCH;
}
}
if ( tDur.size( ) != oDur.size( ) ) {
return tDur.size( ) < oDur.size( )
? E_SyncCurveMatch::LASTSEG_SHORT
: E_SyncCurveMatch::LASTSEG_LONG;
}
}
if ( tSegs == oSegs ) {
return E_SyncCurveMatch::IDENTICAL;
}
return tSegs < oSegs
? E_SyncCurveMatch::MATCHING_SHORT
: E_SyncCurveMatch::MATCHING_LONG;
}
/*= T_SyncCurves =============================================================*/ /*= T_SyncCurves =============================================================*/

View file

@ -51,6 +51,34 @@ struct T_SyncSegment
}; };
M_LSHIFT_OP( T_StringBuilder , T_SyncSegment::E_SegmentType ); M_LSHIFT_OP( T_StringBuilder , T_SyncSegment::E_SegmentType );
/*----------------------------------------------------------------------------*/
// Possible results when trying to check whether two curves have a similar
// structure.
enum class E_SyncCurveMatch
{
// Both curves have the same structure.
IDENTICAL ,
// One of the curves has less information than the other, but the
// information in the shortest curve matches the corresponding
// information in the longest curve (i.e. it is only missing
// segments). _SHORT/_LONG indicate that the curve for which the
// comparison method was called is the shortest/longest (resp.)
MATCHING_SHORT ,
MATCHING_LONG ,
// One of the curves has less information than the other, and its
// last segment is shorter than the corresponding segment in the
// longest record (but its end matches a point in the longest curve's
// segment).
LASTSEG_SHORT ,
LASTSEG_LONG ,
// The curves do not match.
MISMATCH
};
// An input curve // An input curve
struct T_SyncCurve struct T_SyncCurve
{ {
@ -69,8 +97,14 @@ struct T_SyncCurve
// Compute the value at the specified time. // Compute the value at the specified time.
float computeValue( float timeUnits ) const noexcept; float computeValue( float timeUnits ) const noexcept;
// Compare this curve to another.
E_SyncCurveMatch matches(
T_SyncCurve const& other ) const noexcept;
}; };
/*----------------------------------------------------------------------------*/
// All configured curves. Some may not actually correspond to an input and may // All configured curves. Some may not actually correspond to an input and may
// have been defined for inputs that have been removed temporarily (e.g. // have been defined for inputs that have been removed temporarily (e.g.
// because some include was commented out), in which case we don't want to // because some include was commented out), in which case we don't want to

View file

@ -259,6 +259,7 @@ struct T_SyncViewImpl_
void displayInputSelector( ) noexcept; void displayInputSelector( ) noexcept;
void displayOverrideSelector( ) noexcept; void displayOverrideSelector( ) noexcept;
// Selection display/edition windows
void displayTrackWindow( ) noexcept; void displayTrackWindow( ) noexcept;
void displaySegmentWindow( ) noexcept; void displaySegmentWindow( ) noexcept;
void displayPointWindow( ) noexcept; void displayPointWindow( ) noexcept;
@ -1321,6 +1322,24 @@ void T_SyncViewImpl_::displayOverrideSelector( ) noexcept
{ {
using namespace ImGui; using namespace ImGui;
/*
* An override can be selected directly if the inputs that are part of
* it are consistent.
*
* A pair of inputs are consistent if
* - one or both inputs do not have curve information attached;
* - the durations and segment boundaries of the shortest curve
* attached to the inputs match the boundaries and durations from the
* other input's curve OR the last segment is shorter but its end
* matches the location of one of the points in the corresponding
* segment of the other curve.
*
* If the inputs are not consistent, it will be necessary to reset
* some of their curves; best option would be to try and be clever, but
* a temporary measure (resetting all curves to match the structure of
* the first longest curve) would work.
*/
BeginChild( "content" ); BeginChild( "content" );
Common::Sync( ).visitOverrides( [&]( T_SyncOverrideVisitor::T_Element element , const bool exit ) { Common::Sync( ).visitOverrides( [&]( T_SyncOverrideVisitor::T_Element element , const bool exit ) {
if ( element.hasType< T_SyncOverrideSection* >( ) ) { if ( element.hasType< T_SyncOverrideSection* >( ) ) {
@ -1330,47 +1349,79 @@ void T_SyncViewImpl_::displayOverrideSelector( ) noexcept
} }
if ( exit ) { if ( exit ) {
TreePop( ); TreePop( );
} else { return true;
return TreeNodeEx( &sos.cTitle[ 0 ] ,
ImGuiTreeNodeFlags_DefaultOpen );
} }
} else if ( exit ) { return TreeNodeEx( &sos.cTitle[ 0 ] ,
auto const& ov{ *element.value< A_SyncOverride* >( ) }; ImGuiTreeNodeFlags_DefaultOpen );
auto const& id{ ov.id( ) }; }
auto const& in{ ov.inputNames( ) }; if ( ! exit ) {
const bool present{ sOverrides.contains( id ) }; return false;
const bool hasCurves{ !present && [&](){ }
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
if ( sCurves.contains( in[ i ] ) ) {
return true;
}
}
return false;
}() };
if ( hasCurves ) { auto const& ov{ *element.value< A_SyncOverride* >( ) };
PushDisabled( ); auto const& id{ ov.id( ) };
} auto const& in{ ov.inputNames( ) };
const bool present{ sOverrides.contains( id ) };
bool select{ present }; const bool hasCurves{ !present && [&](){
if ( Checkbox( ov.title( ) , &select ) ) { for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
if ( select ) { if ( sCurves.contains( in[ i ] ) ) {
sOverrides.add( id ); return true;
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
sCurves.add( in[ i ] , true );
}
} else {
sOverrides.remove( id );
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
sCurves.remove( in[ i ] );
}
} }
} }
return false;
}() };
if ( hasCurves ) { // FIXME MOVE THIS \/ //
PopDisabled( ); bool bad{ false };
for ( auto i = 0u ; i < in.size( ) - 1 && !bad ; i ++ ) {
T_SyncCurve const* const c0{
Common::Sync( ).getCurve( in[ i ] )
};
if ( !c0 ) {
continue;
}
for ( auto j = i + 1 ; j < in.size( ) && !bad ; j ++ ) {
T_SyncCurve const* const c1{
Common::Sync( ).getCurve( in[ j ] )
};
if ( !c1 ) {
continue;
}
const auto res{ c0->matches( *c1 ) };
bad = ( res == E_SyncCurveMatch::MISMATCH );
} }
} }
// FIXME MOVE THIS /\ //
if ( hasCurves ) {
PushDisabled( );
}
if ( bad ) {
PushStyleColor( ImGuiCol_Text , 0xff0000ff );
}
bool select{ present };
if ( Checkbox( ov.title( ) , &select ) ) {
if ( select ) {
sOverrides.add( id );
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
sCurves.add( in[ i ] , true );
}
} else {
sOverrides.remove( id );
for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
sCurves.remove( in[ i ] );
}
}
}
if ( bad ) {
PopStyleColor( );
}
if ( hasCurves ) {
PopDisabled( );
}
return true; return true;
} ); } );
EndChild( ); EndChild( );