Skip to content

Commit 838f2e3

Browse files
authored
Merge GH-1796 (OCD support improvements)
2 parents 0e72845 + 8c6be46 commit 838f2e3

File tree

3 files changed

+197
-26
lines changed

3 files changed

+197
-26
lines changed

src/fileformats/ocd_file_export.cpp

Lines changed: 186 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ void OcdFileExport::exportSymbols(OcdFile<Format>& file)
10911091

10921092
case Symbol::NoSymbol:
10931093
case Symbol::AllSymbols:
1094-
Q_UNREACHABLE();
1094+
FILEFORMAT_ASSERT(false); // unreachable
10951095
}
10961096

10971097
FILEFORMAT_ASSERT(!ocd_symbol.isEmpty());
@@ -1331,7 +1331,7 @@ qint16 OcdFileExport::exportSubPattern(const MapCoordVector& coords, const Symbo
13311331
case Symbol::AllSymbols:
13321332
case Symbol::Combined:
13331333
case Symbol::Text:
1334-
Q_UNREACHABLE();
1334+
FILEFORMAT_ASSERT(false); // unreachable
13351335
}
13361336

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

19771977

19781978

1979+
/**
1980+
* Returns the type of symbol which would be constructed by exportCombinedSymbol().
1981+
*/
1982+
int OcdFileExport::checkCombinedSymbol(const CombinedSymbol* combined_symbol) const
1983+
{
1984+
// The implementation must mirror exportCombinedSymbol()!
1985+
1986+
auto num_parts = 0; // The count of non-null parts.
1987+
const Symbol* parts[3] = {}; // A random access list without holes
1988+
for (auto i = 0; i < combined_symbol->getNumParts(); ++i)
1989+
{
1990+
if (auto const* part = combined_symbol->getPart(i))
1991+
{
1992+
if (num_parts < 3)
1993+
parts[num_parts] = part;
1994+
++num_parts;
1995+
}
1996+
}
1997+
1998+
switch (num_parts)
1999+
{
2000+
case 1:
2001+
// Single subsymbol: Output just this subsymbol, if sufficient.
2002+
switch (combined_symbol->getType())
2003+
{
2004+
case Symbol::Area:
2005+
return Ocd::SymbolTypeArea;
2006+
case Symbol::Line:
2007+
return Ocd::SymbolTypeLine;
2008+
case Symbol::Combined:
2009+
return 99;
2010+
case Symbol::Point:
2011+
case Symbol::Text:
2012+
case Symbol::NoSymbol:
2013+
case Symbol::AllSymbols:
2014+
return 99;
2015+
}
2016+
break;
2017+
2018+
case 2:
2019+
// Two subsymbols: Area with border, or line with framing, if sufficient.
2020+
if (parts[1]->getType() == Symbol::Area)
2021+
{
2022+
std::swap(parts[0], parts[1]);
2023+
}
2024+
2025+
if (parts[0]->getType() == Symbol::Area)
2026+
{
2027+
if (ocd_version < 9)
2028+
break;
2029+
2030+
// Area symbol with border, since OCD V9
2031+
auto const exported_as_line = [this](Symbol const* symbol) -> bool {
2032+
auto const type = symbol->getType();
2033+
return type == Symbol::Line
2034+
|| (type == Symbol::Combined
2035+
&& checkCombinedSymbol(static_cast<CombinedSymbol const*>(symbol)) == Ocd::SymbolTypeLine);
2036+
};
2037+
2038+
auto const* border_symbol = parts[1];
2039+
if (!exported_as_line(border_symbol))
2040+
{
2041+
// Not a suitable border line symbol
2042+
break;
2043+
}
2044+
else
2045+
{
2046+
// Same result for different branches in exportCombinedSymbol.
2047+
return Ocd::SymbolTypeArea;
2048+
}
2049+
}
2050+
Q_FALLTHROUGH();
2051+
2052+
case 3:
2053+
// Three subsymbols: Line with framing line and filled double line, if sufficient.
2054+
if (parts[0]->getType() == Symbol::Line && parts[1]->getType() == Symbol::Line
2055+
&& (num_parts == 2 || parts[2]->getType() == Symbol::Line))
2056+
{
2057+
// Complex line symbol
2058+
// Desired assignment, after rearrangement
2059+
auto main_line = static_cast<const LineSymbol*>(parts[0]);
2060+
auto framing = static_cast<const LineSymbol*>(parts[1]);
2061+
auto double_line = static_cast<const LineSymbol*>(parts[2]);
2062+
if (!maybeDoubleFilling(double_line))
2063+
{
2064+
// Select candidate double line/filling
2065+
if (maybeDoubleFilling(main_line))
2066+
std::swap(main_line, double_line);
2067+
else if (maybeDoubleFilling(framing))
2068+
std::swap(framing, double_line);
2069+
else if (double_line)
2070+
break;
2071+
}
2072+
if (!maybeFraming(framing))
2073+
{
2074+
// Select candidate framing
2075+
if (!main_line || maybeFraming(main_line))
2076+
std::swap(main_line, framing);
2077+
else if (framing)
2078+
break;
2079+
}
2080+
if (!maybeMainLine(main_line))
2081+
{
2082+
if (main_line)
2083+
break;
2084+
std::swap(main_line, framing);
2085+
}
2086+
2087+
return Ocd::SymbolTypeLine;
2088+
}
2089+
break;
2090+
2091+
default:
2092+
break;
2093+
}
2094+
2095+
// Fallback
2096+
return 99;
2097+
}
2098+
2099+
2100+
// The behaviour of this function must be mirrored by checkCombinedSymbol().
19792101
template< class Format >
19802102
void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSymbol* combined_symbol)
19812103
{
2104+
// Creates a breakdown record for combined symbols which are mapped to
2105+
// a simple OCD symbol. This record is needed to handle path objects
2106+
// which use such symbols.
2107+
auto const add_breakdown = [this](quint32 symbol_number, quint8 type) {
2108+
breakdown_index[symbol_number] = breakdown_list.size();
2109+
breakdown_list.push_back({symbol_number, type});
2110+
breakdown_list.push_back({0, 0});
2111+
};
2112+
19822113
auto num_parts = 0; // The count of non-null parts.
19832114
const Symbol* parts[3] = {}; // A random access list without holes
19842115
for (auto i = 0; i < combined_symbol->getNumParts(); ++i)
19852116
{
1986-
if (auto part = combined_symbol->getPart(i))
2117+
if (auto const* part = combined_symbol->getPart(i))
19872118
{
19882119
if (num_parts < 3)
19892120
parts[num_parts] = part;
@@ -2004,6 +2135,7 @@ void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSy
20042135
copySymbolHead(*combined_symbol, *copy);
20052136
auto ocd_subsymbol = exportAreaSymbol<typename Format::AreaSymbol>(copy.get(), symbol_number);
20062137
file.symbols().insert(ocd_subsymbol);
2138+
add_breakdown(symbol_number, Ocd::SymbolTypeArea);
20072139
}
20082140
return;
20092141
case Symbol::Line:
@@ -2012,6 +2144,7 @@ void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSy
20122144
copySymbolHead(*combined_symbol, *copy);
20132145
auto ocd_subsymbol = exportLineSymbol<typename Format::LineSymbol>(copy.get(), symbol_number);
20142146
file.symbols().insert(ocd_subsymbol);
2147+
add_breakdown(symbol_number, Ocd::SymbolTypeLine);
20152148
}
20162149
return;
20172150
case Symbol::Combined:
@@ -2020,50 +2153,79 @@ void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSy
20202153
case Symbol::Text:
20212154
case Symbol::NoSymbol:
20222155
case Symbol::AllSymbols:
2023-
Q_UNREACHABLE();
2156+
FILEFORMAT_ASSERT(false); // unreachable
20242157
}
20252158
break;
20262159

