Doxygen
Loading...
Searching...
No Matches
FormulaManager Class Reference

#include <src/formula.h>

Classes

struct  Private

Public Member Functions

repository functions
void initFromRepository (const DString &dir)
void checkRepositories ()
formula functions
void clear ()
int addFormula (const DString &formulaText, int width=-1, int height=-1)
const FormulafindFormula (int formulaId) const
bool hasFormulas () const

Static Public Member Functions

static FormulaManagerinstance ()

Private Member Functions

void createFormulasTexFile (Dir &d, Format format, HighDPI hd, Mode mode, bool toIndex)
void createLatexFile (const DString &fileName, Format format, Mode mode, IntVector &formulasToGenerate, bool toIndex)
 FormulaManager ()

Private Attributes

std::unique_ptr< Privatep

generator functions

enum class  Format { Bitmap , Vector }
enum class  HighDPI { On , Off }
enum class  Mode { Dark , Light }
void generateImages (const DString &outputDir, bool toIndex, Format format, HighDPI hd=HighDPI::Off)

Detailed Description

Manager class to handle formulas

Definition at line 58 of file formula.h.

Member Enumeration Documentation

◆ Format

enum class FormulaManager::Format
strong
Enumerator
Bitmap 
Vector 

Definition at line 79 of file formula.h.

79{ Bitmap, Vector };

◆ HighDPI

enum class FormulaManager::HighDPI
strong
Enumerator
On 
Off 

Definition at line 80 of file formula.h.

80{ On, Off };

◆ Mode

enum class FormulaManager::Mode
strong
Enumerator
Dark 
Light 

Definition at line 81 of file formula.h.

81{ Dark, Light };

Constructor & Destructor Documentation

◆ FormulaManager()

FormulaManager::FormulaManager ( )
private

Definition at line 49 of file formula.cpp.

49 : p(std::make_unique<Private>())
50{
51}
std::unique_ptr< Private > p
Definition formula.h:90

References p.

Referenced by instance().

Member Function Documentation

◆ addFormula()

int FormulaManager::addFormula ( const DString & formulaText,
int width = -1,
int height = -1 )

Definition at line 690 of file formula.cpp.

691{
692 Formula *formula = p->formulas.find(formulaText);
693 if (formula) // same formula already stored
694 {
695 return formula->id();
696 }
697 // add new formula
698 int id = static_cast<int>(p->formulas.size());
699 formula = p->formulas.add(formulaText,id,width,height);
700 p->formulaIdMap.emplace(id,formula);
701 return id;
702}
int id() const
Definition formula.h:36

References Formula::id(), and p.

Referenced by addFormula().

◆ checkRepositories()

void FormulaManager::checkRepositories ( )

Definition at line 172 of file formula.cpp.

173{
174 //printf("checkRepositories valid=%d\n",p->repositoriesValid);
175 if (!p->repositoriesValid)
176 {
177 clear(); // clear cached formulas, so the corresponding images and repository files
178 // are regenerated
179 p->repositoriesValid = true;
180 }
181}

References clear(), and p.

Referenced by parseInput().

◆ clear()

void FormulaManager::clear ( )

Definition at line 684 of file formula.cpp.

685{
686 p->formulas.clear();
687 p->formulaIdMap.clear();
688}

References p.

Referenced by checkRepositories(), cleanUpDoxygen(), and clearAll().

◆ createFormulasTexFile()

void FormulaManager::createFormulasTexFile ( Dir & d,
Format format,
HighDPI hd,
Mode mode,
bool toIndex )
private

Definition at line 551 of file formula.cpp.

