Skip to content

Commit

Permalink
Merge GH-1796 (OCD support improvements)
Browse files Browse the repository at this point in the history
  • Loading branch information
dg0yt authored Dec 20, 2020
2 parents 0e72845 + 8c6be46 commit 838f2e3
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 26 deletions.
209 changes: 186 additions & 23 deletions src/fileformats/ocd_file_export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ void OcdFileExport::exportSymbols(OcdFile<Format>& file)

case Symbol::NoSymbol:
case Symbol::AllSymbols:
Q_UNREACHABLE();
FILEFORMAT_ASSERT(false); // unreachable
}

FILEFORMAT_ASSERT(!ocd_symbol.isEmpty());
Expand Down Expand Up @@ -1331,7 +1331,7 @@ qint16 OcdFileExport::exportSubPattern(const MapCoordVector& coords, const Symbo
case Symbol::AllSymbols:
case Symbol::Combined:
case Symbol::Text:
Q_UNREACHABLE();
FILEFORMAT_ASSERT(false); // unreachable
}

return num_coords;
Expand Down Expand Up @@ -1976,14 +1976,145 @@ void OcdFileExport::setupTextSymbolFraming(const TextSymbol* text_symbol, OcdTex



/**
* Returns the type of symbol which would be constructed by exportCombinedSymbol().
*/
int OcdFileExport::checkCombinedSymbol(const CombinedSymbol* combined_symbol) const
{
// The implementation must mirror exportCombinedSymbol()!

auto num_parts = 0; // The count of non-null parts.
const Symbol* parts[3] = {}; // A random access list without holes
for (auto i = 0; i < combined_symbol->getNumParts(); ++i)
{
if (auto const* part = combined_symbol->getPart(i))
{
if (num_parts < 3)
parts[num_parts] = part;
++num_parts;
}
}

switch (num_parts)
{
case 1:
// Single subsymbol: Output just this subsymbol, if sufficient.
switch (combined_symbol->getType())
{
case Symbol::Area:
return Ocd::SymbolTypeArea;
case Symbol::Line:
return Ocd::SymbolTypeLine;
case Symbol::Combined:
return 99;
case Symbol::Point:
case Symbol::Text:
case Symbol::NoSymbol:
case Symbol::AllSymbols:
return 99;
}
break;

case 2:
// Two subsymbols: Area with border, or line with framing, if sufficient.
if (parts[1]->getType() == Symbol::Area)
{
std::swap(parts[0], parts[1]);
}

if (parts[0]->getType() == Symbol::Area)
{
if (ocd_version < 9)
break;

// Area symbol with border, since OCD V9
auto const exported_as_line = [this](Symbol const* symbol) -> bool {
auto const type = symbol->getType();
return type == Symbol::Line
|| (type == Symbol::Combined
&& checkCombinedSymbol(static_cast<CombinedSymbol const*>(symbol)) == Ocd::SymbolTypeLine);
};

auto const* border_symbol = parts[1];
if (!exported_as_line(border_symbol))
{
// Not a suitable border line symbol
break;
}
else
{
// Same result for different branches in exportCombinedSymbol.
return Ocd::SymbolTypeArea;
}
}
Q_FALLTHROUGH();

case 3:
// Three subsymbols: Line with framing line and filled double line, if sufficient.
if (parts[0]->getType() == Symbol::Line && parts[1]->getType() == Symbol::Line
&& (num_parts == 2 || parts[2]->getType() == Symbol::Line))
{
// Complex line symbol
// Desired assignment, after rearrangement
auto main_line = static_cast<const LineSymbol*>(parts[0]);
auto framing = static_cast<const LineSymbol*>(parts[1]);
auto double_line = static_cast<const LineSymbol*>(parts[2]);
if (!maybeDoubleFilling(double_line))
{
// Select candidate double line/filling
if (maybeDoubleFilling(main_line))
std::swap(main_line, double_line);
else if (maybeDoubleFilling(framing))
std::swap(framing, double_line);
else if (double_line)
break;
}
if (!maybeFraming(framing))
{
// Select candidate framing
if (!main_line || maybeFraming(main_line))
std::swap(main_line, framing);
else if (framing)
break;
}
if (!maybeMainLine(main_line))
{
if (main_line)
break;
std::swap(main_line, framing);
}

return Ocd::SymbolTypeLine;
}
break;

default:
break;
}

// Fallback
return 99;
}


// The behaviour of this function must be mirrored by checkCombinedSymbol().
template< class Format >
void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSymbol* combined_symbol)
{
// Creates a breakdown record for combined symbols which are mapped to
// a simple OCD symbol. This record is needed to handle path objects
// which use such symbols.
auto const add_breakdown = [this](quint32 symbol_number, quint8 type) {
breakdown_index[symbol_number] = breakdown_list.size();
breakdown_list.push_back({symbol_number, type});
breakdown_list.push_back({0, 0});
};

auto num_parts = 0; // The count of non-null parts.
const Symbol* parts[3] = {}; // A random access list without holes
for (auto i = 0; i < combined_symbol->getNumParts(); ++i)
{
if (auto part = combined_symbol->getPart(i))
if (auto const* part = combined_symbol->getPart(i))
{
if (num_parts < 3)
parts[num_parts] = part;
Expand All @@ -2004,6 +2135,7 @@ void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSy
copySymbolHead(*combined_symbol, *copy);
auto ocd_subsymbol = exportAreaSymbol<typename Format::AreaSymbol>(copy.get(), symbol_number);
file.symbols().insert(ocd_subsymbol);
add_breakdown(symbol_number, Ocd::SymbolTypeArea);
}
return;
case Symbol::Line:
Expand All @@ -2012,6 +2144,7 @@ void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSy
copySymbolHead(*combined_symbol, *copy);
auto ocd_subsymbol = exportLineSymbol<typename Format::LineSymbol>(copy.get(), symbol_number);
file.symbols().insert(ocd_subsymbol);
add_breakdown(symbol_number, Ocd::SymbolTypeLine);
}
return;
case Symbol::Combined:
Expand All @@ -2020,50 +2153,79 @@ void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSy
case Symbol::Text:
case Symbol::NoSymbol:
case Symbol::AllSymbols:
Q_UNREACHABLE();
FILEFORMAT_ASSERT(false); // unreachable
}
break;