20272160
case 2:
20282161
// Two subsymbols: Area with border, or line with framing, if sufficient.
2029-
case 3:
2030-
// Three subsymbols: Line with framing line and filled double line, if sufficient.
2031-
if (parts[0]->getType() != Symbol::Line && parts[1]->getType() != Symbol::Line)
2032-
{
2033-
break;
2034-
}
2035-
20362162
if (parts[1]->getType() == Symbol::Area)
20372163
{
20382164
std::swap(parts[0], parts[1]);
20392165
}
20402166

20412167
if (parts[0]->getType() == Symbol::Area)
20422168
{
2043-
if (ocd_version < 9 || num_parts != 2)
2169+
if (ocd_version < 9)
20442170
break;
20452171

20462172
// Area symbol with border, since OCD V9
2047-
auto border_symbol = static_cast<const LineSymbol*>(parts[1]);
2048-
if (symbol_numbers.find(border_symbol) == end(symbol_numbers))
2173+
auto const exported_as_line = [this](Symbol const* symbol) -> bool {
2174+
auto const type = symbol->getType();
2175+
return type == Symbol::Line
2176+
|| (type == Symbol::Combined
2177+
&& checkCombinedSymbol(static_cast<CombinedSymbol const*>(symbol)) == Ocd::SymbolTypeLine);
2178+
};
2179+
2180+
auto const* border_symbol = parts[1];
2181+
if (!exported_as_line(border_symbol))
2182+
{
2183+
// Not a suitable border line symbol
2184+
break;
2185+
}
2186+
else if (symbol_numbers.find(border_symbol) != end(symbol_numbers))
20492187
{
2050-
// An unknown border symbol must be a private one
2188+
// The border line is a regular symbol.
2189+
}
2190+
else if (border_symbol->getType() == Symbol::Line)
2191+
{
2192+
// The border line is a private LineSymbol.
20512193
auto border_duplicate = duplicate(static_cast<const LineSymbol&>(*border_symbol));
20522194
copySymbolHead(*combined_symbol, *border_duplicate);
2053-
border_duplicate->setName(QLatin1String("Border of ") + border_symbol->getName());
2195+
border_duplicate->setName(QLatin1String("Border of ") + combined_symbol->getName());
2196+
auto const border_symbol_number = makeUniqueSymbolNumber(symbol_number);
2197+
symbol_numbers[border_duplicate.get()] = border_symbol_number;
2198+
file.symbols().insert(exportLineSymbol<typename Format::LineSymbol>(border_duplicate.get(), border_symbol_number));
20542199
border_symbol = border_duplicate.get();
20552200
temporary_symbols.emplace_back(std::move(border_duplicate));
2056-
auto border_symbol_number = makeUniqueSymbolNumber(symbol_number);
2057-
symbol_numbers[border_symbol] = border_symbol_number;
2058-
file.symbols().insert(exportLineSymbol<typename Format::LineSymbol>(border_symbol, border_symbol_number));
2201+
}
2202+
else if (border_symbol->getType() == Symbol::Combined)
2203+
{
2204+
// The border line is a private CombinedSymbol, exported as OCD line symbol.
2205+
auto border_duplicate = duplicate(static_cast<const CombinedSymbol&>(*border_symbol));
2206+
copySymbolHead(*combined_symbol, *border_duplicate);
2207+
border_duplicate->setName(QLatin1String("Border of ") + combined_symbol->getName());
2208+
auto const border_symbol_number = makeUniqueSymbolNumber(symbol_number);
2209+
symbol_numbers[border_duplicate.get()] = border_symbol_number;
2210+
exportCombinedSymbol<Format>(file, border_duplicate.get());
2211+
border_symbol = border_duplicate.get();
2212+
temporary_symbols.emplace_back(std::move(border_duplicate));
2213+
}
2214+
else
2215+
{
2216+
FILEFORMAT_ASSERT(false); // unreachable
20592217
}
20602218

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

2227+
case 3:
2228+
// (Up to) three subsymbols: Line with framing line and filled double line, if sufficient.
20672229
if (parts[0]->getType() == Symbol::Line && parts[1]->getType() == Symbol::Line
20682230
&& (num_parts == 2 || parts[2]->getType() == Symbol::Line))
20692231
{
@@ -2101,6 +2263,7 @@ void OcdFileExport::exportCombinedSymbol(OcdFile<Format>& file, const CombinedSy
21012263
auto copy = duplicate(static_cast<const LineSymbol&>(*main_line));
21022264
copySymbolHead(*combined_symbol, *copy);
21032265
file.symbols().insert(exportCombinedLineSymbol<typename Format::LineSymbol>(symbol_number, combined_symbol, copy.get(), framing, double_line));
2266+
add_breakdown(symbol_number, Ocd::SymbolTypeLine);
21042267
return;
21052268
}
21062269
break;
@@ -2152,7 +2315,7 @@ void OcdFileExport::exportGenericCombinedSymbol(OcdFile<Format>& file, const Com
21522315
break;
21532316
case Symbol::NoSymbol:
21542317
case Symbol::AllSymbols:
2155-
Q_UNREACHABLE();
2318+
FILEFORMAT_ASSERT(false); // unreachable
21562319
}
21572320
if (type == 0)
21582321
{
@@ -2188,9 +2351,9 @@ QByteArray OcdFileExport::exportCombinedAreaSymbol<Ocd::AreaSymbolV8>(
21882351
quint32 /*symbol_number*/,
21892352
const CombinedSymbol* /*combined_symbol*/,
21902353
const AreaSymbol* /*area_symbol*/,
2191-
const LineSymbol* /*line_symbol*/)
2354+
const Symbol* /*line_symbol*/)
21922355
{
2193-
Q_UNREACHABLE();
2356+
FILEFORMAT_ASSERT(false); // unreachable
21942357
}
21952358

21962359

@@ -2199,7 +2362,7 @@ QByteArray OcdFileExport::exportCombinedAreaSymbol(
21992362
quint32 symbol_number,
22002363
const CombinedSymbol* combined_symbol,
22012364
const AreaSymbol* area_symbol,
2202-
const LineSymbol* line_symbol )
2365+
const Symbol* line_symbol )
22032366
{
22042367
auto ocd_symbol = exportAreaSymbol<OcdAreaSymbol>(area_symbol, symbol_number);
22052368
auto ocd_subsymbol_data = reinterpret_cast<OcdAreaSymbol*>(ocd_symbol.data());

src/fileformats/ocd_file_export.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2018 Kai Pastor
2+
* Copyright 2016-2020 Kai Pastor
33
*
44
* Some parts taken from file_format_oc*d8{.h,_p.h,cpp} which are
55
* Copyright 2012 Pete Curtis
@@ -227,6 +227,8 @@ class OcdFileExport : public Exporter
227227
template< class OcdTextSymbolFraming >
228228
void setupTextSymbolFraming(const TextSymbol* text_symbol, OcdTextSymbolFraming& ocd_text_framing);
229229

230+
int checkCombinedSymbol(const CombinedSymbol* combined_symbol) const;
231+
230232
template< class Format >
231233
void exportCombinedSymbol(OcdFile<Format>& file, const CombinedSymbol* combined_symbol);
232234

@@ -238,7 +240,7 @@ class OcdFileExport : public Exporter
238240
quint32 symbol_number,
239241
const CombinedSymbol* combined_symbol,
240242
const AreaSymbol* area_symbol,
241-
const LineSymbol* line_symbol );
243+
const Symbol* line_symbol );
242244

243245
template< class OcdLineSymbol >
244246
QByteArray exportCombinedLineSymbol(

src/fileformats/ocd_file_import.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,13 @@ Symbol* OcdFileImport::importLineSymbol(const S& ocd_symbol)
12061206

12071207
// Import a 'double' line, including an optional filling?
12081208
OcdImportedLineSymbol* double_line = nullptr;
1209-
if (ocd_symbol.common.double_mode != OcdLineSymbolCommon::DoubleLineOff)
1209+
auto const is_visible_double_line = [](auto const& ocd_attributes) {
1210+
return ocd_attributes.double_mode != OcdLineSymbolCommon::DoubleLineOff
1211+
&& (ocd_attributes.double_width > 0
1212+
|| ocd_attributes.double_left_width > 0
1213+
|| ocd_attributes.double_right_width > 0);
1214+
};
1215+
if (is_visible_double_line(ocd_symbol.common))
12101216
{
12111217
double_line = main_line;
12121218
if (main_line->dashed

0 commit comments

Comments
 (0)