552{
553 IntVector formulasToGenerate;
554 DString formulaFileName = mode==Mode::Light ? "_formulas" : "_formulas_dark";
555 createLatexFile(formulaFileName,format,mode,formulasToGenerate,toIndex);
556
557 if (!formulasToGenerate.empty()) // there are new formulas
558 {
559 if (!createDVIFile(formulaFileName)) return;
560
561 auto getFormula = [this](int pageNum) -> Formula *
562 {
563 auto it = p->formulaIdMap.find(pageNum);
564 if (it!=p->formulaIdMap.end())
565 {
566 return it->second;
567 }
568 return nullptr;
569 };
570
571 int pageIndex=1;
572 std::size_t numThreads = static_cast<std::size_t>(Config_getInt(NUM_PROC_THREADS));
573 if (numThreads>1) // multi-threaded version
574 {
575 ThreadPool threadPool(numThreads);
576 std::vector< std::future< StringVector > > results;
577 for (int pageNum : formulasToGenerate)
578 {
579 // create images for each formula.
580 auto formula = getFormula(pageNum);
581 auto processFormula = [=]() -> StringVector
582 {
583 return generateFormula(thisDir,formulaFileName,formula,pageNum,pageIndex,format,hd,mode);
584 };
585 results.emplace_back(threadPool.queue(processFormula));
586 pageIndex++;
587 }
588 for (auto &f : results)
589 {
590 auto tf = f.get();
591 p->tempFiles.insert(p->tempFiles.end(),tf.begin(),tf.end()); // append tf to p->tempFiles
592 }
593 }
594 else // single threaded version
595 {
596 for (int pageNum : formulasToGenerate)
597 {
598 // create images for each formula.
599 auto formula = getFormula(pageNum);
600 StringVector tf = generateFormula(thisDir,formulaFileName,formula,pageNum,pageIndex,format,hd,mode);
601 p->tempFiles.insert(p->tempFiles.end(),tf.begin(),tf.end()); // append tf to p->tempFiles
602
603 pageIndex++;
604 }
605 }
606 // remove intermediate files produced by latex
607 p->tempFiles.push_back(formulaFileName.str()+".dvi");
608 p->tempFiles.push_back(formulaFileName.str()+".log");
609 p->tempFiles.push_back(formulaFileName.str()+".aux");
610 }
611 // remove the latex file itself
612 p->tempFiles.push_back(formulaFileName.str()+".tex");
613
614 // write/update the formula repository so we know what text the
615 // generated images represent (we use this next time to avoid regeneration
616 // of the images, and to avoid forcing the user to delete all images in order
617 // to let a browser refresh the images).
618 std::ofstream f = Portable::openOutputStream("formula.repository");
619 if (f.is_open())
620 {
621 TextStream t(&f);
622 for (const auto &formula : p->formulas)
623 {
624 t << "\\_form#" << formula->id();
625 if (formula->width()!=-1 && formula->height()!=-1)
626 {
627 t << "=" << formula->width() << "x" << formula->height();
628 }
629 t << ":" << formula->text() << "\n";
630 }
631 }
632}
const std::string & str() const
Definition dstring.h:649
void createLatexFile(const DString &fileName, Format format, Mode mode, IntVector &formulasToGenerate, bool toIndex)
Definition formula.cpp:183
#define Config_getInt(name)
Definition config.h:34
std::vector< int > IntVector
Definition containers.h:38
std::vector< std::string > StringVector
Definition containers.h:33
static StringVector generateFormula(const Dir &thisDir, const DString &formulaFileName, Formula *formula, int pageNum, int pageIndex, FormulaManager::Format format, FormulaManager::HighDPI hd, FormulaManager::Mode mode)
Definition formula.cpp:471
static bool createDVIFile(const DString &fileName)
Definition formula.cpp:240
std::ofstream openOutputStream(const DString &name, bool append=false)
Definition portable.cpp:665

References Config_getInt, createDVIFile(), createLatexFile(), generateFormula(), Light, Portable::openOutputStream(), p, ThreadPool::queue(), and DString::str().

Referenced by generateImages().

◆ createLatexFile()

void FormulaManager::createLatexFile ( const DString & fileName,
Format format,
Mode mode,
IntVector & formulasToGenerate,
bool toIndex )
private

Definition at line 183 of file formula.cpp.