case 2:
// Two subsymbols: Area with border, or line with framing, if sufficient.
case 3:
// Three subsymbols: Line with framing line and filled double line, if sufficient.
if (parts[0]->getType() != Symbol::Line && parts[1]->getType() != Symbol::Line)
{
break;
}

if (parts[1]->getType() == Symbol::Area)
{
std::swap(parts[0], parts[1]);
}

if (parts[0]->getType() == Symbol::Area)
{
if (ocd_version < 9 || num_parts != 2)
if (ocd_version < 9)
break;

// Area symbol with border, since OCD V9
auto border_symbol = static_cast<const LineSymbol*>(parts[1]);
if (symbol_numbers.find(border_symbol) == end(symbol_numbers))
auto const exported_as_line = [this](Symbol const* symbol) -> bool {
auto const type = symbol->getType();
return type == Symbol::Line
|| (type == Symbol::Combined
&& checkCombinedSymbol(static_cast<CombinedSymbol const*>(symbol)) == Ocd::SymbolTypeLine);
};

auto const* border_symbol = parts[1];
if (!exported_as_line(border_symbol))
{
// Not a suitable border line symbol
break;
}
else if (symbol_numbers.find(border_symbol) != end(symbol_numbers))
{
// An unknown border symbol must be a private one
// The border line is a regular symbol.
}
else if (border_symbol->getType() == Symbol::Line)
{
// The border line is a private LineSymbol.
auto border_duplicate = duplicate(static_cast<const LineSymbol&>(*border_symbol));
copySymbolHead(*combined_symbol, *border_duplicate);
border_duplicate->setName(QLatin1String("Border of ") + border_symbol->getName());
border_duplicate->setName(QLatin1String("Border of ") + combined_symbol->getName());
auto const border_symbol_number = makeUniqueSymbolNumber(symbol_number);
symbol_numbers[border_duplicate.get()] = border_symbol_number;
file.symbols().insert(exportLineSymbol<typename Format::LineSymbol>(border_duplicate.get(), border_symbol_number));
border_symbol = border_duplicate.get();
temporary_symbols.emplace_back(std::move(border_duplicate));
auto border_symbol_number = makeUniqueSymbolNumber(symbol_number);
symbol_numbers[border_symbol] = border_symbol_number;
file.symbols().insert(exportLineSymbol<typename Format::LineSymbol>(border_symbol, border_symbol_number));
}
else if (border_symbol->getType() == Symbol::Combined)
{
// The border line is a private CombinedSymbol, exported as OCD line symbol.
auto border_duplicate = duplicate(static_cast<const CombinedSymbol&>(*border_symbol));
copySymbolHead(*combined_symbol, *border_duplicate);
border_duplicate->setName(QLatin1String("Border of ") + combined_symbol->getName());
auto const border_symbol_number = makeUniqueSymbolNumber(symbol_number);
symbol_numbers[border_duplicate.get()] = border_symbol_number;
exportCombinedSymbol<Format>(file, border_duplicate.get());
border_symbol = border_duplicate.get();
temporary_symbols.emplace_back(std::move(border_duplicate));
}
else
{
FILEFORMAT_ASSERT(false); // unreachable
}

auto copy = duplicate(static_cast<const AreaSymbol&>(*parts[0]));
copySymbolHead(*combined_symbol, *copy);
file.symbols().insert(exportCombinedAreaSymbol<typename Format::AreaSymbol>(symbol_number, combined_symbol, copy.get(), border_symbol));
add_breakdown(symbol_number, Ocd::SymbolTypeArea);
return;
}
Q_FALLTHROUGH();

