1#include "FeaturesFile.h"
2#include "ArchiveExtractor.h"
5#include "../invalid_odb_error.h"
7#include "../parse_error.h"
9#include "equals_within.h"
15namespace Odb::Lib::FileModel::Design
19 void apply_default_units_to_symbols(
const std::string &rawUnits, SymbolName::Vector &symbols)
21 const auto inferred = Odb::Lib::FileModel::Design::inferred_unit_type_from_features_units(rawUnits);
22 if (inferred == UnitType::None)
24 for (
const auto &sym : symbols)
28 sym->ApplyDefaultUnitTypeIfNone(inferred);
34 FeaturesFile::FeaturesFile()
35 : m_path(
""), m_directory(
""), m_numFeatures(0), m_id(static_cast<unsigned>(-1))
39 FeaturesFile::~FeaturesFile()
41 m_featureRecords.clear();
42 m_attributeNames.clear();
43 m_attributeTextValues.clear();
44 m_symbolNamesByName.clear();
45 m_symbolNames.clear();
48 bool FeaturesFile::Parse(std::filesystem::path directory,
const std::string &alternateFilename )
50 std::ifstream featuresFile;
56 m_directory = directory;
58 loginfo(
"checking for extraction...");
60 std::vector<std::string> filenames;
61 if (alternateFilename.empty())
63 std::copy(std::begin(FEATURES_FILENAMES), std::end(FEATURES_FILENAMES), std::back_inserter(filenames));
67 filenames.push_back(alternateFilename);
70 std::filesystem::path featuresFilePath;
71 for (
const auto &featuresFilename : filenames)
73 loginfo(
"trying features file: [" + featuresFilename +
"]...");
75 featuresFilePath = Utils::ArchiveExtractor::getUncompressedFilePath(m_directory, featuresFilename);
76 if (exists(featuresFilePath) && is_regular_file(featuresFilePath))
78 loginfo(
"found features file: [" + featuresFilePath.string() +
"]");
83 m_path = featuresFilePath;
85 loginfo(
"any extraction complete, parsing data...");
87 if (!std::filesystem::exists(m_path))
89 auto message =
"features file does not exist: [" + m_path.string() +
"]";
90 throw invalid_odb_error(message.c_str());
92 else if (!std::filesystem::is_regular_file(m_path))
94 auto message =
"features is not a file: [" + m_path.string() +
"]";
95 throw invalid_odb_error(message.c_str());
98 featuresFile.open(m_path.string(), std::ios::in);
99 if (!featuresFile.is_open())
101 auto message =
"unable to open features file: [" + m_path.string() +
"]";
102 throw invalid_odb_error(message.c_str());
105 std::shared_ptr<FeatureRecord> pCurrentFeatureRecord;
106 std::shared_ptr<ContourPolygon> pCurrentContourPolygon;
108 while (std::getline(featuresFile, line))
113 Utils::str_trim(line);
116 std::stringstream lineStream(line);
119 if (line.find(COMMENT_TOKEN) == 0)
123 else if (line.find(UNITS_TOKEN) == 0)
127 if (!std::getline(lineStream, token,
'='))
129 throw_parse_error(m_path, line, token, lineNumber);
131 else if (!std::getline(lineStream, token,
'='))
133 throw_parse_error(m_path, line, token, lineNumber);
137 apply_default_units_to_symbols(m_units, m_symbolNames);
139 else if (line.find(
"U") == 0)
142 if (!std::getline(lineStream, token,
' '))
144 throw_parse_error(m_path, line, token, lineNumber);
146 else if (!std::getline(lineStream, token,
' '))
148 throw_parse_error(m_path, line, token, lineNumber);
152 apply_default_units_to_symbols(m_units, m_symbolNames);
154 else if (line.find(ID_TOKEN) == 0)
157 if (!std::getline(lineStream, token,
'='))
159 throw_parse_error(m_path, line, token, lineNumber);
161 else if (!std::getline(lineStream, token,
'='))
163 throw_parse_error(m_path, line, token, lineNumber);
165 m_id = std::stoul(token);
167 else if (line.find(NUM_FEATURES_TOKEN) == 0)
172 if (!(lineStream >> token))
174 throw_parse_error(m_path, line, token, lineNumber);
177 if (token != NUM_FEATURES_TOKEN)
179 throw_parse_error(m_path, line, token, lineNumber);
182 if (!(lineStream >> m_numFeatures))
184 throw_parse_error(m_path, line, token, lineNumber);
187 else if (line.find(ATTRIBUTE_NAME_TOKEN) == 0)
192 if (!std::getline(lineStream, token,
' '))
194 throw_parse_error(m_path, line, token, lineNumber);
196 else if (!std::getline(lineStream, token,
' '))
198 throw_parse_error(m_path, line, token, lineNumber);
200 m_attributeNames.push_back(token);
202 else if (line.find(ATTRIBUTE_VALUE_TOKEN) == 0)
206 if (!std::getline(lineStream, token,
' '))
208 throw_parse_error(m_path, line, token, lineNumber);
210 else if (!std::getline(lineStream >> std::ws, token))
212 throw_parse_error(m_path, line, token, lineNumber);
214 m_attributeTextValues.push_back(token);
216 else if (line.find(SYMBOL_NAME_TOKEN) == 0)
219 auto pSymbolName = std::make_shared<SymbolName>();
220 if (!pSymbolName->SymbolName::Parse(m_path, line, lineNumber))
222 throw_parse_error(m_path, line,
"", lineNumber);
224 pSymbolName->ApplyDefaultUnitTypeIfNone(Odb::Lib::FileModel::Design::inferred_unit_type_from_features_units(m_units));
225 m_symbolNamesByName[pSymbolName->GetName()] = pSymbolName;
226 m_symbolNames.push_back(pSymbolName);
228 else if (line.find(FeatureRecord::LINE_TOKEN) == 0)
231 if (!(lineStream >> token) || token != FeatureRecord::LINE_TOKEN)
233 throw_parse_error(m_path, line, token, lineNumber);
236 auto pFeatureRecord = std::make_shared<FeatureRecord>();
237 pFeatureRecord->type = FeatureRecord::Type::Line;
239 if (!(lineStream >> pFeatureRecord->xs))
241 throw_parse_error(m_path, line, token, lineNumber);
244 if (!(lineStream >> pFeatureRecord->ys))
246 throw_parse_error(m_path, line, token, lineNumber);
249 if (!(lineStream >> pFeatureRecord->xe))
251 throw_parse_error(m_path, line, token, lineNumber);
254 if (!(lineStream >> pFeatureRecord->ye))
256 throw_parse_error(m_path, line, token, lineNumber);
259 if (!(lineStream >> pFeatureRecord->sym_num))
261 throw_parse_error(m_path, line, token, lineNumber);
265 if (!(lineStream >> polarity))
267 throw_parse_error(m_path, line, token, lineNumber);
272 pFeatureRecord->polarity = Polarity::Positive;
275 pFeatureRecord->polarity = Polarity::Negative;
278 throw_parse_error(m_path, line, token, lineNumber);
281 if (!(lineStream >> pFeatureRecord->dcode))
283 throw_parse_error(m_path, line, token, lineNumber);
286 std::string attrIdString;
287 lineStream >> attrIdString;
289 if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
291 throw_parse_error(m_path, line, token, lineNumber);
294 m_featureRecords.push_back(pFeatureRecord);
296 else if (line.find(FeatureRecord::PAD_TOKEN) == 0)
299 if (!(lineStream >> token) || token != FeatureRecord::PAD_TOKEN)
301 throw_parse_error(m_path, line, token, lineNumber);
304 auto pFeatureRecord = std::make_shared<FeatureRecord>();
305 pFeatureRecord->type = FeatureRecord::Type::Pad;
307 if (!(lineStream >> pFeatureRecord->x))
309 throw_parse_error(m_path, line, token, lineNumber);
312 if (!(lineStream >> pFeatureRecord->y))
314 throw_parse_error(m_path, line, token, lineNumber);
317 if (!(lineStream >> pFeatureRecord->apt_def_symbol_num))
319 throw_parse_error(m_path, line, token, lineNumber);
321 if (pFeatureRecord->apt_def_symbol_num == -1)
323 if (!(lineStream >> pFeatureRecord->apt_def_resize_factor))
325 throw_parse_error(m_path, line, token, lineNumber);
331 if (pFeatureRecord->apt_def_symbol_num >= 0 && pFeatureRecord->sym_num == -1)
333 pFeatureRecord->sym_num = pFeatureRecord->apt_def_symbol_num;
337 if (!(lineStream >> polarity))
339 throw_parse_error(m_path, line, token, lineNumber);
344 pFeatureRecord->polarity = Polarity::Positive;
347 pFeatureRecord->polarity = Polarity::Negative;
350 throw_parse_error(m_path, line, token, lineNumber);
353 if (!(lineStream >> pFeatureRecord->dcode))
355 throw_parse_error(m_path, line, token, lineNumber);
358 if (!(lineStream >> pFeatureRecord->orient_def))
360 throw_parse_error(m_path, line, token, lineNumber);
363 std::string attrIdString;
364 lineStream >> attrIdString;
366 if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
368 throw_parse_error(m_path, line, token, lineNumber);
371 m_featureRecords.push_back(pFeatureRecord);
373 else if (line.find(FeatureRecord::TEXT_TOKEN) == 0)
376 if (!(lineStream >> token) || token != FeatureRecord::TEXT_TOKEN)
378 throw_parse_error(m_path, line, token, lineNumber);
381 auto pFeatureRecord = std::make_shared<FeatureRecord>();
382 pFeatureRecord->type = FeatureRecord::Type::Text;
384 if (!(lineStream >> pFeatureRecord->x))
386 throw_parse_error(m_path, line, token, lineNumber);
389 if (!(lineStream >> pFeatureRecord->y))
391 throw_parse_error(m_path, line, token, lineNumber);
394 if (!(lineStream >> pFeatureRecord->font))
396 throw_parse_error(m_path, line, token, lineNumber);
400 if (!(lineStream >> polarity))
402 throw_parse_error(m_path, line, token, lineNumber);
407 pFeatureRecord->polarity = Polarity::Positive;
410 pFeatureRecord->polarity = Polarity::Negative;
413 throw_parse_error(m_path, line, token, lineNumber);
416 if (!(lineStream >> pFeatureRecord->orient_def))
418 throw_parse_error(m_path, line, token, lineNumber);
421 if (pFeatureRecord->orient_def == 8 ||
422 pFeatureRecord->orient_def == 9)
424 if (!(lineStream >> pFeatureRecord->orient_def_rotation))
426 throw_parse_error(m_path, line, token, lineNumber);
430 if (!(lineStream >> pFeatureRecord->xsize))
432 throw_parse_error(m_path, line, token, lineNumber);
435 if (!(lineStream >> pFeatureRecord->ysize))
437 throw_parse_error(m_path, line, token, lineNumber);
440 if (!(lineStream >> pFeatureRecord->width_factor))
442 throw_parse_error(m_path, line, token, lineNumber);
445 if (!(lineStream >> std::quoted(pFeatureRecord->text,
'\'')))
447 throw_parse_error(m_path, line, token, lineNumber);
450 if (!(lineStream >> pFeatureRecord->version))
452 throw_parse_error(m_path, line, token, lineNumber);
455 std::string attrIdString;
456 lineStream >> attrIdString;
458 if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
460 throw_parse_error(m_path, line, token, lineNumber);
463 m_featureRecords.push_back(pFeatureRecord);
465 else if (line.find(FeatureRecord::ARC_TOKEN) == 0)
468 if (!(lineStream >> token) || token != FeatureRecord::ARC_TOKEN)
470 throw_parse_error(m_path, line, token, lineNumber);
473 auto pFeatureRecord = std::make_shared<FeatureRecord>();
474 pFeatureRecord->type = FeatureRecord::Type::Arc;
476 if (!(lineStream >> pFeatureRecord->xs))
478 throw_parse_error(m_path, line, token, lineNumber);
481 if (!(lineStream >> pFeatureRecord->ys))
483 throw_parse_error(m_path, line, token, lineNumber);
486 if (!(lineStream >> pFeatureRecord->xe))
488 throw_parse_error(m_path, line, token, lineNumber);
491 if (!(lineStream >> pFeatureRecord->ye))
493 throw_parse_error(m_path, line, token, lineNumber);
496 if (!(lineStream >> pFeatureRecord->xc))
498 throw_parse_error(m_path, line, token, lineNumber);
501 if (!(lineStream >> pFeatureRecord->yc))
503 throw_parse_error(m_path, line, token, lineNumber);
506 if (!(lineStream >> pFeatureRecord->sym_num))
508 throw_parse_error(m_path, line, token, lineNumber);
512 if (!(lineStream >> polarity))
514 throw_parse_error(m_path, line, token, lineNumber);
519 pFeatureRecord->polarity = Polarity::Positive;
522 pFeatureRecord->polarity = Polarity::Negative;
525 throw_parse_error(m_path, line, token, lineNumber);
528 if (!(lineStream >> pFeatureRecord->dcode))
530 throw_parse_error(m_path, line, token, lineNumber);
534 if (!(lineStream >> cw))
536 throw_parse_error(m_path, line, token, lineNumber);
541 pFeatureRecord->cw =
true;
544 pFeatureRecord->cw =
false;
547 throw_parse_error(m_path, line, token, lineNumber);
550 std::string attrIdString;
551 lineStream >> attrIdString;
553 if (!pFeatureRecord->ParseAttributeLookupTable(attrIdString))
555 throw_parse_error(m_path, line, token, lineNumber);
558 m_featureRecords.push_back(pFeatureRecord);
560 else if (line.find(FeatureRecord::BARCODE_TOKEN) == 0)
563 if (!(lineStream >> token) || token != FeatureRecord::BARCODE_TOKEN)
565 throw_parse_error(m_path, line, token, lineNumber);
568 auto pFeatureRecord = std::make_shared<FeatureRecord>();
569 pFeatureRecord->type = FeatureRecord::Type::Barcode;
581 m_featureRecords.push_back(pFeatureRecord);
583 else if (line.find(FeatureRecord::SURFACE_START_TOKEN) == 0 &&
584 line.size() > 1 && line[1] ==
' ')
587 if (!(lineStream >> token) || token != FeatureRecord::SURFACE_START_TOKEN)
589 throw_parse_error(m_path, line, token, lineNumber);
592 pCurrentFeatureRecord = std::make_shared<FeatureRecord>();
593 pCurrentFeatureRecord->type = FeatureRecord::Type::Surface;
596 if (!(lineStream >> polarity))
598 throw_parse_error(m_path, line, token, lineNumber);
603 pCurrentFeatureRecord->polarity = Polarity::Positive;
606 pCurrentFeatureRecord->polarity = Polarity::Negative;
609 throw_parse_error(m_path, line, token, lineNumber);
612 if (!(lineStream >> pCurrentFeatureRecord->dcode))
614 throw_parse_error(m_path, line, token, lineNumber);
617 std::string attrIdString;
618 lineStream >> attrIdString;
620 if (!pCurrentFeatureRecord->ParseAttributeLookupTable(attrIdString))
622 throw_parse_error(m_path, line, token, lineNumber);
625 else if (line.find(FeatureRecord::SURFACE_END_TOKEN) == 0)
628 if (!(lineStream >> token) || token != FeatureRecord::SURFACE_END_TOKEN)
630 throw_parse_error(m_path, line, token, lineNumber);
633 if (pCurrentFeatureRecord !=
nullptr)
635 m_featureRecords.push_back(pCurrentFeatureRecord);
636 pCurrentFeatureRecord.reset();
640 throw_parse_error(m_path, line, token, lineNumber);
643 else if (line.find(ContourPolygon::BEGIN_RECORD_TOKEN) == 0)
646 if (!(lineStream >> token))
648 throw_parse_error(m_path, line, token, lineNumber);
651 if (token != ContourPolygon::BEGIN_RECORD_TOKEN)
653 throw_parse_error(m_path, line, token, lineNumber);
656 pCurrentContourPolygon = std::make_shared<ContourPolygon>();
658 if (!(lineStream >> pCurrentContourPolygon->xStart))
660 throw_parse_error(m_path, line, token, lineNumber);
663 if (!(lineStream >> pCurrentContourPolygon->yStart))
665 throw_parse_error(m_path, line, token, lineNumber);
668 if (!(lineStream >> token))
670 throw_parse_error(m_path, line, token, lineNumber);
673 if (token == ContourPolygon::ISLAND_TYPE_TOKEN)
675 pCurrentContourPolygon->type = ContourPolygon::Type::Island;
677 else if (token == ContourPolygon::HOLE_TYPE_TOKEN)
679 pCurrentContourPolygon->type = ContourPolygon::Type::Hole;
683 throw_parse_error(m_path, line, token, lineNumber);
686 else if (line.find(ContourPolygon::END_RECORD_TOKEN) == 0)
689 if (!(lineStream >> token))
691 throw_parse_error(m_path, line, token, lineNumber);
694 if (token != ContourPolygon::END_RECORD_TOKEN)
696 throw_parse_error(m_path, line, token, lineNumber);
699 if (pCurrentFeatureRecord !=
nullptr)
701 pCurrentFeatureRecord->m_contourPolygons.push_back(pCurrentContourPolygon);
702 pCurrentContourPolygon.reset();
706 throw_parse_error(m_path, line, token, lineNumber);
709 else if (line.find(ContourPolygon::PolygonPart::ARC_RECORD_TOKEN) == 0)
712 if (!(lineStream >> token))
714 throw_parse_error(m_path, line, token, lineNumber);
717 if (token != ContourPolygon::PolygonPart::ARC_RECORD_TOKEN)
719 throw_parse_error(m_path, line, token, lineNumber);
722 auto pPolygonPart = std::make_shared<ContourPolygon::PolygonPart>();
723 pPolygonPart->type = ContourPolygon::PolygonPart::Type::Arc;
725 if (!(lineStream >> pPolygonPart->endX))
727 throw_parse_error(m_path, line, token, lineNumber);
730 if (!(lineStream >> pPolygonPart->endY))
732 throw_parse_error(m_path, line, token, lineNumber);
735 if (!(lineStream >> pPolygonPart->xCenter))
737 throw_parse_error(m_path, line, token, lineNumber);
740 if (!(lineStream >> pPolygonPart->yCenter))
742 throw_parse_error(m_path, line, token, lineNumber);
745 if (!(lineStream >> token))
747 throw_parse_error(m_path, line, token, lineNumber);
750 if (token ==
"y" || token ==
"Y")
752 pPolygonPart->isClockwise =
true;
754 else if (token ==
"n" || token ==
"N")
756 pPolygonPart->isClockwise =
false;
760 throw_parse_error(m_path, line, token, lineNumber);
763 if (pCurrentContourPolygon !=
nullptr)
765 pCurrentContourPolygon->m_polygonParts.push_back(pPolygonPart);
769 throw_parse_error(m_path, line, token, lineNumber);
772 else if (line.find(ContourPolygon::PolygonPart::SEGMENT_RECORD_TOKEN) == 0)
775 if (!(lineStream >> token))
777 throw_parse_error(m_path, line, token, lineNumber);
780 if (token != ContourPolygon::PolygonPart::SEGMENT_RECORD_TOKEN)
782 throw_parse_error(m_path, line, token, lineNumber);
785 auto pPolygonPart = std::make_shared<ContourPolygon::PolygonPart>();
786 pPolygonPart->type = ContourPolygon::PolygonPart::Type::Segment;
788 if (!(lineStream >> pPolygonPart->endX))
790 throw_parse_error(m_path, line, token, lineNumber);
793 if (!(lineStream >> pPolygonPart->endY))
795 throw_parse_error(m_path, line, token, lineNumber);
798 if (pCurrentContourPolygon !=
nullptr)
800 pCurrentContourPolygon->m_polygonParts.push_back(pPolygonPart);
804 throw_parse_error(m_path, line, token, lineNumber);
810 parse_info pi(m_path, line, lineNumber);
811 logwarn(pi.toString(
"unrecognized record line in features file:"));
817 if (pCurrentFeatureRecord !=
nullptr)
820 m_featureRecords.push_back(pCurrentFeatureRecord);
821 pCurrentFeatureRecord.reset();
824 featuresFile.close();
826 catch (parse_error &pe)
828 auto m = pe.toString(
"Parse Error:");
830 featuresFile.close();
833 catch (std::exception &e)
835 parse_info pi(m_path, line, lineNumber);
836 const auto m = pi.toString();
837 logexception_msg(e, m);
838 featuresFile.close();
845 std::string FeaturesFile::GetUnits()
const
850 std::filesystem::path FeaturesFile::GetPath()
855 std::filesystem::path FeaturesFile::GetDirectory()
860 int FeaturesFile::GetNumFeatures()
const
862 return m_numFeatures;
865 unsigned int FeaturesFile::GetId()
const
870 const SymbolName::StringMap &FeaturesFile::GetSymbolNamesByName()
const
872 return m_symbolNamesByName;
875 const SymbolName::Vector &FeaturesFile::GetSymbolNames()
const
877 return m_symbolNames;
880 const FeaturesFile::FeatureRecord::Vector &FeaturesFile::GetFeatureRecords()
const
882 return m_featureRecords;
885 std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile> FeaturesFile::to_protobuf()
const
887 std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile> pFeaturesFileMessage(
new Odb::Lib::Protobuf::FeaturesFile);
888 pFeaturesFileMessage->set_id(m_id);
889 pFeaturesFileMessage->set_numfeatures(m_numFeatures);
890 pFeaturesFileMessage->set_units(m_units);
891 for (
const auto &pFeatureRecord : m_featureRecords)
893 pFeaturesFileMessage->add_featurerecords()->CopyFrom(*pFeatureRecord->to_protobuf());
895 for (
const auto &kvSymbolName : m_symbolNamesByName)
897 (*pFeaturesFileMessage->mutable_symbolnamesbyname())[kvSymbolName.first] = *kvSymbolName.second->to_protobuf();
899 for (
const auto &symbolName : m_symbolNames)
901 pFeaturesFileMessage->add_symbolnames()->CopyFrom(*symbolName->to_protobuf());
903 return pFeaturesFileMessage;
906 void FeaturesFile::from_protobuf(
const Odb::Lib::Protobuf::FeaturesFile &message)
909 m_numFeatures = message.numfeatures();
910 m_units = message.units();
911 for (
const auto &featureRecordMessage : message.featurerecords())
913 std::shared_ptr<FeatureRecord> pFeatureRecord(
new FeatureRecord);
914 pFeatureRecord->from_protobuf(featureRecordMessage);
915 m_featureRecords.push_back(pFeatureRecord);
917 if (message.symbolnames().size() > 0)
920 for (
const auto &symbolNameMessage : message.symbolnames())
922 auto pSymbolName = std::make_shared<SymbolName>();
923 pSymbolName->from_protobuf(symbolNameMessage);
924 m_symbolNames.push_back(pSymbolName);
925 m_symbolNamesByName[pSymbolName->GetName()] = pSymbolName;
928 else if (message.symbolnamesbyname().size() > 0)
931 for (
const auto &kvSymbolNameMessage : message.symbolnamesbyname())
933 auto pSymbolName = std::make_shared<SymbolName>();
934 pSymbolName->from_protobuf(kvSymbolNameMessage.second);
935 m_symbolNamesByName[kvSymbolNameMessage.first] = pSymbolName;
936 m_symbolNames.push_back(pSymbolName);
941 bool FeaturesFile::Save(std::ostream &os)
946 FeaturesFile::FeatureRecord::~FeatureRecord()
948 m_contourPolygons.clear();
951 const ContourPolygon::Vector &FeaturesFile::FeatureRecord::GetContourPolygons()
const
953 return m_contourPolygons;
956 std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile::FeatureRecord> Odb::Lib::FileModel::Design::FeaturesFile::FeatureRecord::to_protobuf()
const
958 std::unique_ptr<Odb::Lib::Protobuf::FeaturesFile::FeatureRecord> pFeatureRecordMessage(
new Odb::Lib::Protobuf::FeaturesFile::FeatureRecord);
959 pFeatureRecordMessage->set_apt_def_resize_factor(apt_def_resize_factor);
960 pFeatureRecordMessage->set_xc(xc);
961 pFeatureRecordMessage->set_yc(yc);
962 pFeatureRecordMessage->set_cw(cw);
963 pFeatureRecordMessage->set_font(font);
964 pFeatureRecordMessage->set_xsize(xsize);
965 pFeatureRecordMessage->set_ysize(ysize);
966 pFeatureRecordMessage->set_width_factor(width_factor);
967 pFeatureRecordMessage->set_text(text);
968 pFeatureRecordMessage->set_version(version);
971 pFeatureRecordMessage->set_sym_num(sym_num);
973 pFeatureRecordMessage->set_polarity(
static_cast<Odb::Lib::Protobuf::Polarity
>(polarity));
974 pFeatureRecordMessage->set_dcode(dcode);
975 pFeatureRecordMessage->set_id(
id);
976 pFeatureRecordMessage->set_orient_def(orient_def);
977 pFeatureRecordMessage->set_orient_def_rotation(orient_def_rotation);
978 pFeatureRecordMessage->set_type(
static_cast<Odb::Lib::Protobuf::FeaturesFile::FeatureRecord::Type
>(type));
979 pFeatureRecordMessage->set_xs(xs);
980 pFeatureRecordMessage->set_ys(ys);
981 pFeatureRecordMessage->set_xe(xe);
982 pFeatureRecordMessage->set_ye(ye);
983 pFeatureRecordMessage->set_x(x);
984 pFeatureRecordMessage->set_y(y);
985 if (apt_def_symbol_num >= 0)
987 pFeatureRecordMessage->set_apt_def_symbol_num(apt_def_symbol_num);
989 for (
const auto &pContourPolygon : m_contourPolygons)
991 pFeatureRecordMessage->add_contourpolygons()->CopyFrom(*pContourPolygon->to_protobuf());
993 for (
const auto &kvAttributeAssignment : m_attributeLookupTable)
995 (*pFeatureRecordMessage->mutable_attributelookuptable())[kvAttributeAssignment.first] = kvAttributeAssignment.second;
997 return pFeatureRecordMessage;
1000 void Odb::Lib::FileModel::Design::FeaturesFile::FeatureRecord::from_protobuf(
const Odb::Lib::Protobuf::FeaturesFile::FeatureRecord &message)
1002 apt_def_resize_factor = message.apt_def_resize_factor();
1006 font = message.font();
1007 xsize = message.xsize();
1008 ysize = message.ysize();
1009 width_factor = message.width_factor();
1010 text = message.text();
1011 version = message.version();
1012 sym_num = message.has_sym_num() ? message.sym_num() : -1;
1013 polarity =
static_cast<Polarity
>(message.polarity());
1014 dcode = message.dcode();
1016 orient_def = message.orient_def();
1017 orient_def_rotation = message.orient_def_rotation();
1018 type =
static_cast<Type
>(message.type());
1025 apt_def_symbol_num = message.has_apt_def_symbol_num() ? message.apt_def_symbol_num() : -1;
1026 for (
const auto &contourPolygonMessage : message.contourpolygons())
1028 std::shared_ptr<ContourPolygon> pContourPolygon(
new ContourPolygon);
1029 pContourPolygon->from_protobuf(contourPolygonMessage);
1030 m_contourPolygons.push_back(pContourPolygon);
1032 for (
const auto &kvAttributeAssignment : message.attributelookuptable())
1034 m_attributeLookupTable[kvAttributeAssignment.first] = kvAttributeAssignment.second;
1038 SymbolName::Vector collect_symbols(
const FeaturesFile &featuresFile)
1040 const auto &vec = featuresFile.GetSymbolNames();
1044 SymbolName::Vector collected;
1045 for (
const auto &kv : featuresFile.GetSymbolNamesByName())
1047 collected.push_back(kv.second);
1052 UnitType inferred_unit_type_from_features_units(
const std::string &rawUnits)
1054 if (rawUnits.empty())
1055 return UnitType::None;
1056 std::string u = rawUnits;
1057 std::transform(u.begin(), u.end(), u.begin(), [](
unsigned char c)
1058 { return static_cast<char>(std::tolower(c)); });
1059 if (u ==
"mm" || u ==
"millimeter" || u ==
"millimeters" || u ==
"micron" || u ==
"microns" || u ==
"um" || u ==
"µm")
1061 return UnitType::Metric;
1063 if (u ==
"inch" || u ==
"inches" || u ==
"in" || u ==
"mil" || u ==
"mils")
1065 return UnitType::Imperial;
1067 return UnitType::None;