184{
185 // generate a latex file containing one formula per page.
186 DString texName=fileName+".tex";
187 std::ofstream f = Portable::openOutputStream(texName);
188 if (f.is_open())
189 {
190 TextStream t(&f);
191 t << "\\documentclass{article}\n";
192 t << "\\usepackage{iftex}\n";
193 t << "\\usepackage{ifthen}\n";
194 t << "\\usepackage{epsfig}\n"; // for those who want to include images
195 t << "\\usepackage[utf8]{inputenc}\n"; // looks like some older distributions with newunicode package 1.1 need this option.
196 t << "\\usepackage{xcolor}\n";
197
198 if (mode==Mode::Dark) // invert page and text colors
199 {
200 t << "\\color{white}\n";
201 t << "\\pagecolor{black}\n";
202 }
203
206
207 DString macroFile = Config_getString(FORMULA_MACROFILE);
208 if (!macroFile.empty())
209 {
210 FileInfo fi(macroFile.str());
211 DString stripMacroFile = fi.fileName();
212 t << "\\input{" << stripMacroFile << "}\n";
213 }
214
215 t << "\\pagestyle{empty}\n";
216 t << "\\begin{document}\n";
217 for (const auto &formula : p->formulas)
218 {
219 int id = formula->id();
220 // only formulas for which no image is cached are generated
221 //printf("check formula %d: cached=%d cachedDark=%d\n",formula->id(),formula->isCached(),formula->isCachedDark());
222 if ((mode==Mode::Light && !formula->isCached()) ||
223 (mode==Mode::Dark && !formula->isCachedDark())
224 )
225 {
226 // we force a pagebreak after each formula
227 t << formula->text() << "\n\\pagebreak\n\n";
228 formulasToGenerate.push_back(id);
229 }
230 DString resultName;
231 resultName.sprintf("form_%d%s.%s",id, mode==Mode::Light?"":"_dark", format==Format::Vector?"svg":"png");
232 if (toIndex) Doxygen::indexList->addImageFile(resultName);
233 }
234 t << "\\end{document}\n";
235 t.flush();
236 f.close();
237 }
238}
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:152
DString & sprintf(const char *format,...)
Definition dstring.cpp:30
static IndexList * indexList
Definition doxygen.h:125
void addImageFile(const DString &name)
Definition indexlist.h:124
#define Config_getString(name)
Definition config.h:32
void writeExtraLatexPackages(TextStream &t)
void writeLatexSpecialFormulaChars(TextStream &t)

References IndexList::addImageFile(), Config_getString, Dark, DString::empty(), FileInfo::fileName(), TextStream::flush(), Doxygen::indexList, Light, Portable::openOutputStream(), p, DString::sprintf(), DString::str(), Vector, writeExtraLatexPackages(), and writeLatexSpecialFormulaChars().

Referenced by createFormulasTexFile().

◆ findFormula()

const Formula * FormulaManager::findFormula ( int formulaId) const

Definition at line 704 of file formula.cpp.

705{
706 auto it = p->formulaIdMap.find(formulaId);
707 return it != p->formulaIdMap.end() ? it->second : nullptr;
708}

References p.

Referenced by DocFormula::DocFormula(), and HtmlDocVisitor::operator()().

◆ generateImages()

void FormulaManager::generateImages ( const DString & outputDir,
bool toIndex,
Format format,
HighDPI hd = HighDPI::Off )

Definition at line 634 of file formula.cpp.

