1#include "FeaturesFile.h"
2#include "ArchiveExtractor.h"
5#include "../invalid_odb_error.h"
7#include "../parse_error.h"
9#include "equals_within.h"
11#include "../../Text/Utf8Sanitizer.h"
16namespace Odb::Lib::FileModel::Design
20 void apply_default_units_to_symbols(
const std::string &rawUnits, SymbolName::Vector &symbols)
22 const auto inferred = Odb::Lib::FileModel::Design::inferred_unit_type_from_features_units(rawUnits);
23 if (inferred == UnitType::None)
25 for (
const auto &sym : symbols)
29 sym->ApplyDefaultUnitTypeIfNone(inferred);
35 FeaturesFile::FeaturesFile()
36 : m_path(
""), m_directory(
""), m_numFeatures(0), m_id(static_cast<unsigned>(-1))
40 FeaturesFile::~FeaturesFile()
42 m_featureRecords.clear();
43 m_attributeNames.clear();
44 m_attributeTextValues.clear();
45 m_symbolNamesByName.clear();
46 m_symbolNames.clear();
49 bool FeaturesFile::Parse(std::filesystem::path directory,
const std::string &alternateFilename )
51 std::ifstream featuresFile;
57 m_directory = directory;
59 loginfo(
"checking for extraction...");
61 std::vector<std::string> filenames;
62 if (alternateFilename.empty())
64 std::copy(std::begin(FEATURES_FILENAMES), std::end(FEATURES_FILENAMES), std::back_inserter(filenames));
68 filenames.push_back(alternateFilename);
71 std::filesystem::path featuresFilePath;
72 for (
const auto &featuresFilename : filenames)
74 loginfo(
"trying features file: [" + featuresFilename +
"]...");
76 featuresFilePath = Utils::ArchiveExtractor::getUncompressedFilePath(m_directory, featuresFilename);
77 if (exists(featuresFilePath) && is_regular_file(featuresFilePath))
79 loginfo(
"found features file: [" + featuresFilePath.string() +
"]");
84 m_path = featuresFilePath;
86 loginfo(
"any extraction complete, parsing data...");
88 if (!std::filesystem::exists(m_path))
90 auto message =
"features file does not exist: [" + m_path.string() +
"]";
91 throw invalid_odb_error(message.c_str());
93 else if (!std::filesystem::is_regular_file(m_path))
95 auto message =
"features is not a file: [" + m_path.string() +
"]";
96 throw invalid_odb_error(message.c_str());
99 featuresFile.open(m_path.string(), std::ios::in);
100 if (!featuresFile.is_open())
102 auto message =
"unable to open features file: [" + m_path.string() +
"]";
103 throw invalid_odb_error(message.c_str());
106 std::shared_ptr<FeatureRecord> pCurrentFeatureRecord;
107 std::shared_ptr<ContourPolygon> pCurrentContourPolygon;
109 while (std::getline(featuresFile, line))
114 Utils::str_trim(line);
117 std::stringstream lineStream(line);
120 if (line.find(COMMENT_TOKEN) == 0)
124 else if (line.find(UNITS_TOKEN) == 0)
128 if (!std::getline(lineStream, token,
'='))
130 throw_parse_error(m_path, line, token, lineNumber);
132 else if (!std::getline(lineStream, token,
'='))
134 throw_parse_error(m_path, line, token, lineNumber);
138 apply_default_units_to_symbols(m_units, m_symbolNames);
140 else if (line.find(
"U") == 0)
143 if (!std::getline(lineStream, token,
' '))
145 throw_parse_error(m_path, line, token, lineNumber);
147 else if (!std::getline(lineStream, token,
' '))
149 throw_parse_error(m_path, line, token, lineNumber);
153 apply_default_units_to_symbols(m_units, m_symbolNames);
155 else if (line.find(ID_TOKEN) == 0)
158 if (!std::getline(lineStream, token,
'='))
160 throw_parse_error(m_path, line, token, lineNumber);
162 else if (!std::getline(lineStream, token,
'='))
164 throw_parse_error(m_path, line, token, lineNumber);
166 m_id = std::stoul(token);
168 else if (line.find(NUM_FEATURES_TOKEN) == 0)
173 if (!(lineStream >> token))
175 throw_parse_error(m_path, line, token, lineNumber);
178 if (token != NUM_FEATURES_TOKEN)
180 throw_parse_error(m_path, line, token, lineNumber);
183 if (!(lineStream >> m_numFeatures))
185 throw_parse_error(m_path, line, token, lineNumber);
188 else if (line.find(ATTRIBUTE_NAME_TOKEN) == 0)
193 if (!std::getline(lineStream, token,
' '))
195 throw_parse_error(m_path, line, token, lineNumber);
197 else if (!std::getline(lineStream, token,
' '))
199 throw_parse_error(m_path, line, token, lineNumber);
201 m_attributeNames.push_back(token);
203 else if (line.find(ATTRIBUTE_VALUE_TOKEN) == 0)
207 if (!std::getline(lineStream, token,
' '))
209 throw_parse_error(m_path, line, token, lineNumber);
211 else if (!std::getline(lineStream >> std::ws, token))
213 throw_parse_error(m_path, line, token, lineNumber);
215 m_attributeTextValues.push_back(token);
217 else if (line.find(SYMBOL_NAME_TOKEN) == 0)
220 auto pSymbolName = std::make_shared<SymbolName>();
221 if (!pSymbolName->SymbolName::Parse(m_path, line, lineNumber))
223 throw_parse_error(m_path, line,
"", lineNumber);
225 pSymbolName->ApplyDefaultUnitTypeIfNone(Odb::Lib::FileModel::Design::inferred_unit_type_from_features_units(m_units));
226 m_symbolNamesByName[pSymbolName->GetName()] = pSymbolName;
227 m_symbolNames.push_back(pSymbolName);
229 else if (line.find(FeatureRecord::LINE_TOKEN) == 0)
232 if (!(lineStream >> token) || token != FeatureRecord::LINE_TOKEN)
234 throw_parse_error(m_path, line, token, lineNumber);
237 auto pFeatureRecord = std::make_shared<FeatureRecord>();
238 pFeatureRecord->type = FeatureRecord::Type::Line;
240 if (!(lineStream >> pFeatureRecord->xs))
242 throw_parse_error(m_path, line, token, lineNumber);
245 if (!(lineStream >> pFeatureRecord->ys))
247 throw_parse_error(m_path, line, token, lineNumber);
250 if (!(lineStream >> pFeatureRecord->xe))
252 throw_parse_error(m_path, line, token, lineNumber);
255 if (!(lineStream >> pFeatureRecord->ye))
257 throw_parse_error(m_path, line, token, lineNumber);
260 if (!(lineStream >> pFeatureRecord->sym_num))
262 throw_parse_error(m_path, line, token, lineNumber);
266 if (!(lineStream >> polarity))
268 throw_parse_error(m_path, line, token, lineNumber);
273 pFeatureRecord->polarity = Polarity::Positive;
276 pFeatureRecord->polarity = Polarity::Negative;
279 throw_parse_error(m_path, line, token, lineNumber);
282 if (!(lineStream >> pFeatureRecord->dcode))
284 throw_parse_error(m_path, line, token, lineNumber);
287 std::string attrIdString;
288 lineStream >> attrIdString;
290 if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
292 throw_parse_error(m_path, line, token, lineNumber);
295 m_featureRecords.push_back(pFeatureRecord);
297 else if (line.find(FeatureRecord::PAD_TOKEN) == 0)
300 if (!(lineStream >> token) || token != FeatureRecord::PAD_TOKEN)
302 throw_parse_error(m_path, line, token, lineNumber);
305 auto pFeatureRecord = std::make_shared<FeatureRecord>();
306 pFeatureRecord->type = FeatureRecord::Type::Pad;
308 if (!(lineStream >> pFeatureRecord->x))
310 throw_parse_error(m_path, line, token, lineNumber);
313 if (!(lineStream >> pFeatureRecord->y))
315 throw_parse_error(m_path, line, token, lineNumber);
318 if (!(lineStream >> pFeatureRecord->apt_def_symbol_num))
320 throw_parse_error(m_path, line, token, lineNumber);
322 if (pFeatureRecord->apt_def_symbol_num == -1)
324 if (!(lineStream >> pFeatureRecord->apt_def_resize_factor))
326 throw_parse_error(m_path, line, token, lineNumber);
332 if (pFeatureRecord->apt_def_symbol_num >= 0 && pFeatureRecord->sym_num == -1)
334 pFeatureRecord->sym_num = pFeatureRecord->apt_def_symbol_num;
338 if (!(lineStream >> polarity))
340 throw_parse_error(m_path, line, token, lineNumber);
345 pFeatureRecord->polarity = Polarity::Positive;
348 pFeatureRecord->polarity = Polarity::Negative;
351 throw_parse_error(m_path, line, token, lineNumber);
354 if (!(lineStream >> pFeatureRecord->dcode))
356 throw_parse_error(m_path, line, token, lineNumber);
359 if (!(lineStream >> pFeatureRecord->orient_def))
361 throw_parse_error(m_path, line, token, lineNumber);
364 std::string attrIdString;
365 lineStream >> attrIdString;
367 if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
369 throw_parse_error(m_path, line, token, lineNumber);
372 m_featureRecords.push_back(pFeatureRecord);
374 else if (line.find(FeatureRecord::TEXT_TOKEN) == 0)
377 if (!(lineStream >> token) || token != FeatureRecord::TEXT_TOKEN)
379 throw_parse_error(m_path, line, token, lineNumber);
382 auto pFeatureRecord = std::make_shared<FeatureRecord>();
383 pFeatureRecord->type = FeatureRecord::Type::Text;
385 if (!(lineStream >> pFeatureRecord->x))
387 throw_parse_error(m_path, line, token, lineNumber);
390 if (!(lineStream >> pFeatureRecord->y))
392 throw_parse_error(m_path, line, token, lineNumber);
395 if (!(lineStream >> pFeatureRecord->font))
397 throw_parse_error(m_path, line, token, lineNumber);
401 if (!(lineStream >> polarity))
403 throw_parse_error(m_path, line, token, lineNumber);
408 pFeatureRecord->polarity = Polarity::Positive;
411 pFeatureRecord->polarity = Polarity::Negative;
414 throw_parse_error(m_path, line, token, lineNumber);
417 if (!(lineStream >> pFeatureRecord->orient_def))
419 throw_parse_error(m_path, line, token, lineNumber);
422 if (pFeatureRecord->orient_def == 8 ||
423 pFeatureRecord->orient_def == 9)
425 if (!(lineStream >> pFeatureRecord->orient_def_rotation))
427 throw_parse_error(m_path, line, token, lineNumber);
431 if (!(lineStream >> pFeatureRecord->xsize))
433 throw_parse_error(m_path, line, token, lineNumber);
436 if (!(lineStream >> pFeatureRecord->ysize))
438 throw_parse_error(m_path, line, token, lineNumber);
441 if (!(lineStream >> pFeatureRecord->width_factor))
443 throw_parse_error(m_path, line, token, lineNumber);
446 if (!(lineStream >> std::quoted(pFeatureRecord->text,
'\'')))
448 throw_parse_error(m_path, line, token, lineNumber);
451 if (!(lineStream >> pFeatureRecord->version))
453 throw_parse_error(m_path, line, token, lineNumber);
456 std::string attrIdString;
457 lineStream >> attrIdString;
459 if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
461 throw_parse_error(m_path, line, token, lineNumber);
464 m_featureRecords.push_back(pFeatureRecord);
466 else if (line.find(FeatureRecord::ARC_TOKEN) == 0)
469 if (!(lineStream >> token) || token != FeatureRecord::ARC_TOKEN)
471 throw_parse_error(m_path, line, token, lineNumber);
474 auto pFeatureRecord = std::make_shared<FeatureRecord>();
475 pFeatureRecord->type = FeatureRecord::Type::Arc;
477 if (!(lineStream >> pFeatureRecord->xs))
479 throw_parse_error(m_path, line, token, lineNumber);
482 if (!(lineStream >> pFeatureRecord->ys))
484 throw_parse_error(m_path, line, token, lineNumber);
487 if (!(lineStream >> pFeatureRecord->xe))
489 throw_parse_error(m_path, line, token, lineNumber);
492 if (!(lineStream >> pFeatureRecord->ye))
494 throw_parse_error(m_path, line, token, lineNumber);
497 if (!(lineStream >> pFeatureRecord->xc))
499 throw_parse_error(m_path, line, token, lineNumber);
502 if (!(lineStream >> pFeatureRecord->yc))
504 throw_parse_error(m_path, line, token, lineNumber);
507 if (!(lineStream >> pFeatureRecord->sym_num))
509 throw_parse_error(m_path, line, token, lineNumber);
513 if (!(lineStream >> polarity))
515 throw_parse_error(m_path, line, token, lineNumber);
520 pFeatureRecord->polarity = Polarity::Positive;
523 pFeatureRecord->polarity = Polarity::Negative;
526 throw_parse_error(m_path, line, token, lineNumber);
529 if (!(lineStream >> pFeatureRecord->dcode))
531 throw_parse_error(m_path, line, token, lineNumber);
535 if (!(lineStream >> cw))
537 throw_parse_error(m_path, line, token, lineNumber);
542 pFeatureRecord->cw =
true;
545 pFeatureRecord->cw =
false;
548 throw_parse_error(m_path, line, token, lineNumber);
551 std::string attrIdString;
552 lineStream >> attrIdString;
554 if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
556 throw_parse_error(m_path, line, token, lineNumber);
559 m_featureRecords.push_back(pFeatureRecord);
561 else if (line.find(FeatureRecord::BARCODE_TOKEN) == 0)
564 if (!(lineStream >> token) || token != FeatureRecord::BARCODE_TOKEN)
566 throw_parse_error(m_path, line, token, lineNumber);
569 auto pFeatureRecord = std::make_shared<FeatureRecord>();
570 pFeatureRecord->type = FeatureRecord::Type::Barcode;
582 m_featureRecords.push_back(pFeatureRecord);
584 else if (line.find(FeatureRecord::SURFACE_START_TOKEN) == 0 &&
585 line.size() > 1 && line[1] ==
' ')
588 if (!(lineStream >> token) || token != FeatureRecord::SURFACE_START_TOKEN)
590 throw_parse_error(m_path, line, token, lineNumber);
593 pCurrentFeatureRecord = std::make_shared<FeatureRecord>();
594 pCurrentFeatureRecord->type = FeatureRecord::Type::Surface;
597 if (!(lineStream >> polarity))
599 throw_parse_error(m_path, line, token, lineNumber);
604 pCurrentFeatureRecord->polarity = Polarity::Positive;
607 pCurrentFeatureRecord->polarity = Polarity::Negative;
610 throw_parse_error(m_path, line, token, lineNumber);
613 if (!(lineStream >> pCurrentFeatureRecord->dcode))
615 throw_parse_error(m_path, line, token, lineNumber);
618 std::string attrIdString;
619 lineStream >> attrIdString;
621 if (!pCurrentFeatureRecord->ParseAttributeLookupTable(attrIdString))
623 throw_parse_error(m_path, line, token, lineNumber);
626 else if (line.find(FeatureRecord::SURFACE_END_TOKEN) == 0)
629 if (!(lineStream >> token) || token != FeatureRecord::SURFACE_END_TOKEN)
631 throw_parse_error(m_path, line, token, lineNumber);
634 if (pCurrentFeatureRecord !=
nullptr)
636 m_featureRecords.push_back(pCurrentFeatureRecord);
637 pCurrentFeatureRecord.reset();
641 throw_parse_error(m_path, line, token, lineNumber);
644 else if (line.find(ContourPolygon::BEGIN_RECORD_TOKEN) == 0)
647 if (!(lineStream >> token))
649 throw_parse_error(m_path, line, token, lineNumber);
652 if (token != ContourPolygon::BEGIN_RECORD_TOKEN)
654 throw_parse_error(m_path, line, token, lineNumber);
657 pCurrentContourPolygon = std::make_shared<ContourPolygon>();
659 if (!(lineStream >> pCurrentContourPolygon->xStart))
661 throw_parse_error(m_path, line, token, lineNumber);
664 if (!(lineStream >> pCurrentContourPolygon->yStart))
666 throw_parse_error(m_path, line, token, lineNumber);
669 if (!(lineStream >> token))
671 throw_parse_error(m_path, line, token, lineNumber);
674 if (token == ContourPolygon::ISLAND_TYPE_TOKEN)
676 pCurrentContourPolygon->type = ContourPolygon::Type::Island;
678 else if (token == ContourPolygon::HOLE_TYPE_TOKEN)
680 pCurrentContourPolygon->type = ContourPolygon::Type::Hole;
684 throw_parse_error(m_path, line, token, lineNumber);
687 else if (line.find(ContourPolygon::END_RECORD_TOKEN) == 0)
690 if (!(lineStream >> token))
692 throw_parse_error(m_path, line, token, lineNumber);
695 if (token != ContourPolygon::END_RECORD_TOKEN)
697 throw_parse_error(m_path, line, token, lineNumber);
700 if (pCurrentFeatureRecord !=
nullptr)
702 pCurrentFeatureRecord->m_contourPolygons.push_back(pCurrentContourPolygon);
703 pCurrentContourPolygon.reset();
707 throw_parse_error(m_path, line, token, lineNumber);
710 else if (line.find(ContourPolygon::PolygonPart::ARC_RECORD_TOKEN) == 0)
713 if (!(lineStream >> token))
715 throw_parse_error(m_path, line, token, lineNumber);
718 if (token != ContourPolygon::PolygonPart::ARC_RECORD_TOKEN)
720 throw_parse_error(m_path, line, token, lineNumber);
723 auto pPolygonPart = std::make_shared<ContourPolygon::PolygonPart>();
724 pPolygonPart->type = ContourPolygon::PolygonPart::Type::Arc;
726 if (!(lineStream >> pPolygonPart->endX))
728 throw_parse_error(m_path, line, token, lineNumber);
731 if (!(lineStream >> pPolygonPart->endY))
733 throw_parse_error(m_path, line, token, lineNumber);
736 if (!(lineStream >> pPolygonPart->xCenter))
738 throw_parse_error(m_path, line, token, lineNumber);
741 if (!(lineStream >> pPolygonPart->yCenter))
743 throw_parse_error(m_path, line, token, lineNumber);
746 if (!(lineStream >> token))
748 throw_parse_error(m_path, line, token, lineNumber);
751 if (token ==
"y" || token ==
"Y")
753 pPolygonPart->isClockwise =
true;
755 else if (token ==
"n" || token ==
"N")
757 pPolygonPart->isClockwise =
false;
761 throw_parse_error(m_path, line, token, lineNumber);
764 if (pCurrentContourPolygon !=
nullptr)
766 pCurrentContourPolygon->m_polygonParts.push_back(pPolygonPart);
770 throw_parse_error(m_path, line, token, lineNumber);
773 else if (line.find(ContourPolygon::PolygonPart::SEGMENT_RECORD_TOKEN) == 0)
776 if (!(lineStream >> token))
778 throw_parse_error(m_path, line, token, lineNumber);
781 if (token != ContourPolygon::PolygonPart::SEGMENT_RECORD_TOKEN)
783 throw_parse_error(m_path, line, token, lineNumber);
786 auto pPolygonPart = std::make_shared<ContourPolygon::PolygonPart>();
787 pPolygonPart->type = ContourPolygon::PolygonPart::Type::Segment;
789 if (!(lineStream >> pPolygonPart->endX))
791 throw_parse_error(m_path, line, token, lineNumber);
794 if (!(lineStream >> pPolygonPart->endY))
796 throw_parse_error(m_path, line, token, lineNumber);
799 if (pCurrentContourPolygon !=
nullptr)
801 pCurrentContourPolygon->m_polygonParts.push_back(pPolygonPart);
805 throw_parse_error(m_path, line, token, lineNumber);
811 parse_info pi(m_path, line, lineNumber);
812 logwarn(pi.toString(
"unrecognized record line in features file:"));
818 if (pCurrentFeatureRecord !=
nullptr)
821 m_featureRecords.push_back(pCurrentFeatureRecord);
822 pCurrentFeatureRecord.reset();
825 featuresFile.close();
827 catch (parse_error &pe)
829 auto m = pe.toString(
"Parse Error:");
831 featuresFile.close();
834 catch (std::exception &e)
836 parse_info pi(m_path, line, lineNumber);
837 const auto m = pi.toString();
838 logexception_msg(e, m);
839 featuresFile.close();
846 std::string FeaturesFile::GetUnits()
const
851 std::filesystem::path FeaturesFile::GetPath()
856 std::filesystem::path FeaturesFile::GetDirectory()
861 int FeaturesFile::GetNumFeatures()
const
863 return m_numFeatures;
866 unsigned int FeaturesFile::GetId()
const
871 const SymbolName::StringMap &FeaturesFile::GetSymbolNamesByName()
const
873 return m_symbolNamesByName;
876 const SymbolName::Vector &FeaturesFile::GetSymbolNames()
const
878 return m_symbolNames;
881 const FeaturesFile::FeatureRecord::Vector &FeaturesFile::GetFeatureRecords()
const
883 return m_featureRecords;
886 std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile> FeaturesFile::to_protobuf()
const
888 std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile> pFeaturesFileMessage(
new Odb::Lib::Protobuf::FeaturesFile);
889 pFeaturesFileMessage->set_id(m_id);
890 pFeaturesFileMessage->set_numfeatures(m_numFeatures);
891 pFeaturesFileMessage->set_units(Odb::Lib::Text::ToUtf8(m_units));
892 for (
const auto &pFeatureRecord : m_featureRecords)
894 pFeaturesFileMessage->add_featurerecords()->CopyFrom(*pFeatureRecord->to_protobuf());
896 for (
const auto &kvSymbolName : m_symbolNamesByName)
898 (*pFeaturesFileMessage->mutable_symbolnamesbyname())[Odb::Lib::Text::ToUtf8(kvSymbolName.first)] = *kvSymbolName.second->to_protobuf();
900 for (
const auto &symbolName : m_symbolNames)
902 pFeaturesFileMessage->add_symbolnames()->CopyFrom(*symbolName->to_protobuf());
904 return pFeaturesFileMessage;
907 void FeaturesFile::from_protobuf(
const Odb::Lib::Protobuf::FeaturesFile &message)
910 m_numFeatures = message.numfeatures();
911 m_units = message.units();
912 for (
const auto &featureRecordMessage : message.featurerecords())
914 std::shared_ptr<FeatureRecord> pFeatureRecord(
new FeatureRecord);
915 pFeatureRecord->from_protobuf(featureRecordMessage);
916 m_featureRecords.push_back(pFeatureRecord);
918 if (message.symbolnames().size() > 0)
921 for (
const auto &symbolNameMessage : message.symbolnames())
923 auto pSymbolName = std::make_shared<SymbolName>();
924 pSymbolName->from_protobuf(symbolNameMessage);
925 m_symbolNames.push_back(pSymbolName);
926 m_symbolNamesByName[pSymbolName->GetName()] = pSymbolName;
929 else if (message.symbolnamesbyname().size() > 0)
932 for (
const auto &kvSymbolNameMessage : message.symbolnamesbyname())
934 auto pSymbolName = std::make_shared<SymbolName>();
935 pSymbolName->from_protobuf(kvSymbolNameMessage.second);
936 m_symbolNamesByName[kvSymbolNameMessage.first] = pSymbolName;
937 m_symbolNames.push_back(pSymbolName);
942 bool FeaturesFile::Save(std::ostream &os)
947 FeaturesFile::FeatureRecord::~FeatureRecord()
949 m_contourPolygons.clear();
952 const ContourPolygon::Vector &FeaturesFile::FeatureRecord::GetContourPolygons()
const
954 return m_contourPolygons;
957 std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile::FeatureRecord> Odb::Lib::FileModel::Design::FeaturesFile::FeatureRecord::to_protobuf()
const
959 std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile::FeatureRecord> pFeatureRecordMessage(
new Odb::Lib::Protobuf::FeaturesFile::FeatureRecord);
960 pFeatureRecordMessage->set_apt_def_resize_factor(apt_def_resize_factor);
961 pFeatureRecordMessage->set_xc(xc);
962 pFeatureRecordMessage->set_yc(yc);
963 pFeatureRecordMessage->set_cw(cw);
964 pFeatureRecordMessage->set_font(Odb::Lib::Text::ToUtf8(font));
965 pFeatureRecordMessage->set_xsize(xsize);
966 pFeatureRecordMessage->set_ysize(ysize);
967 pFeatureRecordMessage->set_width_factor(width_factor);
968 pFeatureRecordMessage->set_text(Odb::Lib::Text::ToUtf8(text));
969 pFeatureRecordMessage->set_version(version);
972 pFeatureRecordMessage->set_sym_num(sym_num);
974 pFeatureRecordMessage->set_polarity(
static_cast<Odb::Lib::Protobuf::Polarity
>(polarity));
975 pFeatureRecordMessage->set_dcode(dcode);
976 pFeatureRecordMessage->set_id(
id);
977 pFeatureRecordMessage->set_orient_def(orient_def);
978 pFeatureRecordMessage->set_orient_def_rotation(orient_def_rotation);
979 pFeatureRecordMessage->set_type(
static_cast<Odb::Lib::Protobuf::FeaturesFile::FeatureRecord::Type
>(type));
980 pFeatureRecordMessage->set_xs(xs);
981 pFeatureRecordMessage->set_ys(ys);
982 pFeatureRecordMessage->set_xe(xe);
983 pFeatureRecordMessage->set_ye(ye);
984 pFeatureRecordMessage->set_x(x);
985 pFeatureRecordMessage->set_y(y);
986 if (apt_def_symbol_num >= 0)
988 pFeatureRecordMessage->set_apt_def_symbol_num(apt_def_symbol_num);
990 for (
const auto &pContourPolygon : m_contourPolygons)
992 pFeatureRecordMessage->add_contourpolygons()->CopyFrom(*pContourPolygon->to_protobuf());
994 for (
const auto &kvAttributeAssignment : m_attributeLookupTable)
996 (*pFeatureRecordMessage->mutable_attributelookuptable())[Odb::Lib::Text::ToUtf8(kvAttributeAssignment.first)] =
Odb::Lib::Text::ToUtf8(kvAttributeAssignment.second);
998 return pFeatureRecordMessage;
1001 void Odb::Lib::FileModel::Design::FeaturesFile::FeatureRecord::from_protobuf(
const Odb::Lib::Protobuf::FeaturesFile::FeatureRecord &message)
1003 apt_def_resize_factor = message.apt_def_resize_factor();
1007 font = message.font();
1008 xsize = message.xsize();
1009 ysize = message.ysize();
1010 width_factor = message.width_factor();
1011 text = message.text();
1012 version = message.version();
1013 sym_num = message.has_sym_num() ? message.sym_num() : -1;
1014 polarity =
static_cast<Polarity
>(message.polarity());
1015 dcode = message.dcode();
1017 orient_def = message.orient_def();
1018 orient_def_rotation = message.orient_def_rotation();
1019 type =
static_cast<Type
>(message.type());
1026 apt_def_symbol_num = message.has_apt_def_symbol_num() ? message.apt_def_symbol_num() : -1;
1027 for (
const auto &contourPolygonMessage : message.contourpolygons())
1029 std::shared_ptr<ContourPolygon> pContourPolygon(
new ContourPolygon);
1030 pContourPolygon->from_protobuf(contourPolygonMessage);
1031 m_contourPolygons.push_back(pContourPolygon);
1033 for (
const auto &kvAttributeAssignment : message.attributelookuptable())
1035 m_attributeLookupTable[kvAttributeAssignment.first] = kvAttributeAssignment.second;
1039 SymbolName::Vector collect_symbols(
const FeaturesFile &featuresFile)
1041 const auto &vec = featuresFile.GetSymbolNames();
1045 SymbolName::Vector collected;
1046 for (
const auto &kv : featuresFile.GetSymbolNamesByName())
1048 collected.push_back(kv.second);
1053 UnitType inferred_unit_type_from_features_units(
const std::string &rawUnits)
1055 if (rawUnits.empty())
1056 return UnitType::None;
1057 std::string u = rawUnits;
1058 std::transform(u.begin(), u.end(), u.begin(), [](
unsigned char c)
1059 { return static_cast<char>(std::tolower(c)); });
1060 if (u ==
"mm" || u ==
"millimeter" || u ==
"millimeters" || u ==
"micron" || u ==
"microns" || u ==
"um" || u ==
"µm")
1062 return UnitType::Metric;
1064 if (u ==
"inch" || u ==
"inches" || u ==
"in" || u ==
"mil" || u ==
"mils")
1066 return UnitType::Imperial;
1068 return UnitType::None;
std::string ToUtf8(std::string_view input)
Converts input to valid UTF-8.