From 6388bd6e8660a67e7e5d9b6f15c7f97ce37bf699 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Sat, 28 Sep 2024 13:16:10 +0200 Subject: [PATCH 01/10] Add facsimile elements to functors --- include/vrv/functorinterface.h | 32 +++++++++++++ src/functorinterface.cpp | 84 ++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/include/vrv/functorinterface.h b/include/vrv/functorinterface.h index 1ee9384bf61..f24743f5839 100644 --- a/include/vrv/functorinterface.h +++ b/include/vrv/functorinterface.h @@ -41,6 +41,7 @@ class EditorialElement; class Ending; class Expansion; class F; +class Facsimile; class Fb; class Fermata; class Fing; @@ -52,6 +53,7 @@ class GenericLayerElement; class Gliss; class GraceAligner; class GraceGrp; +class Graphic; class GrpSym; class Hairpin; class HalfmRpt; @@ -118,6 +120,7 @@ class StaffAlignment; class StaffDef; class StaffGrp; class Stem; +class Surface; class Svg; class Syl; class Syllable; @@ -142,6 +145,7 @@ class TupletBracket; class TupletNum; class Turn; class Verse; +class Zone; //---------------------------------------------------------------------------- // FunctorInterface @@ -458,6 +462,20 @@ class FunctorInterface { virtual FunctorCode VisitTextElementEnd(TextElement *textElement); ///@} + /** + * @name Visit facsimle elements + */ + ///@{ + virtual FunctorCode VisitFacsimile(Facsimile *facsimile); + virtual FunctorCode VisitFacsimileEnd(Facsimile *facsimile); + virtual FunctorCode VisitGraphic(Graphic *graphic); + virtual FunctorCode VisitGraphicEnd(Graphic *graphic); + virtual FunctorCode VisitSurface(Surface *surface); + virtual FunctorCode VisitSurfaceEnd(Surface *surface); + virtual FunctorCode VisitZone(Zone *zone); + virtual FunctorCode VisitZoneEnd(Zone *zone); + ///@} + /** * @name Visit horizontal aligners */ @@ -817,6 +835,20 @@ class ConstFunctorInterface { virtual FunctorCode VisitTextElementEnd(const TextElement *textElement); ///@} + /** + * @name Visit facsimle elements + */ + ///@{ + virtual FunctorCode VisitFacsimile(const Facsimile *facsimile); + virtual FunctorCode VisitFacsimileEnd(const Facsimile *facsimile); + virtual FunctorCode VisitGraphic(const Graphic *graphic); + virtual FunctorCode VisitGraphicEnd(const Graphic *graphic); + virtual FunctorCode VisitSurface(const Surface *surface); + virtual FunctorCode VisitSurfaceEnd(const Surface *surface); + virtual FunctorCode VisitZone(const Zone *zone); + virtual FunctorCode VisitZoneEnd(const Zone *zone); + ///@} + /** * @name Visit horizontal aligners */ diff --git a/src/functorinterface.cpp b/src/functorinterface.cpp index 92d82a8dee3..202645cbbbc 100644 --- a/src/functorinterface.cpp +++ b/src/functorinterface.cpp @@ -35,6 +35,7 @@ #include "ending.h" #include "expansion.h" #include "f.h" +#include "facsimile.h" #include "fb.h" #include "fermata.h" #include "fig.h" @@ -43,6 +44,7 @@ #include "genericlayerelement.h" #include "gliss.h" #include "gracegrp.h" +#include "graphic.h" #include "grpsym.h" #include "hairpin.h" #include "halfmrpt.h" @@ -101,6 +103,7 @@ #include "staffdef.h" #include "staffgrp.h" #include "stem.h" +#include "surface.h" #include "svg.h" #include "syl.h" #include "syllable.h" @@ -119,6 +122,7 @@ #include "tuplet.h" #include "turn.h" #include "verse.h" +#include "zone.h" namespace vrv { @@ -1326,6 +1330,46 @@ FunctorCode FunctorInterface::VisitTextElementEnd(TextElement *textElement) return this->VisitObjectEnd(textElement); } +FunctorCode FunctorInterface::VisitFacsimile(Facsimile *facsimile) +{ + return this->VisitObject(facsimile); +} + +FunctorCode FunctorInterface::VisitFacsimileEnd(Facsimile *facsimile) +{ + return this->VisitObjectEnd(facsimile); +} + +FunctorCode FunctorInterface::VisitGraphic(Graphic *graphic) +{ + return this->VisitObject(graphic); +} + +FunctorCode FunctorInterface::VisitGraphicEnd(Graphic *graphic) +{ + return this->VisitObjectEnd(graphic); +} + +FunctorCode FunctorInterface::VisitSurface(Surface *surface) +{ + return this->VisitObject(surface); +} + +FunctorCode FunctorInterface::VisitSurfaceEnd(Surface *surface) +{ + return this->VisitObjectEnd(surface); +} + +FunctorCode FunctorInterface::VisitZone(Zone *zone) +{ + return this->VisitObject(zone); +} + +FunctorCode FunctorInterface::VisitZoneEnd(Zone *zone) +{ + return this->VisitObjectEnd(zone); +} + FunctorCode FunctorInterface::VisitAlignment(Alignment *alignment) { return this->VisitObject(alignment); @@ -2620,6 +2664,46 @@ FunctorCode ConstFunctorInterface::VisitTextElementEnd(const TextElement *textEl return this->VisitObjectEnd(textElement); } +FunctorCode ConstFunctorInterface::VisitFacsimile(const Facsimile *facsimile) +{ + return this->VisitObject(facsimile); +} + +FunctorCode ConstFunctorInterface::VisitFacsimileEnd(const Facsimile *facsimile) +{ + return this->VisitObjectEnd(facsimile); +} + +FunctorCode ConstFunctorInterface::VisitGraphic(const Graphic *graphic) +{ + return this->VisitObject(graphic); +} + +FunctorCode ConstFunctorInterface::VisitGraphicEnd(const Graphic *graphic) +{ + return this->VisitObjectEnd(graphic); +} + +FunctorCode ConstFunctorInterface::VisitSurface(const Surface *surface) +{ + return this->VisitObject(surface); +} + +FunctorCode ConstFunctorInterface::VisitSurfaceEnd(const Surface *surface) +{ + return this->VisitObjectEnd(surface); +} + +FunctorCode ConstFunctorInterface::VisitZone(const Zone *zone) +{ + return this->VisitObject(zone); +} + +FunctorCode ConstFunctorInterface::VisitZoneEnd(const Zone *zone) +{ + return this->VisitObjectEnd(zone); +} + FunctorCode ConstFunctorInterface::VisitAlignment(const Alignment *alignment) { return this->VisitObject(alignment); From 620bb7557fd6a948acce5d8b448d416c5644586d Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Sat, 28 Sep 2024 16:57:12 +0200 Subject: [PATCH 02/10] Add Accept and AcceptEnd methods to facsimile classes --- include/vrv/facsimile.h | 19 +++++++++++++++++++ include/vrv/graphic.h | 14 ++++++++++++++ include/vrv/surface.h | 14 ++++++++++++++ include/vrv/zone.h | 14 ++++++++++++++ src/facsimile.cpp | 25 +++++++++++++++++++++++++ src/graphic.cpp | 25 +++++++++++++++++++++++++ src/surface.cpp | 25 +++++++++++++++++++++++++ src/zone.cpp | 25 +++++++++++++++++++++++++ 8 files changed, 161 insertions(+) diff --git a/include/vrv/facsimile.h b/include/vrv/facsimile.h index 00f86a29c74..0a7e401a558 100644 --- a/include/vrv/facsimile.h +++ b/include/vrv/facsimile.h @@ -47,6 +47,25 @@ class Facsimile : public Object, public AttTyped { const Zone *FindZoneByID(const std::string &zoneId) const; int GetMaxX() const; int GetMaxY() const; + + //----------// + // Functors // + //----------// + + /** + * Interface for class functor visitation + */ + ///@{ + FunctorCode Accept(Functor &functor) override; + FunctorCode Accept(ConstFunctor &functor) const override; + FunctorCode AcceptEnd(Functor &functor) override; + FunctorCode AcceptEnd(ConstFunctor &functor) const override; + ///@} + +protected: + // +private: + // }; } // namespace vrv diff --git a/include/vrv/graphic.h b/include/vrv/graphic.h index 7e1b263e68c..4bf765c7dcc 100644 --- a/include/vrv/graphic.h +++ b/include/vrv/graphic.h @@ -48,6 +48,20 @@ class Graphic : public Object, public AttPointing, public AttWidth, public AttHe int GetDrawingHeight(int unit, int staffSize) const; ///@} + //----------// + // Functors // + //----------// + + /** + * Interface for class functor visitation + */ + ///@{ + FunctorCode Accept(Functor &functor) override; + FunctorCode Accept(ConstFunctor &functor) const override; + FunctorCode AcceptEnd(Functor &functor) override; + FunctorCode AcceptEnd(ConstFunctor &functor) const override; + ///@} + protected: // private: diff --git a/include/vrv/surface.h b/include/vrv/surface.h index f6cc1eb8eec..046c26c66d7 100644 --- a/include/vrv/surface.h +++ b/include/vrv/surface.h @@ -44,6 +44,20 @@ class Surface : public Object, public AttTyped, public AttCoordinated, public At int GetMaxX() const; int GetMaxY() const; + //----------// + // Functors // + //----------// + + /** + * Interface for class functor visitation + */ + ///@{ + FunctorCode Accept(Functor &functor) override; + FunctorCode Accept(ConstFunctor &functor) const override; + FunctorCode AcceptEnd(Functor &functor) override; + FunctorCode AcceptEnd(ConstFunctor &functor) const override; + ///@} + protected: // private: diff --git a/include/vrv/zone.h b/include/vrv/zone.h index c9e3e44ebc7..f8a35cb355a 100644 --- a/include/vrv/zone.h +++ b/include/vrv/zone.h @@ -43,6 +43,20 @@ class Zone : public Object, public AttTyped, public AttCoordinated, public AttCo int GetLogicalUly() const; int GetLogicalLry() const; + //----------// + // Functors // + //----------// + + /** + * Interface for class functor visitation + */ + ///@{ + FunctorCode Accept(Functor &functor) override; + FunctorCode Accept(ConstFunctor &functor) const override; + FunctorCode AcceptEnd(Functor &functor) override; + FunctorCode AcceptEnd(ConstFunctor &functor) const override; + ///@} + protected: // private: diff --git a/src/facsimile.cpp b/src/facsimile.cpp index e3f48762f98..887a678c6cd 100644 --- a/src/facsimile.cpp +++ b/src/facsimile.cpp @@ -14,6 +14,7 @@ //---------------------------------------------------------------------------- #include "comparison.h" +#include "functor.h" #include "surface.h" #include "vrv.h" #include "zone.h" @@ -80,4 +81,28 @@ int Facsimile::GetMaxY() const return max; } +//---------------------------------------------------------------------------- +// Functor methods +//---------------------------------------------------------------------------- + +FunctorCode Facsimile::Accept(Functor &functor) +{ + return functor.VisitFacsimile(this); +} + +FunctorCode Facsimile::Accept(ConstFunctor &functor) const +{ + return functor.VisitFacsimile(this); +} + +FunctorCode Facsimile::AcceptEnd(Functor &functor) +{ + return functor.VisitFacsimileEnd(this); +} + +FunctorCode Facsimile::AcceptEnd(ConstFunctor &functor) const +{ + return functor.VisitFacsimileEnd(this); +} + } // namespace vrv diff --git a/src/graphic.cpp b/src/graphic.cpp index 03f04040e12..e2a96453691 100644 --- a/src/graphic.cpp +++ b/src/graphic.cpp @@ -14,6 +14,7 @@ //---------------------------------------------------------------------------- #include "comparison.h" +#include "functor.h" #include "vrv.h" namespace vrv { @@ -59,4 +60,28 @@ int Graphic::GetDrawingHeight(int unit, int staffSize) const return (this->GetHeight().GetVu() * unit); } +//---------------------------------------------------------------------------- +// Functor methods +//---------------------------------------------------------------------------- + +FunctorCode Graphic::Accept(Functor &functor) +{ + return functor.VisitGraphic(this); +} + +FunctorCode Graphic::Accept(ConstFunctor &functor) const +{ + return functor.VisitGraphic(this); +} + +FunctorCode Graphic::AcceptEnd(Functor &functor) +{ + return functor.VisitGraphicEnd(this); +} + +FunctorCode Graphic::AcceptEnd(ConstFunctor &functor) const +{ + return functor.VisitGraphicEnd(this); +} + } // namespace vrv diff --git a/src/surface.cpp b/src/surface.cpp index 3c0b01d1b43..0f8e0fdf44c 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -15,6 +15,7 @@ #include "comparison.h" #include "facsimile.h" +#include "functor.h" #include "graphic.h" #include "vrv.h" #include "zone.h" @@ -85,4 +86,28 @@ int Surface::GetMaxY() const return max; } +//---------------------------------------------------------------------------- +// Functor methods +//---------------------------------------------------------------------------- + +FunctorCode Surface::Accept(Functor &functor) +{ + return functor.VisitSurface(this); +} + +FunctorCode Surface::Accept(ConstFunctor &functor) const +{ + return functor.VisitSurface(this); +} + +FunctorCode Surface::AcceptEnd(Functor &functor) +{ + return functor.VisitSurfaceEnd(this); +} + +FunctorCode Surface::AcceptEnd(ConstFunctor &functor) const +{ + return functor.VisitSurfaceEnd(this); +} + } // namespace vrv diff --git a/src/zone.cpp b/src/zone.cpp index b5838cd7672..1861a40e1bf 100644 --- a/src/zone.cpp +++ b/src/zone.cpp @@ -14,6 +14,7 @@ //---------------------------------------------------------------------------- #include "comparison.h" +#include "functor.h" #include "vrv.h" namespace vrv { @@ -59,4 +60,28 @@ int Zone::GetLogicalLry() const return (this->GetLry()); } +//---------------------------------------------------------------------------- +// Functor methods +//---------------------------------------------------------------------------- + +FunctorCode Zone::Accept(Functor &functor) +{ + return functor.VisitZone(this); +} + +FunctorCode Zone::Accept(ConstFunctor &functor) const +{ + return functor.VisitZone(this); +} + +FunctorCode Zone::AcceptEnd(Functor &functor) +{ + return functor.VisitZoneEnd(this); +} + +FunctorCode Zone::AcceptEnd(ConstFunctor &functor) const +{ + return functor.VisitZoneEnd(this); +} + } // namespace vrv From 588d637cd5c3ac20c8a74e614a48c11694fbe4ac Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Mon, 30 Sep 2024 10:23:39 +0200 Subject: [PATCH 03/10] Read and write `surface@type` pixel per unit when loading or writing facsimile data --- include/vrv/facsimilefunctor.h | 12 +++- include/vrv/miscfunctor.h | 4 +- src/doc.cpp | 20 +++--- src/facsimilefunctor.cpp | 117 ++++++++++++++++++++++++++------- src/miscfunctor.cpp | 38 ++++++++++- src/view_element.cpp | 2 +- 6 files changed, 153 insertions(+), 40 deletions(-) diff --git a/include/vrv/facsimilefunctor.h b/include/vrv/facsimilefunctor.h index 7ccf8f3e772..e74b93000ff 100644 --- a/include/vrv/facsimilefunctor.h +++ b/include/vrv/facsimilefunctor.h @@ -75,6 +75,11 @@ class SyncFromFacsimileFunctor : public Functor { Measure *m_currentNeumeLine; /** map to store the zone corresponding to a staff */ std::map m_staffZones; + // + int m_pageMarginTop; + int m_pageMarginLeft; + // + double m_ppuFactor; }; //---------------------------------------------------------------------------- @@ -90,14 +95,14 @@ class SyncToFacsimileFunctor : public Functor { * @name Constructors, destructors */ ///@{ - SyncToFacsimileFunctor(Doc *doc); + SyncToFacsimileFunctor(Doc *doc, double ppuFactor); virtual ~SyncToFacsimileFunctor() = default; ///@} /* * Abstract base implementation */ - bool ImplementsEndInterface() const override { return false; } + bool ImplementsEndInterface() const override { return true; } /* * Functor interface @@ -106,6 +111,7 @@ class SyncToFacsimileFunctor : public Functor { FunctorCode VisitLayerElement(LayerElement *layerElement) override; FunctorCode VisitMeasure(Measure *measure) override; FunctorCode VisitPage(Page *page) override; + FunctorCode VisitPageEnd(Page *page) override; FunctorCode VisitPb(Pb *pb) override; FunctorCode VisitSb(Sb *sb) override; FunctorCode VisitStaff(Staff *staff) override; @@ -133,6 +139,8 @@ class SyncToFacsimileFunctor : public Functor { // int m_pageMarginTop; int m_pageMarginLeft; + // + double m_ppuFactor; }; } // namespace vrv diff --git a/include/vrv/miscfunctor.h b/include/vrv/miscfunctor.h index fbfe04cfc37..c14c997e0a4 100644 --- a/include/vrv/miscfunctor.h +++ b/include/vrv/miscfunctor.h @@ -25,7 +25,7 @@ class ApplyPPUFactorFunctor : public Functor { * @name Constructors, destructors */ ///@{ - ApplyPPUFactorFunctor(); + ApplyPPUFactorFunctor(Page *page = NULL); virtual ~ApplyPPUFactorFunctor() = default; ///@} @@ -42,7 +42,9 @@ class ApplyPPUFactorFunctor : public Functor { FunctorCode VisitMeasure(Measure *measure) override; FunctorCode VisitPage(Page *page) override; FunctorCode VisitStaff(Staff *staff) override; + FunctorCode VisitSurface(Surface *surface) override; FunctorCode VisitSystem(System *system) override; + FunctorCode VisitZone(Zone *zone) override; ///@} protected: diff --git a/src/doc.cpp b/src/doc.cpp index b123741b1cf..bc0ab3a7f6d 100644 --- a/src/doc.cpp +++ b/src/doc.cpp @@ -1407,20 +1407,20 @@ void Doc::SyncFromFacsimileDoc() void Doc::SyncToFacsimileDoc() { + double ppuFactor = 1.0; // Create a new facsimile object if we do not have one already if (!this->HasFacsimile()) { Facsimile *facsimile = new Facsimile(); this->SetFacsimile(facsimile); + m_facsimile->SetType("transcription"); + // We use the scale option to determine the ppu and adjust the ppu factor accordingly + // For example, with scale 50 and the default unit, the ppu will be 4.5 (instead of 9.0) + ppuFactor = (double)m_options->m_scale.GetValue() / 100.0; } - if (!m_facsimile->FindDescendantByType(SURFACE)) { - m_facsimile->AddChild(new Surface()); - } - this->ScoreDefSetCurrentDoc(); - m_facsimile->SetType("transcription"); - m_facsimile->ClearChildren(); + this->ScoreDefSetCurrentDoc(); - SyncToFacsimileFunctor syncToFacimileFunctor(this); + SyncToFacsimileFunctor syncToFacimileFunctor(this, ppuFactor); this->Process(syncToFacimileFunctor); } @@ -2140,8 +2140,7 @@ int Doc::GetAdjustedDrawingPageHeight() const // Take into account the PPU when getting the page height in facsimile if (this->IsTranscription() || this->IsFacs()) { - const int factor = DEFINITION_FACTOR / m_drawingPage->GetPPUFactor(); - return m_drawingPage->m_pageHeight / factor; + return m_drawingPage->m_pageHeight * m_drawingPage->GetPPUFactor() / DEFINITION_FACTOR; } int contentHeight = m_drawingPage->GetContentHeight(); @@ -2154,8 +2153,7 @@ int Doc::GetAdjustedDrawingPageWidth() const // Take into account the PPU when getting the page width in facsimile if (this->IsTranscription() || this->IsFacs()) { - const int factor = DEFINITION_FACTOR / m_drawingPage->GetPPUFactor(); - return m_drawingPage->m_pageWidth / factor; + return m_drawingPage->m_pageWidth * m_drawingPage->GetPPUFactor() / DEFINITION_FACTOR; } int contentWidth = m_drawingPage->GetContentWidth(); diff --git a/src/facsimilefunctor.cpp b/src/facsimilefunctor.cpp index f70d6804d9c..b2dd83998a5 100644 --- a/src/facsimilefunctor.cpp +++ b/src/facsimilefunctor.cpp @@ -36,6 +36,9 @@ SyncFromFacsimileFunctor::SyncFromFacsimileFunctor(Doc *doc) : Functor() m_view.SetDoc(doc); m_currentPage = NULL; m_currentSystem = NULL; + m_pageMarginTop = 0; + m_pageMarginLeft = 0; + m_ppuFactor = 1.0; } FunctorCode SyncFromFacsimileFunctor::VisitLayerElement(LayerElement *layerElement) @@ -44,9 +47,9 @@ FunctorCode SyncFromFacsimileFunctor::VisitLayerElement(LayerElement *layerEleme Zone *zone = layerElement->GetZone(); assert(zone); - layerElement->m_drawingFacsX = m_view.ToLogicalX(zone->GetUlx() * DEFINITION_FACTOR); + layerElement->m_drawingFacsX = m_view.ToLogicalX(zone->GetUlx() * DEFINITION_FACTOR - m_pageMarginLeft); if (layerElement->Is({ ACCID, SYL })) { - layerElement->m_drawingFacsY = m_view.ToLogicalY(zone->GetUly() * DEFINITION_FACTOR); + layerElement->m_drawingFacsY = m_view.ToLogicalY(zone->GetUly() * DEFINITION_FACTOR - m_pageMarginTop); } return FUNCTOR_CONTINUE; @@ -61,8 +64,8 @@ FunctorCode SyncFromFacsimileFunctor::VisitMeasure(Measure *measure) else { Zone *zone = measure->GetZone(); assert(zone); - measure->m_drawingFacsX1 = m_view.ToLogicalX(zone->GetUlx() * DEFINITION_FACTOR); - measure->m_drawingFacsX2 = m_view.ToLogicalX(zone->GetLrx() * DEFINITION_FACTOR); + measure->m_drawingFacsX1 = m_view.ToLogicalX(zone->GetUlx() * DEFINITION_FACTOR - m_pageMarginLeft); + measure->m_drawingFacsX2 = m_view.ToLogicalX(zone->GetLrx() * DEFINITION_FACTOR - m_pageMarginLeft); } return FUNCTOR_CONTINUE; @@ -80,7 +83,10 @@ FunctorCode SyncFromFacsimileFunctor::VisitPage(Page *page) FunctorCode SyncFromFacsimileFunctor::VisitPageEnd(Page *page) { // Used for adjusting staff size in neon - filled in VisitStaff - if (m_staffZones.empty()) return FUNCTOR_CONTINUE; + if (!m_staffZones.empty()) { + // Since we multiply all values by the DEFINITION_FACTOR, set it as PPU for neon facs + m_ppuFactor = DEFINITION_FACTOR; + } // The staff size is calculated based on the zone height and takes into acocunt the rotation for (auto &[staff, zone] : m_staffZones) { @@ -92,8 +98,7 @@ FunctorCode SyncFromFacsimileFunctor::VisitPageEnd(Page *page) staff->SetDrawingRotation(rotate); } - // Since we multiply all values by the DEFINITION_FACTOR, set it as PPU - m_currentPage->SetPPUFactor(DEFINITION_FACTOR); + m_currentPage->SetPPUFactor(m_ppuFactor); if (m_currentPage->GetPPUFactor() != 1.0) { ApplyPPUFactorFunctor applyPPUFactor; m_currentPage->Process(applyPPUFactor); @@ -117,12 +122,35 @@ FunctorCode SyncFromFacsimileFunctor::VisitPb(Pb *pb) if (surface && surface->HasLrx() && surface->HasLry()) { m_currentPage->m_pageHeight = surface->GetLry() * DEFINITION_FACTOR; m_currentPage->m_pageWidth = surface->GetLrx() * DEFINITION_FACTOR; + // Read the ppu factor from surface@type + std::string surfaceType = surface->GetType(); + if (surfaceType.starts_with("ppu:")) { + std::string ppuFactorStr = surfaceType.substr(surfaceType.find(":") + 1); + if (vrv::IsValidDouble(ppuFactorStr)) { + m_ppuFactor = std::strtod(ppuFactorStr.c_str(), NULL); + m_ppuFactor *= DEFINITION_FACTOR / m_doc->GetOptions()->m_unit.GetValue(); + } + } + // Read margins + if (zone && zone->HasUlx() && zone->HasUly() && zone->HasLrx() && zone->HasLry()) { + m_pageMarginTop = zone->GetUly() * DEFINITION_FACTOR; + m_pageMarginLeft = zone->GetUlx() * DEFINITION_FACTOR; + m_currentPage->m_pageMarginTop = m_pageMarginTop; + // Calculate the bottom margin looking at the surface lry and zone lry + m_currentPage->m_pageMarginBottom = m_currentPage->m_pageHeight - zone->GetLry() * DEFINITION_FACTOR; + m_currentPage->m_pageMarginLeft = m_pageMarginLeft; + // Calculate the right margin looking at the surface lrx and zone lrx + m_currentPage->m_pageMarginRight = m_currentPage->m_pageWidth - zone->GetLrx() * DEFINITION_FACTOR; + ; + m_doc->UpdatePageDrawingSizes(); + } } // Fallback on zone else { m_currentPage->m_pageHeight = zone->GetLry() * DEFINITION_FACTOR; m_currentPage->m_pageWidth = zone->GetLrx() * DEFINITION_FACTOR; } + // Update the page size to have to View::ToLogicalX/Y valid m_doc->UpdatePageDrawingSizes(); @@ -136,8 +164,8 @@ FunctorCode SyncFromFacsimileFunctor::VisitSb(Sb *sb) Zone *zone = sb->GetZone(); assert(zone); - m_currentSystem->m_drawingFacsX = m_view.ToLogicalX(zone->GetUlx() * DEFINITION_FACTOR); - m_currentSystem->m_drawingFacsY = m_view.ToLogicalY(zone->GetUly() * DEFINITION_FACTOR); + m_currentSystem->m_drawingFacsX = m_view.ToLogicalX(zone->GetUlx() * DEFINITION_FACTOR - m_pageMarginLeft); + m_currentSystem->m_drawingFacsY = m_view.ToLogicalY(zone->GetUly() * DEFINITION_FACTOR - m_pageMarginTop); return FUNCTOR_CONTINUE; } @@ -146,12 +174,12 @@ FunctorCode SyncFromFacsimileFunctor::VisitStaff(Staff *staff) { Zone *zone = staff->GetZone(); assert(zone); - staff->m_drawingFacsY = m_view.ToLogicalY(zone->GetUly() * DEFINITION_FACTOR); + staff->m_drawingFacsY = m_view.ToLogicalY(zone->GetUly() * DEFINITION_FACTOR - m_pageMarginTop); // neon specific code - set the position of the pseudo measure (neume line) if (m_currentNeumeLine) { - m_currentNeumeLine->m_drawingFacsX1 = m_view.ToLogicalX(zone->GetUlx() * DEFINITION_FACTOR); - m_currentNeumeLine->m_drawingFacsX2 = m_view.ToLogicalX(zone->GetLrx() * DEFINITION_FACTOR); + m_currentNeumeLine->m_drawingFacsX1 = m_view.ToLogicalX(zone->GetUlx() * DEFINITION_FACTOR - m_pageMarginLeft); + m_currentNeumeLine->m_drawingFacsX2 = m_view.ToLogicalX(zone->GetLrx() * DEFINITION_FACTOR - m_pageMarginLeft); m_staffZones[staff] = zone; // The staff slope is going up. The y left position needs to be adjusted accordingly @@ -177,9 +205,10 @@ FunctorCode SyncFromFacsimileFunctor::VisitSystem(System *system) // SyncToFacsimileFunctor //---------------------------------------------------------------------------- -SyncToFacsimileFunctor::SyncToFacsimileFunctor(Doc *doc) : Functor() +SyncToFacsimileFunctor::SyncToFacsimileFunctor(Doc *doc, double ppuFactor) : Functor() { m_doc = doc; + m_ppuFactor = ppuFactor; m_view.SetDoc(doc); m_surface = NULL; m_currentPage = NULL; @@ -213,29 +242,68 @@ FunctorCode SyncToFacsimileFunctor::VisitMeasure(Measure *measure) FunctorCode SyncToFacsimileFunctor::VisitPage(Page *page) { + // This is required since processing Pb will create or select the Surface + if (!page->FindDescendantByType(PB)) { + LogWarning("Page without skipped when synching to facsimile"); + return FUNCTOR_SIBLINGS; + } + m_currentPage = page; m_doc->SetDrawingPage(page->GetIdx()); page->LayOut(); - // - m_surface = new Surface(); - assert(m_doc->GetFacsimile()); - m_doc->GetFacsimile()->AddChild(m_surface); - m_surface->SetLrx(m_doc->m_drawingPageWidth / DEFINITION_FACTOR); - m_surface->SetLry(m_doc->m_drawingPageHeight / DEFINITION_FACTOR); - // Because the facsimile output zone positions include the margins, we will add them to each zone - m_pageMarginTop = m_doc->m_drawingPageMarginTop / DEFINITION_FACTOR; - m_pageMarginLeft = m_doc->m_drawingPageMarginLeft / DEFINITION_FACTOR; + // From a previously loaded facsimile + if (page->GetPPUFactor() != 1.0) { + m_ppuFactor = page->GetPPUFactor(); + } + // When generating a facsimile with a scale option + else { + page->SetPPUFactor(m_ppuFactor); + } + + return FUNCTOR_CONTINUE; +} + +FunctorCode SyncToFacsimileFunctor::VisitPageEnd(Page *page) +{ + if (m_ppuFactor != 1.0) { + ApplyPPUFactorFunctor applyPPUFactor(m_currentPage); + m_surface->Process(applyPPUFactor); + m_surface->SetType( + StringFormat("ppu:%f", m_ppuFactor * m_doc->GetOptions()->m_unit.GetValue() / DEFINITION_FACTOR)); + } return FUNCTOR_CONTINUE; } FunctorCode SyncToFacsimileFunctor::VisitPb(Pb *pb) { - Zone *zone = this->GetZone(pb, pb->GetClassName()); + Zone *zone = pb->GetZone(); + // Assume to be creating the facsimile data from scratch + if (!pb->GetZone()) { + // Also create a new surface + m_surface = new Surface(); + assert(m_doc->GetFacsimile()); + m_doc->GetFacsimile()->AddChild(m_surface); + zone = this->GetZone(pb, pb->GetClassName()); + } + // We already have some facsimile data - retrieve the surface ancestor + else { + m_surface = vrv_cast(zone->GetFirstAncestor(SURFACE)); + } + assert(m_surface); + assert(zone); + + m_surface->SetLrx(m_doc->m_drawingPageWidth / DEFINITION_FACTOR); + m_surface->SetLry(m_doc->m_drawingPageHeight / DEFINITION_FACTOR); + // Because the facsimile output zone positions include the margins, we will add them to each zone + m_pageMarginTop = m_doc->m_drawingPageMarginTop / DEFINITION_FACTOR; + m_pageMarginLeft = m_doc->m_drawingPageMarginLeft / DEFINITION_FACTOR; + // The Pb zone values are currently not used in SyncFromFacsimileFunctor because the // page sizes are synced from the parent Surface and zone positions include margins zone->SetUlx(m_pageMarginLeft); zone->SetUly(m_pageMarginTop); + // Use the page content size to factor in the bottom and right margins zone->SetLrx(m_doc->m_drawingPageContentWidth / DEFINITION_FACTOR + m_pageMarginLeft); zone->SetLry(m_doc->m_drawingPageContentHeight / DEFINITION_FACTOR + m_pageMarginTop); @@ -268,8 +336,11 @@ FunctorCode SyncToFacsimileFunctor::VisitSystem(System *system) Zone *SyncToFacsimileFunctor::GetZone(FacsimileInterface *interface, std::string type) { + assert(m_surface); + if (interface->GetZone()) { // Here we should probably check if the zone is a child of m_surface + assert(interface->GetZone()->GetParent() == m_surface); return interface->GetZone(); } else { diff --git a/src/miscfunctor.cpp b/src/miscfunctor.cpp index f10936c906e..58754e1a2ca 100644 --- a/src/miscfunctor.cpp +++ b/src/miscfunctor.cpp @@ -12,8 +12,10 @@ #include "layer.h" #include "page.h" #include "staff.h" +#include "surface.h" #include "system.h" #include "verse.h" +#include "zone.h" //---------------------------------------------------------------------------- @@ -23,13 +25,15 @@ namespace vrv { // ApplyPPUFactorFunctor //---------------------------------------------------------------------------- -ApplyPPUFactorFunctor::ApplyPPUFactorFunctor() : Functor() +ApplyPPUFactorFunctor::ApplyPPUFactorFunctor(Page *page) : Functor() { - m_page = NULL; + m_page = page; } FunctorCode ApplyPPUFactorFunctor::VisitLayerElement(LayerElement *layerElement) { + assert(m_page); + if (layerElement->IsScoreDefElement()) return FUNCTOR_SIBLINGS; if (layerElement->m_drawingFacsX != VRV_UNSET) layerElement->m_drawingFacsX /= m_page->GetPPUFactor(); @@ -40,6 +44,8 @@ FunctorCode ApplyPPUFactorFunctor::VisitLayerElement(LayerElement *layerElement) FunctorCode ApplyPPUFactorFunctor::VisitMeasure(Measure *measure) { + assert(m_page); + if (measure->m_drawingFacsX1 != VRV_UNSET) measure->m_drawingFacsX1 /= m_page->GetPPUFactor(); if (measure->m_drawingFacsX2 != VRV_UNSET) measure->m_drawingFacsX2 /= m_page->GetPPUFactor(); @@ -61,13 +67,29 @@ FunctorCode ApplyPPUFactorFunctor::VisitPage(Page *page) FunctorCode ApplyPPUFactorFunctor::VisitStaff(Staff *staff) { + assert(m_page); + if (staff->m_drawingFacsY != VRV_UNSET) staff->m_drawingFacsY /= m_page->GetPPUFactor(); return FUNCTOR_CONTINUE; } +FunctorCode ApplyPPUFactorFunctor::VisitSurface(Surface *surface) +{ + assert(m_page); + + if (surface->HasUlx()) surface->SetUlx(surface->GetUlx() * m_page->GetPPUFactor()); + if (surface->HasUly()) surface->SetUly(surface->GetUly() * m_page->GetPPUFactor()); + if (surface->HasLrx()) surface->SetLrx(surface->GetLrx() * m_page->GetPPUFactor()); + if (surface->HasLry()) surface->SetLry(surface->GetLry() * m_page->GetPPUFactor()); + + return FUNCTOR_CONTINUE; +} + FunctorCode ApplyPPUFactorFunctor::VisitSystem(System *system) { + assert(m_page); + if (system->m_drawingFacsX != VRV_UNSET) system->m_drawingFacsX /= m_page->GetPPUFactor(); if (system->m_drawingFacsY != VRV_UNSET) system->m_drawingFacsY /= m_page->GetPPUFactor(); system->m_systemLeftMar *= m_page->GetPPUFactor(); @@ -76,6 +98,18 @@ FunctorCode ApplyPPUFactorFunctor::VisitSystem(System *system) return FUNCTOR_CONTINUE; } +FunctorCode ApplyPPUFactorFunctor::VisitZone(Zone *zone) +{ + assert(m_page); + + if (zone->HasUlx()) zone->SetUlx(zone->GetUlx() * m_page->GetPPUFactor()); + if (zone->HasUly()) zone->SetUly(zone->GetUly() * m_page->GetPPUFactor()); + if (zone->HasLrx()) zone->SetLrx(zone->GetLrx() * m_page->GetPPUFactor()); + if (zone->HasLry()) zone->SetLry(zone->GetLry() * m_page->GetPPUFactor()); + + return FUNCTOR_CONTINUE; +} + //---------------------------------------------------------------------------- // GetAlignmentLeftRightFunctor //---------------------------------------------------------------------------- diff --git a/src/view_element.cpp b/src/view_element.cpp index efa5fd74b63..c4166e20b99 100644 --- a/src/view_element.cpp +++ b/src/view_element.cpp @@ -1746,7 +1746,7 @@ void View::DrawSyl(DeviceContext *dc, LayerElement *element, Layer *layer, Staff return; } - if (!m_doc->IsFacs() && !m_doc->IsNeumeLines()) { + if (!m_doc->IsFacs() && !m_doc->IsTranscription() && !m_doc->IsNeumeLines()) { syl->SetDrawingYRel(this->GetSylYRel(syl->m_drawingVerse, staff)); } From 144f3746542cb1caf4555a6c23b112e526889ecc Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Tue, 12 Nov 2024 09:10:16 +0100 Subject: [PATCH 04/10] Add LedgerLine::Dash class --- include/vrv/staff.h | 28 +++++++++++++++++++++++++++- src/calcledgerlinesfunctor.cpp | 21 ++++++++++----------- src/staff.cpp | 13 +++++++------ src/view_page.cpp | 4 ++-- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/include/vrv/staff.h b/include/vrv/staff.h index d49d48f0c8c..823c72bc398 100644 --- a/include/vrv/staff.h +++ b/include/vrv/staff.h @@ -45,6 +45,31 @@ class LedgerLine { */ void AddDash(int left, int right, int extension); + class Dash { + public: + int m_x1; + int m_x2; + ListOfConstObjects m_events; + + // Constructor + Dash(int x1, int x2, const Object *object) + { + m_x1 = x1; + m_x2 = x2; + m_events.push_back(object); + } + + // Merge function to merge another Dash object into this one + void MergeWith(const Dash &other) + { + // Keep the first int from this Dash object, and the second int from the other + this->m_x1 = std::min(other.m_x1, this->m_x1); + this->m_x2 = std::max(other.m_x2, this->m_x2); + // Append the list from other to this + this->m_events.insert(this->m_events.end(), other.m_events.begin(), other.m_events.end()); + } + }; + protected: // private: @@ -53,7 +78,8 @@ class LedgerLine { /** * A list of dashes relative to the staff position. */ - std::list> m_dashes; + // std::list> m_dashes; + std::list m_dashes; protected: // diff --git a/src/calcledgerlinesfunctor.cpp b/src/calcledgerlinesfunctor.cpp index bef0616bf2b..cdaf14abf54 100644 --- a/src/calcledgerlinesfunctor.cpp +++ b/src/calcledgerlinesfunctor.cpp @@ -121,15 +121,14 @@ void CalcLedgerLinesFunctor::AdjustLedgerLines( // For each dash on the inner line (both cue and normal) we construct an adjustment with zero delta // and sort them std::vector adjustments; - using DashType = std::pair; if (!lines.empty()) { - for (const DashType &dash : lines.at(0).m_dashes) { - adjustments.push_back({ dash.first, dash.second, false, 0 }); + for (const LedgerLine::Dash &dash : lines.at(0).m_dashes) { + adjustments.push_back({ dash.m_x1, dash.m_x2, false, 0 }); } } if (!cueLines.empty()) { - for (const DashType &dash : cueLines.at(0).m_dashes) { - adjustments.push_back({ dash.first, dash.second, true, 0 }); + for (const LedgerLine::Dash &dash : cueLines.at(0).m_dashes) { + adjustments.push_back({ dash.m_x1, dash.m_x2, true, 0 }); } } @@ -175,13 +174,13 @@ void CalcLedgerLinesFunctor::AdjustLedgerLines( if (adjustment.delta > 0) { ArrayOfLedgerLines &linesToAdjust = adjustment.isCue ? cueLines : lines; for (LedgerLine &line : linesToAdjust) { - std::list::iterator iterDash - = std::find_if(line.m_dashes.begin(), line.m_dashes.end(), [&adjustment](const DashType &dash) { - return ((dash.first >= adjustment.left) && (dash.second <= adjustment.right)); - }); + std::list::iterator iterDash = std::find_if( + line.m_dashes.begin(), line.m_dashes.end(), [&adjustment](const LedgerLine::Dash &dash) { + return ((dash.m_x1 >= adjustment.left) && (dash.m_x2 <= adjustment.right)); + }); if (iterDash != line.m_dashes.end()) { - iterDash->first += adjustment.delta; - iterDash->second -= adjustment.delta; + iterDash->m_x1 += adjustment.delta; + iterDash->m_x2 -= adjustment.delta; } } } diff --git a/src/staff.cpp b/src/staff.cpp index 2a71ace62d8..50aab291f84 100644 --- a/src/staff.cpp +++ b/src/staff.cpp @@ -302,23 +302,24 @@ void LedgerLine::AddDash(int left, int right, int extension) { assert(left < right); - std::list>::iterator iter; + std::list::iterator iter; // First add the dash for (iter = m_dashes.begin(); iter != m_dashes.end(); ++iter) { - if (iter->first > left) break; + if (iter->m_x1 > left) break; } - m_dashes.insert(iter, { left, right }); + m_dashes.insert(iter, LedgerLine::Dash(left, right, NULL)); // Merge dashes which overlap by more than 1.5 extensions // => Dashes belonging to the same chord overlap at least by two extensions and will get merged // => Overlapping dashes of adjacent notes will not get merged - std::list>::iterator previous = m_dashes.begin(); + std::list::iterator previous = m_dashes.begin(); iter = m_dashes.begin(); ++iter; while (iter != m_dashes.end()) { - if (previous->second > iter->first + 1.5 * extension) { - previous->second = std::max(iter->second, previous->second); + if (previous->m_x1 > iter->m_x1 + 1.5 * extension) { + previous->MergeWith(*iter); + previous->m_x2 = std::max(iter->m_x2, previous->m_x2); iter = m_dashes.erase(iter); } else { diff --git a/src/view_page.cpp b/src/view_page.cpp index d8e7797b34a..0ee797feeee 100644 --- a/src/view_page.cpp +++ b/src/view_page.cpp @@ -1376,8 +1376,8 @@ void View::DrawLedgerLines(DeviceContext *dc, Staff *staff, const ArrayOfLedgerL dc->SetBrush(m_currentColor, AxSOLID); for (const LedgerLine &line : lines) { - for (const std::pair &dash : line.m_dashes) { - dc->DrawLine(ToDeviceContextX(x + dash.first), ToDeviceContextY(y), ToDeviceContextX(x + dash.second), + for (const LedgerLine::Dash &dash : line.m_dashes) { + dc->DrawLine(ToDeviceContextX(x + dash.m_x1), ToDeviceContextY(y), ToDeviceContextX(x + dash.m_x2), ToDeviceContextY(y)); } y += ySpace; From 7ed45bd6e26e76630ecddd767cfed8eaf3acb078 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Tue, 12 Nov 2024 11:17:26 +0100 Subject: [PATCH 05/10] Add DeviceContext method to add custom data-* --- include/vrv/devicecontext.h | 5 +++++ include/vrv/svgdevicecontext.h | 7 ++++++- src/svgdevicecontext.cpp | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/vrv/devicecontext.h b/include/vrv/devicecontext.h index bf13577346e..6edc296b837 100644 --- a/include/vrv/devicecontext.h +++ b/include/vrv/devicecontext.h @@ -271,6 +271,11 @@ class DeviceContext { */ virtual void SetCustomGraphicColor(const std::string &color) {} + /** + * Method for adding custom graphic data-* attributes + */ + virtual void SetCustomGraphicAttributes(const std::string &data, const std::string &value) {} + /** * @name Methods for re-starting and ending a graphic for objects drawn in separate steps * The methods can be used to the output together, for example for a Beam diff --git a/include/vrv/svgdevicecontext.h b/include/vrv/svgdevicecontext.h index 0139e26ed8b..2b35ee72f5b 100644 --- a/include/vrv/svgdevicecontext.h +++ b/include/vrv/svgdevicecontext.h @@ -131,7 +131,12 @@ class SvgDeviceContext : public DeviceContext { /** * Method for changing the color of a custom graphic */ - virtual void SetCustomGraphicColor(const std::string &color) override; + void SetCustomGraphicColor(const std::string &color) override; + + /** + * Method for adding custom graphic data-* attributes + */ + void SetCustomGraphicAttributes(const std::string &data, const std::string &value) override; /** * @name Methods for re-starting and ending a graphic for objects drawn in separate steps diff --git a/src/svgdevicecontext.cpp b/src/svgdevicecontext.cpp index 1cec345599f..1d01a5d5b1d 100644 --- a/src/svgdevicecontext.cpp +++ b/src/svgdevicecontext.cpp @@ -438,6 +438,11 @@ void SvgDeviceContext::SetCustomGraphicColor(const std::string &color) m_currentNode.append_attribute("fill") = color.c_str(); } +void SvgDeviceContext::SetCustomGraphicAttributes(const std::string &data, const std::string &value) +{ + m_currentNode.append_attribute(("data-" + data).c_str()) = value.c_str(); +} + void SvgDeviceContext::EndResumedGraphic(Object *object, View *view) { m_svgNodeStack.pop_back(); From 89bff7867ae9432b961afc78245c569719e391b9 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Tue, 12 Nov 2024 11:18:18 +0100 Subject: [PATCH 06/10] Pass event object to various ledgerline related functions --- include/vrv/staff.h | 8 ++++---- src/calcledgerlinesfunctor.cpp | 4 ++-- src/staff.cpp | 17 +++++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/vrv/staff.h b/include/vrv/staff.h index 823c72bc398..1271318e469 100644 --- a/include/vrv/staff.h +++ b/include/vrv/staff.h @@ -43,7 +43,7 @@ class LedgerLine { * Add a dash to the ledger line object. * If necessary merges overlapping dashes. */ - void AddDash(int left, int right, int extension); + void AddDash(int left, int right, int extension, const Object *event); class Dash { public: @@ -233,8 +233,8 @@ class Staff : public Object, * If necessary creates the ledger line array. */ ///@{ - void AddLedgerLineAbove(int count, int left, int right, int extension, bool cueSize); - void AddLedgerLineBelow(int count, int left, int right, int extension, bool cueSize); + void AddLedgerLineAbove(int count, int left, int right, int extension, bool cueSize, const Object *event); + void AddLedgerLineBelow(int count, int left, int right, int extension, bool cueSize, const Object *event); ///@} /** @@ -274,7 +274,7 @@ class Staff : public Object, /** * Add the ledger line dashes to the legderline array. */ - void AddLedgerLines(ArrayOfLedgerLines &lines, int count, int left, int right, int extension); + void AddLedgerLines(ArrayOfLedgerLines &lines, int count, int left, int right, int extension, const Object *event); public: /** diff --git a/src/calcledgerlinesfunctor.cpp b/src/calcledgerlinesfunctor.cpp index cdaf14abf54..ce6e2460856 100644 --- a/src/calcledgerlinesfunctor.cpp +++ b/src/calcledgerlinesfunctor.cpp @@ -82,10 +82,10 @@ void CalcLedgerLinesFunctor::CalcForLayerElement( } if (linesAbove > 0) { - staff->AddLedgerLineAbove(linesAbove, left, right, extension, drawingCueSize); + staff->AddLedgerLineAbove(linesAbove, left, right, extension, drawingCueSize, layerElement); } else { - staff->AddLedgerLineBelow(linesBelow, left, right, extension, drawingCueSize); + staff->AddLedgerLineBelow(linesBelow, left, right, extension, drawingCueSize, layerElement); } } diff --git a/src/staff.cpp b/src/staff.cpp index 50aab291f84..eee4fc0a3ed 100644 --- a/src/staff.cpp +++ b/src/staff.cpp @@ -239,23 +239,24 @@ int Staff::CalcPitchPosYRel(const Doc *doc, int loc) const return (loc - staffLocOffset) * doc->GetDrawingUnit(m_drawingStaffSize); } -void Staff::AddLedgerLineAbove(int count, int left, int right, int extension, bool cueSize) +void Staff::AddLedgerLineAbove(int count, int left, int right, int extension, bool cueSize, const Object *event) { - this->AddLedgerLines(cueSize ? m_ledgerLinesAboveCue : m_ledgerLinesAbove, count, left, right, extension); + this->AddLedgerLines(cueSize ? m_ledgerLinesAboveCue : m_ledgerLinesAbove, count, left, right, extension, event); } -void Staff::AddLedgerLineBelow(int count, int left, int right, int extension, bool cueSize) +void Staff::AddLedgerLineBelow(int count, int left, int right, int extension, bool cueSize, const Object *event) { - this->AddLedgerLines(cueSize ? m_ledgerLinesBelowCue : m_ledgerLinesBelow, count, left, right, extension); + this->AddLedgerLines(cueSize ? m_ledgerLinesBelowCue : m_ledgerLinesBelow, count, left, right, extension, event); } -void Staff::AddLedgerLines(ArrayOfLedgerLines &lines, int count, int left, int right, int extension) +void Staff::AddLedgerLines( + ArrayOfLedgerLines &lines, int count, int left, int right, int extension, const Object *event) { assert(left < right); if ((int)lines.size() < count) lines.resize(count); for (int i = 0; i < count; ++i) { - lines.at(i).AddDash(left, right, extension); + lines.at(i).AddDash(left, right, extension, event); } } @@ -298,7 +299,7 @@ int Staff::GetNearestInterStaffPosition(int y, const Doc *doc, data_STAFFREL pla // LedgerLine //---------------------------------------------------------------------------- -void LedgerLine::AddDash(int left, int right, int extension) +void LedgerLine::AddDash(int left, int right, int extension, const Object *event) { assert(left < right); @@ -308,7 +309,7 @@ void LedgerLine::AddDash(int left, int right, int extension) for (iter = m_dashes.begin(); iter != m_dashes.end(); ++iter) { if (iter->m_x1 > left) break; } - m_dashes.insert(iter, LedgerLine::Dash(left, right, NULL)); + m_dashes.insert(iter, LedgerLine::Dash(left, right, event)); // Merge dashes which overlap by more than 1.5 extensions // => Dashes belonging to the same chord overlap at least by two extensions and will get merged From 470e7c24d91799ab64a305790d808f613378bb00 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Tue, 12 Nov 2024 11:18:46 +0100 Subject: [PATCH 07/10] Add custom group and data-* to ledger line dashes --- src/view_page.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/view_page.cpp b/src/view_page.cpp index 0ee797feeee..141c70fd02e 100644 --- a/src/view_page.cpp +++ b/src/view_page.cpp @@ -11,6 +11,7 @@ #include #include +#include //---------------------------------------------------------------------------- @@ -1375,10 +1376,31 @@ void View::DrawLedgerLines(DeviceContext *dc, Staff *staff, const ArrayOfLedgerL dc->SetPen(m_currentColor, ToDeviceContextX(lineWidth), AxSOLID); dc->SetBrush(m_currentColor, AxSOLID); + bool svgHtml5 = (m_doc->GetOptions()->m_svgHtml5.GetValue()); + for (const LedgerLine &line : lines) { for (const LedgerLine::Dash &dash : line.m_dashes) { + if (svgHtml5) { + // Add the custom graphic only with html5 + dc->StartCustomGraphic("lineDash"); + // Function to concatenate IDs from the list of Object events + auto concatenateIDs = [](const ListOfConstObjects &objects) { + // Get a list of strings + auto ids = objects | std::views::transform([](const Object *object) { return object->GetID(); }); + // Concatenate IDs with a space separator + std::stringstream sstream; + std::copy(ids.begin(), ids.end(), std::ostream_iterator(sstream, " ")); + return sstream.str(); + }; + std::string events = concatenateIDs(dash.m_events); + if (!events.empty()) events.pop_back(); // Remove extra space added by the concatenation + dc->SetCustomGraphicAttributes("mei-id", events); + } + dc->DrawLine(ToDeviceContextX(x + dash.m_x1), ToDeviceContextY(y), ToDeviceContextX(x + dash.m_x2), ToDeviceContextY(y)); + + if (svgHtml5) dc->EndCustomGraphic(); } y += ySpace; } From 914f21f1024c5a695edb2512affb965b23eea327 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Tue, 12 Nov 2024 11:41:17 +0100 Subject: [PATCH 08/10] Process BarLine and ignore y-position when not neon data --- include/vrv/facsimilefunctor.h | 2 ++ src/facsimilefunctor.cpp | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/vrv/facsimilefunctor.h b/include/vrv/facsimilefunctor.h index 7ccf8f3e772..71f801dad1c 100644 --- a/include/vrv/facsimilefunctor.h +++ b/include/vrv/facsimilefunctor.h @@ -133,6 +133,8 @@ class SyncToFacsimileFunctor : public Functor { // int m_pageMarginTop; int m_pageMarginLeft; + // A flag indicating we are dealing with a neume line + bool m_currentNeumeLine; }; } // namespace vrv diff --git a/src/facsimilefunctor.cpp b/src/facsimilefunctor.cpp index f70d6804d9c..ebb6a8f9bf3 100644 --- a/src/facsimilefunctor.cpp +++ b/src/facsimilefunctor.cpp @@ -40,12 +40,13 @@ SyncFromFacsimileFunctor::SyncFromFacsimileFunctor(Doc *doc) : Functor() FunctorCode SyncFromFacsimileFunctor::VisitLayerElement(LayerElement *layerElement) { - if (!layerElement->Is({ ACCID, CLEF, CUSTOS, DIVLINE, LIQUESCENT, NC, NOTE, REST, SYL })) return FUNCTOR_CONTINUE; + if (!layerElement->Is({ ACCID, BARLINE, CLEF, CUSTOS, DIVLINE, LIQUESCENT, NC, NOTE, REST, SYL })) + return FUNCTOR_CONTINUE; Zone *zone = layerElement->GetZone(); assert(zone); layerElement->m_drawingFacsX = m_view.ToLogicalX(zone->GetUlx() * DEFINITION_FACTOR); - if (layerElement->Is({ ACCID, SYL })) { + if (m_currentNeumeLine && layerElement->Is({ ACCID, SYL })) { layerElement->m_drawingFacsY = m_view.ToLogicalY(zone->GetUly() * DEFINITION_FACTOR); } @@ -186,15 +187,17 @@ SyncToFacsimileFunctor::SyncToFacsimileFunctor(Doc *doc) : Functor() m_currentSystem = NULL; m_pageMarginTop = 0; m_pageMarginLeft = 0; + m_currentNeumeLine = false; } FunctorCode SyncToFacsimileFunctor::VisitLayerElement(LayerElement *layerElement) { - if (!layerElement->Is({ ACCID, CLEF, CUSTOS, DIVLINE, LIQUESCENT, NC, NOTE, REST, SYL })) return FUNCTOR_CONTINUE; + if (!layerElement->Is({ ACCID, BARLINE, CLEF, CUSTOS, DIVLINE, LIQUESCENT, NC, NOTE, REST, SYL })) + return FUNCTOR_CONTINUE; Zone *zone = this->GetZone(layerElement, layerElement->GetClassName()); zone->SetUlx(m_view.ToDeviceContextX(layerElement->GetDrawingX()) / DEFINITION_FACTOR + m_pageMarginLeft); - if (layerElement->Is({ ACCID, SYL })) { + if (m_currentNeumeLine && layerElement->Is({ ACCID, SYL })) { zone->SetUly(m_view.ToDeviceContextY(layerElement->GetDrawingY()) / DEFINITION_FACTOR + m_pageMarginTop); } @@ -208,6 +211,8 @@ FunctorCode SyncToFacsimileFunctor::VisitMeasure(Measure *measure) zone->SetLrx( m_view.ToDeviceContextX(measure->GetDrawingX() + measure->GetWidth()) / DEFINITION_FACTOR + m_pageMarginLeft); + m_currentNeumeLine = measure->IsNeumeLine(); + return FUNCTOR_CONTINUE; } From ba256682a853053d9ef40d15b8f045f47ce78ff4 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Wed, 13 Nov 2024 08:27:04 +0100 Subject: [PATCH 09/10] Do not process event when not html5 --- include/vrv/staff.h | 4 +++- src/calcledgerlinesfunctor.cpp | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/vrv/staff.h b/include/vrv/staff.h index 1271318e469..41db500ec8e 100644 --- a/include/vrv/staff.h +++ b/include/vrv/staff.h @@ -66,7 +66,9 @@ class LedgerLine { this->m_x1 = std::min(other.m_x1, this->m_x1); this->m_x2 = std::max(other.m_x2, this->m_x2); // Append the list from other to this - this->m_events.insert(this->m_events.end(), other.m_events.begin(), other.m_events.end()); + if (!other.m_events.empty()) { + this->m_events.insert(this->m_events.end(), other.m_events.begin(), other.m_events.end()); + } } }; diff --git a/src/calcledgerlinesfunctor.cpp b/src/calcledgerlinesfunctor.cpp index ce6e2460856..57fc206fb52 100644 --- a/src/calcledgerlinesfunctor.cpp +++ b/src/calcledgerlinesfunctor.cpp @@ -81,11 +81,12 @@ void CalcLedgerLinesFunctor::CalcForLayerElement( left -= width / 2; } + const LayerElement *event = (m_doc->GetOptions()->m_svgHtml5.GetValue()) ? layerElement : NULL; if (linesAbove > 0) { - staff->AddLedgerLineAbove(linesAbove, left, right, extension, drawingCueSize, layerElement); + staff->AddLedgerLineAbove(linesAbove, left, right, extension, drawingCueSize, event); } else { - staff->AddLedgerLineBelow(linesBelow, left, right, extension, drawingCueSize, layerElement); + staff->AddLedgerLineBelow(linesBelow, left, right, extension, drawingCueSize, event); } } From 73f28d6401cf3409cab9ab5dfe52400b448abc09 Mon Sep 17 00:00:00 2001 From: Laurent Pugin Date: Thu, 14 Nov 2024 14:40:25 +0100 Subject: [PATCH 10/10] Adjust the ledger line dash data-* * Add # * Change name to data-related --- src/view_page.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/view_page.cpp b/src/view_page.cpp index 141c70fd02e..235e6a908a2 100644 --- a/src/view_page.cpp +++ b/src/view_page.cpp @@ -1386,15 +1386,19 @@ void View::DrawLedgerLines(DeviceContext *dc, Staff *staff, const ArrayOfLedgerL // Function to concatenate IDs from the list of Object events auto concatenateIDs = [](const ListOfConstObjects &objects) { // Get a list of strings - auto ids = objects | std::views::transform([](const Object *object) { return object->GetID(); }); - // Concatenate IDs with a space separator + auto ids = objects + | std::views::transform([](const Object *object) { return ("#" + object->GetID() + " "); }); + // Concatenate IDs + // Once we have C++ 23 we can add the space above and do + // std::ranges::to(std::views::join(ids)); + // But for now use a stringstream std::stringstream sstream; - std::copy(ids.begin(), ids.end(), std::ostream_iterator(sstream, " ")); + std::copy(ids.begin(), ids.end(), std::ostream_iterator(sstream)); return sstream.str(); }; std::string events = concatenateIDs(dash.m_events); if (!events.empty()) events.pop_back(); // Remove extra space added by the concatenation - dc->SetCustomGraphicAttributes("mei-id", events); + dc->SetCustomGraphicAttributes("related", events); } dc->DrawLine(ToDeviceContextX(x + dash.m_x1), ToDeviceContextY(y), ToDeviceContextX(x + dash.m_x2),