635{
636 Dir d(path.str());
637 // store the original directory
638 if (!d.exists())
639 {
640 term("Output directory '{}' does not exist!\n",path);
641 }
642 std::string oldDir = Dir::currentDirPath();
643
644 DString macroFile = Config_getString(FORMULA_MACROFILE);
645 DString stripMacroFile;
646 if (!macroFile.empty())
647 {
648 FileInfo fi(macroFile.str());
649 macroFile=fi.absFilePath();
650 stripMacroFile = fi.fileName();
651 }
652
653 // go to the html output directory (i.e. path)
654 Dir::setCurrent(d.absPath());
655 Dir thisDir;
656
657 if (!macroFile.empty())
658 {
659 copyFile(macroFile,stripMacroFile);
660 }
661
662 createFormulasTexFile(thisDir,format,hd,Mode::Light,toIndex);
663 // for the HTML output format (toIndex == true) we possibly need the dark mode, not for the other formats
664 if (toIndex && Config_getEnum(HTML_COLORSTYLE)!=HTML_COLORSTYLE_t::LIGHT) // all modes other than light need a dark version
665 {
666 // note that the dark version reuses the bounding box of the light version so it needs to be
667 // created after the light version.
668 createFormulasTexFile(thisDir,format,hd,Mode::Dark,toIndex);
669 }
670
671 // clean up temporary files
673 {
674 for (const auto &file : p->tempFiles)
675 {
676 thisDir.remove(file);
677 }
678 }
679
680 // reset the directory to the original location.
681 Dir::setCurrent(oldDir);
682}
@ Formula
Definition debug.h:34
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:133
static std::string currentDirPath()
Definition dir.cpp:343
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:315
static bool setCurrent(const std::string &path)
Definition dir.cpp:351
void createFormulasTexFile(Dir &d, Format format, HighDPI hd, Mode mode, bool toIndex)
Definition formula.cpp:551
#define Config_getEnum(name)
Definition config.h:35
#define term(fmt,...)
Definition message.h:137
bool copyFile(const DString &src, const DString &dest)
Copies the contents of file with name src to the newly created file with name dest.
Definition util.cpp:4621

References FileInfo::absFilePath(), Dir::absPath(), Config_getEnum, Config_getString, copyFile(), createFormulasTexFile(), Dir::currentDirPath(), Dark, DString::empty(), Dir::exists(), FileInfo::fileName(), Debug::Formula, Debug::isFlagSet(), Light, p, Dir::remove(), Dir::setCurrent(), DString::str(), and term.

Referenced by generateOutput().

◆ hasFormulas()

bool FormulaManager::hasFormulas ( ) const

Definition at line 719 of file formula.cpp.

720{
721 return !p->formulas.empty();
722}

References p.

Referenced by generateOutput().

◆ initFromRepository()

void FormulaManager::initFromRepository ( const DString & dir)

Definition at line 59 of file formula.cpp.

