Skip to content

Commit d45cae8

Browse files
authored
Merge pull request #4260 from rism-digital/develop-expand-doc
Add option to generate expansion from measure repeats
2 parents f6c8bff + 0458be2 commit d45cae8

File tree

5 files changed

+154
-2
lines changed

5 files changed

+154
-2
lines changed

include/vrv/expansionmap.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
namespace vrv {
1919

20+
class Score;
21+
class Section;
22+
2023
class ExpansionMap {
2124

2225
public:
@@ -52,6 +55,25 @@ class ExpansionMap {
5255
*/
5356
void ToJson(std::string &output);
5457

58+
/**
59+
* Generate an expan for the score analysing the repeats and endings
60+
*/
61+
void GenerateExpansionFor(Score *score);
62+
63+
//----------------//
64+
// Static methods //
65+
//----------------//
66+
67+
/**
68+
* @name Methods to check if a measure yields a repeat start or end
69+
*/
70+
///@{
71+
static bool IsRepeatStart(Measure *measure);
72+
static bool IsRepeatEnd(Measure *measure);
73+
static bool IsNextRepeatStart(Measure *measure);
74+
static bool IsPreviousRepeatEnd(Measure *measure);
75+
///@}
76+
5577
private:
5678
bool UpdateIDs(Object *object);
5779

@@ -62,6 +84,9 @@ class ExpansionMap {
6284
/** Ads an id string to an original/notated id */
6385
bool AddExpandedIDToExpansionMap(const std::string &origXmlId, std::string newXmlId);
6486

87+
std::string CreateSection(
88+
Section *section, const ListOfObjects::iterator &first, const ListOfObjects::iterator &last);
89+
6590
public:
6691
/** The expansion map indicates which xmlId has been repeated (expanded) elsewhere */
6792
std::map<std::string, std::vector<std::string>> m_map;

include/vrv/options.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,8 +631,6 @@ class Options {
631631
OptionBool m_condenseNotLastSystem;
632632
OptionBool m_condenseTempoPages;
633633
OptionBool m_evenNoteSpacing;
634-
OptionString m_expand;
635-
OptionBool m_expandFirst;
636634
OptionIntMap m_footer;
637635
OptionIntMap m_header;
638636
OptionBool m_humType;
@@ -774,6 +772,9 @@ class Options {
774772

775773
OptionArray m_appXPathQuery;
776774
OptionArray m_choiceXPathQuery;
775+
OptionString m_expand;
776+
OptionBool m_expandFirst;
777+
OptionBool m_expandGenerate;
777778
OptionBool m_loadSelectedMdivOnly;
778779
OptionBool m_mdivAll;
779780
OptionString m_mdivXPathQuery;

src/doc.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,6 +1609,19 @@ void Doc::ExpandExpansions()
16091609
// Upon MEI import: use expansion ID or boolean for first expansion, given by command line argument
16101610
std::string expansionId = this->GetOptions()->m_expand.GetValue();
16111611
bool expandFirst = this->GetOptions()->m_expandFirst.GetValue();
1612+
1613+
if (this->GetOptions()->m_expandGenerate.GetValue()) {
1614+
ExpansionMap expansionMap;
1615+
ListOfObjects scores = this->FindAllDescendantsByType(SCORE);
1616+
for (Object *object : scores) {
1617+
Score *score = vrv_cast<Score *>(object);
1618+
assert(score);
1619+
expansionMap.GenerateExpansionFor(score);
1620+
}
1621+
// Enable expansion of first one when generated
1622+
expandFirst = true;
1623+
}
1624+
16121625
if (expansionId.empty() && !expandFirst) return;
16131626

16141627
Expansion *startExpansion = NULL;

src/expansionmap.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
#include "expansion.h"
2020
#include "lem.h"
2121
#include "linkinginterface.h"
22+
#include "measure.h"
2223
#include "plistinterface.h"
2324
#include "rdg.h"
25+
#include "score.h"
2426
#include "section.h"
2527
#include "timeinterface.h"
2628
#include "vrv.h"
@@ -362,4 +364,111 @@ void ExpansionMap::ToJson(std::string &output)
362364
output = expansionmap.json();
363365
}
364366

367+
void ExpansionMap::GenerateExpansionFor(Score *score)
368+
{
369+
if (score->FindDescendantByType(EXPANSION)) {
370+
LogWarning("An expansion cannot be generated if one is already encoded");
371+
return;
372+
}
373+
374+
if (score->HasEditorialContent()) {
375+
LogWarning("An expansion cannot be generated with editorial content");
376+
return;
377+
}
378+
379+
if (score->FindAllDescendantsByType(SECTION).size() > 1) {
380+
LogWarning("An expansion cannot be generated with more than one section");
381+
return;
382+
}
383+
384+
Section *section = vrv_cast<Section *>(score->FindDescendantByType(SECTION, 1));
385+
assert(section);
386+
387+
ArrayOfObjects childrenArray = section->GetChildrenForModification();
388+
ListOfObjects children(childrenArray.begin(), childrenArray.end());
389+
390+
Expansion *expansion = new Expansion();
391+
section->InsertChild(expansion, 0);
392+
393+
ListOfObjects::iterator first = children.begin();
394+
ListOfObjects::iterator last = children.begin();
395+
396+
bool isStartFromPrevious = false;
397+
398+
for (auto current = children.begin(); current != children.end(); current++) {
399+
if ((*current)->Is(MEASURE)) {
400+
Measure *measure = vrv_cast<Measure *>(*current);
401+
// The current measure has a repeat end on its left
402+
if (ExpansionMap::IsPreviousRepeatEnd(measure)) {
403+
std::string ref = "#" + this->CreateSection(section, first, last);
404+
expansion->GetPlistInterface()->AddRefAllowDuplicate(ref);
405+
expansion->GetPlistInterface()->AddRefAllowDuplicate(ref);
406+
}
407+
if (isStartFromPrevious || ExpansionMap::IsRepeatStart(measure)) {
408+
first = current;
409+
}
410+
// The current measure has a repeat start on its right
411+
isStartFromPrevious = ExpansionMap::IsNextRepeatStart(measure);
412+
last = current;
413+
if (ExpansionMap::IsRepeatEnd(measure)) {
414+
std::string ref = "#" + this->CreateSection(section, first, last);
415+
expansion->GetPlistInterface()->AddRefAllowDuplicate(ref);
416+
expansion->GetPlistInterface()->AddRefAllowDuplicate(ref);
417+
}
418+
}
419+
}
420+
}
421+
422+
std::string ExpansionMap::CreateSection(
423+
Section *section, const ListOfObjects::iterator &first, const ListOfObjects::iterator &last)
424+
{
425+
Section *subSection = new Section();
426+
section->InsertBefore(*first, subSection);
427+
for (auto sectionCurrent = first; sectionCurrent != std::next(last); sectionCurrent++) {
428+
section->DetachChild((*sectionCurrent)->GetIdx());
429+
subSection->AddChild(*sectionCurrent);
430+
}
431+
return subSection->GetID();
432+
}
433+
434+
//----------------------------------------------------------------------------
435+
// Static methods
436+
//----------------------------------------------------------------------------
437+
438+
bool ExpansionMap::IsRepeatStart(Measure *measure)
439+
{
440+
static const std::vector<data_BARRENDITION> match{ BARRENDITION_rptboth, BARRENDITION_rptstart };
441+
442+
if (!measure->HasLeft()) return false;
443+
444+
return (std::find(match.begin(), match.end(), measure->GetLeft()) != match.end());
445+
}
446+
447+
bool ExpansionMap::IsRepeatEnd(Measure *measure)
448+
{
449+
static const std::vector<data_BARRENDITION> match{ BARRENDITION_rptboth, BARRENDITION_rptend };
450+
451+
if (!measure->HasRight()) return false;
452+
453+
return (std::find(match.begin(), match.end(), measure->GetRight()) != match.end());
454+
}
455+
456+
bool ExpansionMap::IsNextRepeatStart(Measure *measure)
457+
{
458+
static const std::vector<data_BARRENDITION> match{ BARRENDITION_rptboth, BARRENDITION_rptstart };
459+
460+
if (!measure->HasRight()) return false;
461+
462+
return (std::find(match.begin(), match.end(), measure->GetRight()) != match.end());
463+
}
464+
465+
bool ExpansionMap::IsPreviousRepeatEnd(Measure *measure)
466+
{
467+
static const std::vector<data_BARRENDITION> match{ BARRENDITION_rptboth, BARRENDITION_rptend };
468+
469+
if (!measure->HasLeft()) return false;
470+
471+
return (std::find(match.begin(), match.end(), measure->GetLeft()) != match.end());
472+
}
473+
365474
} // namespace vrv

src/options.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,6 +1593,10 @@ Options::Options()
15931593
m_expandFirst.Init(false);
15941594
this->Register(&m_expandFirst, "expandFirst", &m_selectors);
15951595

1596+
m_expandGenerate.SetInfo("Generate expansion", "Generate an expansion based on repeats");
1597+
m_expandGenerate.Init(false);
1598+
this->Register(&m_expandGenerate, "expandGenerate", &m_selectors);
1599+
15961600
m_loadSelectedMdivOnly.SetInfo(
15971601
"Load selected Mdiv only", "Load only the selected mdiv; the content of the other is skipped");
15981602
m_loadSelectedMdivOnly.Init(false);

0 commit comments

Comments
 (0)