case 3:
// (Up to) three subsymbols: Line with framing line and filled double line, if sufficient.
if (parts[0]->getType() == Symbol::Line && parts[1]->getType() == Symbol::Line
&& (num_parts == 2 || parts[2]->getType() == Symbol::Line))
{
Expand Down Expand Up @@ -2101,6 +2263,7 @@ void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSy
auto copy = duplicate(static_cast<const LineSymbol&>(*main_line));
copySymbolHead(*combined_symbol, *copy);
file.symbols().insert(exportCombinedLineSymbol<typename Format::LineSymbol>(symbol_number, combined_symbol, copy.get(), framing, double_line));
add_breakdown(symbol_number, Ocd::SymbolTypeLine);
return;
}
break;
Expand Down Expand Up @@ -2152,7 +2315,7 @@ void OcdFileExport::exportGenericCombinedSymbol(OcdFile<Format>& file, const Com
break;
case Symbol::NoSymbol:
case Symbol::AllSymbols:
Q_UNREACHABLE();
FILEFORMAT_ASSERT(false); // unreachable
}
if (type == 0)
{
Expand Down Expand Up @@ -2188,9 +2351,9 @@ QByteArray OcdFileExport::exportCombinedAreaSymbol<Ocd::AreaSymbolV8>(
quint32 /*symbol_number*/,
const CombinedSymbol* /*combined_symbol*/,
const AreaSymbol* /*area_symbol*/,
const LineSymbol* /*line_symbol*/)
const Symbol* /*line_symbol*/)
{
Q_UNREACHABLE();
FILEFORMAT_ASSERT(false); // unreachable
}


Expand All @@ -2199,7 +2362,7 @@ QByteArray OcdFileExport::exportCombinedAreaSymbol(
quint32 symbol_number,
const CombinedSymbol* combined_symbol,
const AreaSymbol* area_symbol,
const LineSymbol* line_symbol )
const Symbol* line_symbol )
{
auto ocd_symbol = exportAreaSymbol<OcdAreaSymbol>(area_symbol, symbol_number);
auto ocd_subsymbol_data = reinterpret_cast<OcdAreaSymbol*>(ocd_symbol.data());
Expand Down
6 changes: 4 additions & 2 deletions src/fileformats/ocd_file_export.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 Kai Pastor
* Copyright 2016-2020 Kai Pastor
*
* Some parts taken from file_format_oc*d8{.h,_p.h,cpp} which are
* Copyright 2012 Pete Curtis
Expand Down Expand Up @@ -227,6 +227,8 @@ class OcdFileExport : public Exporter
template< class OcdTextSymbolFraming >
void setupTextSymbolFraming(const TextSymbol* text_symbol, OcdTextSymbolFraming& ocd_text_framing);

int checkCombinedSymbol(const CombinedSymbol* combined_symbol) const;

template< class Format >
void exportCombinedSymbol(OcdFile<Format>& file, const CombinedSymbol* combined_symbol);

Expand All @@ -238,7 +240,7 @@ class OcdFileExport : public Exporter
quint32 symbol_number,
const CombinedSymbol* combined_symbol,
const AreaSymbol* area_symbol,
const LineSymbol* line_symbol );
const Symbol* line_symbol );

template< class OcdLineSymbol >
QByteArray exportCombinedLineSymbol(
Expand Down
8 changes: 7 additions & 1 deletion src/fileformats/ocd_file_import.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,13 @@ Symbol* OcdFileImport::importLineSymbol(const S& ocd_symbol)

// Import a 'double' line, including an optional filling?
OcdImportedLineSymbol* double_line = nullptr;
if (ocd_symbol.common.double_mode != OcdLineSymbolCommon::DoubleLineOff)
auto const is_visible_double_line = [](auto const& ocd_attributes) {
return ocd_attributes.double_mode != OcdLineSymbolCommon::DoubleLineOff
&& (ocd_attributes.double_width > 0
|| ocd_attributes.double_left_width > 0
|| ocd_attributes.double_right_width > 0);
};
if (is_visible_double_line(ocd_symbol.common))
{
double_line = main_line;
if (main_line->dashed
Expand Down

0 comments on commit 838f2e3

Please sign in to comment.