60{
61 std::ifstream f = Portable::openInputStream(dir+"/formula.repository");
62 if (f.is_open())
63 {
64 uint32_t formulaCount=0;
65 msg("Reading formula repository...\n");
66 std::string readLine;
67 std::string line;
68 std::string prefix("\\_form#");
69 int nextLineNr=1;
70 bool hasNextLine = !getline(f,readLine).fail();
71 while (hasNextLine)
72 {
73 line = readLine;
74 int lineNr = nextLineNr;
75
76 // look ahead a bit because a formula can be spread over several lines
77 while ((hasNextLine = !getline(f,readLine).fail()))
78 {
79 nextLineNr+=1;
80 if (!readLine.compare(0, prefix.size(), prefix)) break;
81 line += "\n" + readLine;
82 }
83
84 // new format: \_form#<digits>=<digits>x<digits>:formula
85 static const reg::Ex re_new(R"(\\_form#(\d+)=(\d+)x(\d+):)");
86 // old format: \_form#<digits>:formula
87 static const reg::Ex re_old(R"(\\_form#(\d+):)");
88
89 reg::Match match;
90 int id = -1;
91 int width = -1;
92 int height = -1;
93 std::string text;
94 if (reg::search(line,match,re_new)) // try new format first
95 {
96 id = std::stoi(match[1].str());
97 width = std::stoi(match[2].str());
98 height = std::stoi(match[3].str());
99 text = line.substr(match.position()+match.length());
100 //printf("new format found id=%d width=%d height=%d text=%s\n",id,width,height,qPrinf(text));
101 }
102 else if (reg::search(line,match,re_old)) // check for old format
103 {
104 //id = std::stoi(match[1].str());
105 //text = line.substr(match.position()+match.length());
106 //printf("old format found id=%d text=%s\n",id,qPrint(text));
107 msg("old formula.repository format detected; forcing upgrade.\n");
108 p->repositoriesValid = false;
109 break;
110 }
111 else // unexpected content
112 {
113 warn_uncond("{}/formula.repository contains invalid content at line {}: found: '{}'\n",dir,lineNr,line);
114 p->repositoriesValid = false;
115 break;
116 }
117
118 auto it = p->formulaIdMap.find(id);
119 Formula *formula=nullptr;
120 if (it!=p->formulaIdMap.end()) // formula already found in a repository for another output format
121 {
122 formula = it->second;
123 if (formula->text().str()!=text) // inconsistency between repositories detected
124 {
125 msg("differences detected between formula.repository files; forcing upgrade.\n");
126 p->repositoriesValid = false;
127 break;
128 }
129 formulaCount++;
130 }
131 else // create new formula from cache
132 {
133 //printf("formula not found adding it under id=%d\n",id);
134 formula = p->formulas.add(text,id,width,height);
135 p->formulaIdMap.emplace(id,formula);
136 }
137
138 if (formula) // if an entry in the repository exists also check if there is a generated image
139 {
140 DString formImgName;
141 formImgName.sprintf("form_%d",formula->id());
142 FileInfo fiPng((dir+"/"+formImgName+".png").str());
143 FileInfo fiSvg((dir+"/"+formImgName+".svg").str());
144 // mark formula as cached, so we do not need to regenerate the images
145 bool isCached = fiPng.exists() || fiSvg.exists();
146 formula->setCached(isCached);
147 //printf("formula %d: cached=%d\n",formula->id(),isCached);
148
149 FileInfo fiPngDark((dir+"/"+formImgName+"_dark.png").str());
150 FileInfo fiSvgDark((dir+"/"+formImgName+"_dark.svg").str());
151 bool isCachedDark = fiPngDark.exists() || fiSvgDark.exists();
152 formula->setCachedDark(isCachedDark);
153 //printf("formula %d: cachedDark=%d\n",formula->id(),isCachedDark);
154 }
155 }
156
157 // For the first repository all formulas should be new (e.g. formulaCount==0).
158 // For the other repositories the same number of formulas should be found
159 // (and number of formulas should be the same for all repositories, content is already check above)
160 if (formulaCount>0 && formulaCount!=p->formulas.size()) // inconsistency between repositories
161 {
162 msg("differences detected between formula.repository files; forcing upgrade.\n");
163 p->repositoriesValid = false;
164 }
165 }
166 else // no repository found for an output format
167 {
168 p->repositoriesValid = false;
169 }
170}
constexpr auto prefix
Definition anchor.cpp:44
void setCachedDark(bool cached)
Definition formula.h:46
DString text() const
Definition formula.h:37
void setCached(bool cached)
Definition formula.h:45
#define warn_uncond(fmt,...)
Definition message.h:122
#define msg(fmt,...)
Definition message.h:94
std::ifstream openInputStream(const DString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:676
bool search(std::string_view str, Match &match, const Ex &re, size_t pos)
Search in a given string str starting at position pos for a match against regular expression re.
Definition regex.cpp:847
bool match(std::string_view str, Match &match, const Ex &re)
Matches a given string str for a match against regular expression re.
Definition regex.cpp:858

References FileInfo::exists(), Formula::id(), msg, Portable::openInputStream(), p, prefix, reg::search(), Formula::setCached(), Formula::setCachedDark(), DString::sprintf(), DString::str(), Formula::text(), and warn_uncond.

Referenced by parseInput().

◆ instance()

FormulaManager & FormulaManager::instance ( )
static

Definition at line 53 of file formula.cpp.

54{
55 static FormulaManager fm;
56 return fm;
57}

References FormulaManager().

Referenced by addFormula(), cleanUpDoxygen(), clearAll(), DocFormula::DocFormula(), generateOutput(), HtmlDocVisitor::operator()(), and parseInput().

Member Data Documentation

◆ p


The documentation for this class was generated from the following files: