From 1e30d1a999e71e59af5c51486834539e05191393 Mon Sep 17 00:00:00 2001 From: "michael.l.walker" Date: Fri, 12 Apr 2024 22:05:51 -0700 Subject: [PATCH 1/5] Fix 2 crashes: Removing all occurrences reaching end of linked list, and reallocating uninitialized array items pointer --- include/gdstk/array.hpp | 2 +- src/property.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/gdstk/array.hpp b/include/gdstk/array.hpp index a8bf2272f..a5a23f36a 100644 --- a/include/gdstk/array.hpp +++ b/include/gdstk/array.hpp @@ -29,7 +29,7 @@ template struct Array { uint64_t capacity; // allocated capacity uint64_t count; // number of slots used - T* items; // slots + T* items=NULL; // slots T& operator[](uint64_t idx) { return items[idx]; } const T& operator[](uint64_t idx) const { return items[idx]; } diff --git a/src/property.cpp b/src/property.cpp index 8f73b11a1..9d5c19a9b 100644 --- a/src/property.cpp +++ b/src/property.cpp @@ -239,7 +239,7 @@ void set_gds_property(Property*& properties, uint16_t attribute, const char* val uint64_t remove_property(Property*& properties, const char* name, bool all_occurences) { uint64_t removed = 0; if (properties == NULL) return removed; - while (strcmp(properties->name, name) == 0) { + while (properties != NULL && strcmp(properties->name, name) == 0) { property_values_clear(properties->value); free_allocation(properties->name); Property* next = properties->next; @@ -248,6 +248,7 @@ uint64_t remove_property(Property*& properties, const char* name, bool all_occur removed++; if (!all_occurences) return removed; } + if (properties == NULL) return removed; Property* property = properties; while (true) { while (property->next && strcmp(property->next->name, name) != 0) property = property->next; From 0fc344047c6301721409244acd55df46fa0dac57 Mon Sep 17 00:00:00 2001 From: "Michael L. Walker" <1370092+walkerstop@users.noreply.github.com> Date: Fri, 12 Apr 2024 22:10:22 -0700 Subject: [PATCH 2/5] Update array.hpp fix spacing --- include/gdstk/array.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gdstk/array.hpp b/include/gdstk/array.hpp index a5a23f36a..3c31f09b7 100644 --- a/include/gdstk/array.hpp +++ b/include/gdstk/array.hpp @@ -29,7 +29,7 @@ template struct Array { uint64_t capacity; // allocated capacity uint64_t count; // number of slots used - T* items=NULL; // slots + T* items=NULL; // slots T& operator[](uint64_t idx) { return items[idx]; } const T& operator[](uint64_t idx) const { return items[idx]; } From 38b3ba6d00689ff22d9dcd91b8009c6d1497e4f3 Mon Sep 17 00:00:00 2001 From: "Michael L. Walker" <1370092+walkerstop@users.noreply.github.com> Date: Fri, 12 Apr 2024 22:15:19 -0700 Subject: [PATCH 3/5] Update array.hpp --- include/gdstk/array.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/gdstk/array.hpp b/include/gdstk/array.hpp index 3c31f09b7..5428a9fd1 100644 --- a/include/gdstk/array.hpp +++ b/include/gdstk/array.hpp @@ -27,9 +27,9 @@ namespace gdstk { template struct Array { - uint64_t capacity; // allocated capacity - uint64_t count; // number of slots used - T* items=NULL; // slots + uint64_t capacity = 0; // allocated capacity + uint64_t count = 0; // number of slots used + T* items = NULL; // slots T& operator[](uint64_t idx) { return items[idx]; } const T& operator[](uint64_t idx) const { return items[idx]; } From 45d0edfa181219cea47c1fe8e96030ec331eaae7 Mon Sep 17 00:00:00 2001 From: "Michael L. Walker" Date: Thu, 19 Dec 2024 02:45:06 -0700 Subject: [PATCH 4/5] Add support for .gds.gz files and shape and label tag filters in read_oas() --- include/gdstk/array.hpp | 80 +++- include/gdstk/cell.hpp | 6 +- include/gdstk/flexpath.hpp | 2 + include/gdstk/gdsii.hpp | 2 +- include/gdstk/library.hpp | 26 +- include/gdstk/oasis.hpp | 21 +- include/gdstk/polygon.hpp | 26 + include/gdstk/rawcell.hpp | 12 +- include/gdstk/reference.hpp | 6 +- include/gdstk/repetition.hpp | 40 +- include/gdstk/robustpath.hpp | 43 ++ include/gdstk/utils.hpp | 75 +++ src/cell.cpp | 67 ++- src/flexpath.cpp | 43 +- src/gdsii.cpp | 14 +- src/library.cpp | 890 +++++++++++++++++++++++------------ src/oasis.cpp | 251 +++++++++- src/polygon.cpp | 28 +- src/rawcell.cpp | 21 +- src/reference.cpp | 34 +- src/repetition.cpp | 29 +- src/robustpath.cpp | 37 +- 22 files changed, 1349 insertions(+), 404 deletions(-) diff --git a/include/gdstk/array.hpp b/include/gdstk/array.hpp index 5428a9fd1..864834da9 100644 --- a/include/gdstk/array.hpp +++ b/include/gdstk/array.hpp @@ -27,13 +27,68 @@ namespace gdstk { template struct Array { - uint64_t capacity = 0; // allocated capacity - uint64_t count = 0; // number of slots used - T* items = NULL; // slots + uint64_t capacity; // allocated capacity + uint64_t count; // number of slots used + T* items = nullptr; // slots T& operator[](uint64_t idx) { return items[idx]; } const T& operator[](uint64_t idx) const { return items[idx]; } + ~Array() { + clear(); + } + Array() { + capacity = 0; + count = 0; + items = nullptr; + } + Array(const Array& _array) { + capacity = 0; + count = 0; + items = nullptr; + copy_from(_array); + } + + Array(Array&& _array) { + capacity = _array.capacity; + count = _array.count; + items = _array.items; + _array.items = nullptr; + _array.capacity = 0; + _array.count = 0; + } + + template + Array(Number _capacity, Number _count, T* _item) { + capacity = 0; + count = 0; + ensure_slots((std::max)((uint64_t)_capacity,(uint64_t)_count)); + if (_count == 1) { + items[0] = *_item; + } + else { + for (Number i = 0; i < _count; i++) { + items[i] = _item[i]; + } + } + } + Array& operator = (Array&& _array) { + if (this == &_array)return *this; + clear(); + capacity = _array.capacity; + count = _array.count; + items = _array.items; + _array.items = nullptr; + _array.capacity = 0; + _array.count = 0; + return *this; + } + + Array& operator = (const Array& _array) { + if (this == &_array)return *this; + copy_from(_array); + return *this; + } void print(bool all) const { printf("Array <%p>, count %" PRIu64 "/%" PRIu64 "\n", this, count, capacity); if (all && count > 0) { @@ -45,10 +100,13 @@ struct Array { } } - void clear() { - if (items) free_allocation(items); - items = NULL; - capacity = 0; + void clear(bool deallocate = true) { + if (deallocate) + { + if (items) free_allocation(items); + items = NULL; + capacity = 0; + } count = 0; } @@ -126,6 +184,14 @@ struct Array { // The instance should be zeroed before copy_from void copy_from(const Array& src) { + if (capacity > src.count && src.count>0) { + //enought capacity to just copy + count = src.count; + memcpy(items, src.items, sizeof(T) * count); + return; + } + // need to re allocate + clear(); capacity = src.count; count = src.count; if (count > 0) { diff --git a/include/gdstk/cell.hpp b/include/gdstk/cell.hpp index b61835260..b0d432377 100644 --- a/include/gdstk/cell.hpp +++ b/include/gdstk/cell.hpp @@ -25,6 +25,7 @@ LICENSE file or #include "set.hpp" #include "style.hpp" #include "tagmap.hpp" +#include namespace gdstk { @@ -139,6 +140,8 @@ struct Cell { // is true, only polygons with the indicated tag are appended. void get_polygons(bool apply_repetitions, bool include_paths, int64_t depth, bool filter, Tag tag, Array& result) const; + void get_polygons(bool apply_repetitions, bool include_paths, int64_t depth, + std::set* _tags, Array& result) const; // Similar to get_polygons, but for paths and labels. void get_flexpaths(bool apply_repetitions, int64_t depth, bool filter, Tag tag, @@ -147,7 +150,8 @@ struct Cell { Array& result) const; void get_labels(bool apply_repetitions, int64_t depth, bool filter, Tag tag, Array& result) const; - + void get_labels(bool apply_repetitions, int64_t depth, std::set* _tags, + Array& result) const; // Insert all dependencies in result. Dependencies are cells that appear // in this cell's references. If recursive, include the whole dependency // tree (dependencies of dependencies). diff --git a/include/gdstk/flexpath.hpp b/include/gdstk/flexpath.hpp index 3fe2ebb18..2a40466c9 100644 --- a/include/gdstk/flexpath.hpp +++ b/include/gdstk/flexpath.hpp @@ -12,6 +12,7 @@ LICENSE file or #define _USE_MATH_DEFINES #include +#include #include "array.hpp" #include "curve.hpp" @@ -153,6 +154,7 @@ struct FlexPath { // Overlapping points are removed from the path before any processing is // executed. ErrorCode to_polygons(bool filter, Tag tag, Array& result); + ErrorCode to_polygons(const std::set* _tags, Array& result); // Calculate the center of an element of this path and append the resulting // curve to result. diff --git a/include/gdstk/gdsii.hpp b/include/gdstk/gdsii.hpp index 609ef8241..3a2caf831 100644 --- a/include/gdstk/gdsii.hpp +++ b/include/gdstk/gdsii.hpp @@ -100,7 +100,7 @@ double gdsii_real_to_double(uint64_t real); // Read a record and swaps only first 2 bytes (record length). The size of the // buffer must be passed in buffer_count. On return, the record length // (including header) is returned in buffer_count. -ErrorCode gdsii_read_record(FILE* in, uint8_t* buffer, uint64_t& buffer_count); +ErrorCode gdsii_read_record(FileWrapper* in, uint8_t* buffer, uint64_t& buffer_count); } // namespace gdstk diff --git a/include/gdstk/library.hpp b/include/gdstk/library.hpp index 412e34146..3d4f788dd 100644 --- a/include/gdstk/library.hpp +++ b/include/gdstk/library.hpp @@ -164,8 +164,17 @@ struct LibraryInfo { // tags will be imported. If not NULL, any errors will be reported through // error_code. Library read_gds(const char* filename, double unit, double tolerance, const Set* shape_tags, + const Set* label_tags, ErrorCode* error_code); +Library read_gds(const char* filename, double unit, double tolerance, const Set* shape_tags, + ErrorCode* error_code) +{ + return read_gds(filename, unit, tolerance, shape_tags, NULL, error_code); +} + +Library read_gds2(const char* filename, double unit, double tolerance, ErrorCode* error_code); + // Read the contents of an OASIS file into a new library. If unit is not zero, // the units in the file are converted (all elements are properly scaled to the // desired unit). The value of tolerance is used as the default tolerance for @@ -173,8 +182,21 @@ Library read_gds(const char* filename, double unit, double tolerance, const Set< // empty, only shapes in those tags will be imported. If not NULL, any errors // will be reported through error_code. Library read_oas(const char* filename, double unit, - double tolerance, // TODO: const Set* shape_tags, - ErrorCode* error_code); + double tolerance, + const Set* shape_tags, + const Set* label_tags, + ErrorCode* error_code, + Tag fub_tag, double min_fub_dimension); + +Library read_oas(const char* filename, double unit, + double tolerance, + const Set* shape_tags, + const Set* label_tags, + ErrorCode* error_code); + +Library read_oas(const char* filename, double unit, + double tolerance, + ErrorCode* error_code); // Read the unit and precision of a GDSII file and return in the respective // arguments. diff --git a/include/gdstk/oasis.hpp b/include/gdstk/oasis.hpp index 8cace5d70..f4828cbb1 100644 --- a/include/gdstk/oasis.hpp +++ b/include/gdstk/oasis.hpp @@ -18,6 +18,7 @@ LICENSE file or #include "map.hpp" #include "repetition.hpp" #include "utils.hpp" +#include "label.hpp" namespace gdstk { @@ -166,16 +167,26 @@ struct OasisState { ErrorCode oasis_read(void* buffer, size_t size, size_t count, OasisStream& in); +ErrorCode oasis_skip(size_t size, size_t count, OasisStream& in); + size_t oasis_write(const void* buffer, size_t size, size_t count, OasisStream& out); int oasis_putc(int c, OasisStream& out); uint8_t* oasis_read_string(OasisStream& in, bool append_terminating_null, uint64_t& len); +void oasis_read_string2(OasisStream& in, Label* dest, uint64_t capacity, uint64_t& count); + +ErrorCode oasis_skip_string(OasisStream& in); + uint64_t oasis_read_unsigned_integer(OasisStream& in); +ErrorCode oasis_skip_unsigned_integer(OasisStream& in); + int64_t oasis_read_integer(OasisStream& in); +ErrorCode oasis_skip_integer(OasisStream& in); + inline int64_t oasis_read_1delta(OasisStream& in) { return oasis_read_integer(in); }; void oasis_read_2delta(OasisStream& in, int64_t& x, int64_t& y); @@ -184,8 +195,12 @@ void oasis_read_3delta(OasisStream& in, int64_t& x, int64_t& y); void oasis_read_gdelta(OasisStream& in, int64_t& x, int64_t& y); +ErrorCode oasis_skip_gdelta(OasisStream& in); + double oasis_read_real_by_type(OasisStream& in, OasisDataType type); +ErrorCode oasis_skip_real_by_type(OasisStream& in, OasisDataType type); + inline double oasis_read_real(OasisStream& in) { OasisDataType type; if (oasis_read(&type, 1, 1, in) != ErrorCode::NoError) return 0; @@ -197,8 +212,12 @@ inline double oasis_read_real(OasisStream& in) { // be an implicit extra delta for Manhattan types). uint64_t oasis_read_point_list(OasisStream& in, double scaling, bool closed, Array& result); +ErrorCode oasis_skip_point_list(OasisStream& in); + void oasis_read_repetition(OasisStream& in, double scaling, Repetition& repetition); +ErrorCode oasis_skip_repetition(OasisStream& in); + void oasis_write_unsigned_integer(OasisStream& out, uint64_t value); void oasis_write_integer(OasisStream& out, int64_t value); @@ -223,7 +242,7 @@ void oasis_write_point_list(OasisStream& out, const Array points, double s bool closed); // This should only be called with repetition.get_count() > 1 -void oasis_write_repetition(OasisStream& out, const Repetition repetition, double scaling); +void oasis_write_repetition(OasisStream& out, const Repetition &repetition, double scaling); } // namespace gdstk diff --git a/include/gdstk/polygon.hpp b/include/gdstk/polygon.hpp index 4a44cd1a5..144e2d8b2 100644 --- a/include/gdstk/polygon.hpp +++ b/include/gdstk/polygon.hpp @@ -28,6 +28,32 @@ struct Polygon { Array point_array; Repetition repetition; Property* properties; + + Polygon() { properties = nullptr; } + Polygon& operator=(Polygon&& _p) { + if (this == &_p) return *this; + point_array.clear(); + repetition.clear(); + if (properties) { + properties_clear(properties); + } + tag = _p.tag; + point_array = std::move(_p.point_array); + repetition = std::move(_p.repetition); + properties = _p.properties; + _p.properties = nullptr; + return *this; + } + + Polygon(Polygon&& _p) { + tag = _p.tag; + point_array = std::move(_p.point_array); + repetition = std::move(_p.repetition); + properties = _p.properties; + _p.properties = nullptr; + } + ~Polygon() { clear(); } + // Used by the python interface to store the associated PyObject* (if any). // No functions in gdstk namespace should touch this value! void* owner; diff --git a/include/gdstk/rawcell.hpp b/include/gdstk/rawcell.hpp index 4abf8398a..a95236371 100644 --- a/include/gdstk/rawcell.hpp +++ b/include/gdstk/rawcell.hpp @@ -25,19 +25,13 @@ LICENSE file or namespace gdstk { struct RawSource { - FILE* file; + FileWrapper* file; uint32_t uses; // Read num_bytes into buffer from fd starting at offset int64_t offset_read(void* buffer, uint64_t num_bytes, uint64_t offset) const { -#ifdef _WIN32 - // The POSIX version (pread) does not change the file cursor, this - // does. Furthermore, this is not thread-safe! - FSEEK64(file, offset, SEEK_SET); - return fread(buffer, 1, num_bytes, file); -#else - return pread(fileno(file), buffer, num_bytes, offset); -#endif + file->Seek(offset, SEEK_SET); + return file->Read(buffer, 1, num_bytes); }; }; diff --git a/include/gdstk/reference.hpp b/include/gdstk/reference.hpp index 61d119ebb..5f968226e 100644 --- a/include/gdstk/reference.hpp +++ b/include/gdstk/reference.hpp @@ -13,6 +13,7 @@ LICENSE file or #include #include +#include #include "flexpath.hpp" #include "label.hpp" @@ -107,13 +108,16 @@ struct Reference { // created. void get_polygons(bool apply_repetitions, bool include_paths, int64_t depth, bool filter, Tag tag, Array& result) const; + void get_polygons(bool apply_repetitions, bool include_paths, int64_t depth, + std::set* _tags, Array& result) const; void get_flexpaths(bool apply_repetitions, int64_t depth, bool filter, Tag tag, Array& result) const; void get_robustpaths(bool apply_repetitions, int64_t depth, bool filter, Tag tag, Array& result) const; void get_labels(bool apply_repetitions, int64_t depth, bool filter, Tag tag, Array& result) const; - + void get_labels(bool apply_repetitions, int64_t depth, std::set* _tags, + Array& result) const; // These functions output the reference in the GDSII and SVG formats. They // are not supposed to be called by the user. ErrorCode to_gds(FILE* out, double scaling) const; diff --git a/include/gdstk/repetition.hpp b/include/gdstk/repetition.hpp index 506c07135..fc0f2a884 100644 --- a/include/gdstk/repetition.hpp +++ b/include/gdstk/repetition.hpp @@ -14,7 +14,7 @@ LICENSE file or #include "array.hpp" #include "property.hpp" #include "vec.hpp" - +#include namespace gdstk { enum struct RepetitionType { @@ -45,12 +45,44 @@ struct Repetition { Array coords; // ExplicitX and ExplicitY }; + Repetition() { +#ifdef linux +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + memset(this, 0, sizeof(Repetition)); +#ifdef linux +#pragma GCC diagnostic pop +#endif + } + + Repetition(const RepetitionType _type) { + type = _type; + } + + Repetition& operator = (Repetition&& _repetition) { +#ifdef linux +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + if (this == &_repetition) return *this; + memcpy(this, &_repetition, sizeof(Repetition)); + memset(&_repetition, 0, sizeof(Repetition)); + return *this; +#ifdef linux +#pragma GCC diagnostic pop +#endif + } + + ~Repetition() { + clear(); + } void print() const; - void clear(); + void clear(bool deallocate = true); // This repetition instance must be zeroed before copy_from - void copy_from(const Repetition repetition); + void copy_from(const Repetition& repetition); // Return the number of repetitions created by this object, including the // original @@ -60,6 +92,8 @@ struct Repetition { // (0, 0), as first element, to result. void get_offsets(Array& result) const; + void get_offsets(std::vector& result) const; + // Append the extrema offsets generated by this repetition, including the // original, to result. void get_extrema(Array& result) const; diff --git a/include/gdstk/robustpath.hpp b/include/gdstk/robustpath.hpp index 82d17f8b2..fc157306a 100644 --- a/include/gdstk/robustpath.hpp +++ b/include/gdstk/robustpath.hpp @@ -13,6 +13,7 @@ LICENSE file or #include #include +#include #include "array.hpp" #include "curve.hpp" @@ -107,6 +108,47 @@ struct SubPath { }; }; + SubPath(SubPathType _type) { +#ifdef linux +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + memset(this, 0, sizeof(SubPath)); + type = _type; + +#ifdef linux +#pragma GCC diagnostic pop +#endif + } + + SubPath(const SubPath& _subpath) { +#ifdef linux +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + memcpy(this, &_subpath, sizeof(SubPath) - sizeof(Array)); + ctrl = _subpath.ctrl; + +#ifdef linux +#pragma GCC diagnostic pop +#endif + } + + SubPath& operator=(const SubPath& _subpath) { +#ifdef linux +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif + if (this == &_subpath) return *this; + memcpy(this, &_subpath, sizeof(SubPath) - sizeof(Array)); + ctrl = _subpath.ctrl; + return *this; +#ifdef linux +#pragma GCC diagnostic pop +#endif + } + + ~SubPath() {} void print() const; Vec2 gradient(double u, const double* trafo) const; Vec2 eval(double u, const double* trafo) const; @@ -267,6 +309,7 @@ struct RobustPath { // Overlapping points are removed from the path before any processing is // executed. ErrorCode to_polygons(bool filter, Tag tag, Array& result) const; + ErrorCode to_polygons(const std::set* _tags, Array& result) const; // These functions output the polygon in the GDSII, OASIS and SVG formats. // They are not supposed to be called by the user. Because fracturing diff --git a/include/gdstk/utils.hpp b/include/gdstk/utils.hpp index a487775dd..a39050b1d 100644 --- a/include/gdstk/utils.hpp +++ b/include/gdstk/utils.hpp @@ -56,14 +56,67 @@ LICENSE file or #define FSEEK64 fseek #endif +#include #include +#include #include #include "array.hpp" #include "vec.hpp" +struct gzFile_s; +typedef struct gzFile_s* gzFile; + namespace gdstk { +bool endsWithIgnoreCase(const std::string& str, const std::string& suffix); + +class FileWrapper { +public: + virtual ~FileWrapper() {} + virtual bool Open(const char* filename, const char* mode) = 0; + virtual void Close() = 0; + virtual bool IsEOF() = 0; + virtual size_t Read(void* buffer, size_t elementSizeBytes, size_t elementCount) = 0; + virtual size_t Write(const void* buffer, size_t elementSizeBytes, size_t elementCount) = 0; + virtual size_t PRead(void* buffer, size_t numBytes, size_t offset) = 0; + virtual size_t Tell() = 0; + virtual size_t Seek(long int offset, int origin) = 0; + virtual int Error() = 0; +}; + +class FileWrapperStd : public FileWrapper { +public: + FileWrapperStd(); + bool Open(const char* filename, const char* mode); + void Close(); + bool IsEOF(); + size_t Read(void* buffer, size_t elementSizeBytes, size_t elementCount); + size_t Write(const void* buffer, size_t elementSizeBytes, size_t elementCount); + size_t PRead(void* buffer, size_t numBytes, size_t offset); + size_t Tell(); + size_t Seek(long int offset, int origin); + int Error(); +protected: + FILE* file; +}; + +class FileWrapperGZlib : public FileWrapper { +public: + FileWrapperGZlib(); + bool Open(const char* filename, const char* mode); + void Close(); + bool IsEOF(); + size_t Read(void* buffer, size_t elementSizeBytes, size_t elementCount); + size_t Write(const void* buffer, size_t elementSizeBytes, size_t elementCount); + size_t PRead(void* buffer, size_t numBytes, size_t offset); + size_t Tell(); + size_t Seek(long int offset, int origin); + int Error(); +protected: + gzFile file; +}; + // Error codes enum struct ErrorCode { NoError = 0, @@ -87,6 +140,28 @@ enum struct ErrorCode { ZlibError, }; +inline std::string error_code_str(const ErrorCode _err) { + switch (_err) { + case ErrorCode::NoError: return "NoError"; + case ErrorCode::BooleanError: return "BooleanError"; + case ErrorCode::IntersectionNotFound: return "IntersectionNotFound"; + case ErrorCode::MissingReference: return "MissingReference"; + case ErrorCode::UnsupportedRecord: return "UnsupportedRecord"; + case ErrorCode::UnofficialSpecification: return "UnofficialSpecification"; + case ErrorCode::InvalidRepetition: return "InvalidRepetition"; + case ErrorCode::Overflow: return "Overflow"; + case ErrorCode::ChecksumError: return "ChecksumError"; + case ErrorCode::OutputFileOpenError: return "OutputFileOpenError"; + case ErrorCode::InputFileOpenError: return "InputFileOpenError"; + case ErrorCode::InputFileError: return "InputFileError"; + case ErrorCode::FileError: return "FileError"; + case ErrorCode::InvalidFile: return "InvalidFile"; + case ErrorCode::InsufficientMemory: return "InsufficientMemory"; + case ErrorCode::ZlibError: return "ZlibError"; + } + return "unknown"; +} + // Tag encapsulates layer and data (text) type. The implementation details // might change in the future. The only guarantee is that a zeroed Tag // indicates layer 0 and type 0. diff --git a/src/cell.cpp b/src/cell.cpp index 34e10f5ed..1b845df74 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -364,36 +364,38 @@ void Cell::copy_from(const Cell& cell, const char* new_name, bool deep_copy) { void Cell::get_polygons(bool apply_repetitions, bool include_paths, int64_t depth, bool filter, Tag tag, Array& result) const { + std::set filters; + if (filter) filters.insert(tag); + get_polygons(apply_repetitions, include_paths, depth, filter ? &filters : nullptr, result); +} + +void Cell::get_polygons(bool apply_repetitions, bool include_paths, int64_t depth, + std::set* _tags, Array& result) const { uint64_t start = result.count; - if (filter) { - for (uint64_t i = 0; i < polygon_array.count; i++) { - Polygon* psrc = polygon_array[i]; - if (psrc->tag != tag) continue; - Polygon* poly = (Polygon*)allocate_clear(sizeof(Polygon)); - poly->copy_from(*psrc); - result.append(poly); - } - } else { - result.ensure_slots(polygon_array.count); - for (uint64_t i = 0; i < polygon_array.count; i++) { - Polygon* poly = (Polygon*)allocate_clear(sizeof(Polygon)); - poly->copy_from(*polygon_array[i]); - result.append_unsafe(poly); + for (uint64_t i = 0; i < polygon_array.count; i++) { + Polygon* psrc = polygon_array[i]; + bool load = true; + if (_tags) { + load = _tags->find(psrc->tag) != _tags->end(); } + if (!load) continue; + Polygon* poly = (Polygon*)allocate_clear(sizeof(Polygon)); + poly->copy_from(*psrc); + result.append(poly); } if (include_paths) { FlexPath** flexpath = flexpath_array.items; for (uint64_t i = 0; i < flexpath_array.count; i++, flexpath++) { // NOTE: return ErrorCode ignored here - (*flexpath)->to_polygons(filter, tag, result); + (*flexpath)->to_polygons(_tags, result); } RobustPath** robustpath = robustpath_array.items; for (uint64_t i = 0; i < robustpath_array.count; i++, robustpath++) { // NOTE: return ErrorCode ignored here - (*robustpath)->to_polygons(filter, tag, result); + (*robustpath)->to_polygons(_tags, result); } } @@ -408,7 +410,7 @@ void Cell::get_polygons(bool apply_repetitions, bool include_paths, int64_t dept Reference** ref = reference_array.items; for (uint64_t i = 0; i < reference_array.count; i++, ref++) { (*ref)->get_polygons(apply_repetitions, include_paths, depth > 0 ? depth - 1 : -1, - filter, tag, result); + _tags, result); } } } @@ -580,6 +582,37 @@ void Cell::get_labels(bool apply_repetitions, int64_t depth, bool filter, Tag ta } } +void Cell::get_labels(bool apply_repetitions, int64_t depth, std::set* _tags, + Array& result) const { + uint64_t start = result.count; + + for (uint64_t i = 0; i < label_array.count; i++) { + Label* lsrc = label_array[i]; + bool load = true; + if (_tags) { + load = _tags->find(lsrc->tag) != _tags->end(); + } + if (!load) continue; + Label* label = (Label*)allocate_clear(sizeof(Label)); + label->copy_from(*lsrc); + result.append(label); + } + + if (apply_repetitions) { + uint64_t finish = result.count; + for (uint64_t i = start; i < finish; i++) { + result[i]->apply_repetition(result); + } + } + + if (depth != 0) { + Reference** ref = reference_array.items; + for (uint64_t i = 0; i < reference_array.count; i++, ref++) { + (*ref)->get_labels(apply_repetitions, depth > 0 ? depth - 1 : -1, _tags, result); + } + } +} + void Cell::flatten(bool apply_repetitions, Array& result) { uint64_t i = 0; while (i < reference_array.count) { diff --git a/src/flexpath.cpp b/src/flexpath.cpp index 071e41250..07fa2a9fb 100644 --- a/src/flexpath.cpp +++ b/src/flexpath.cpp @@ -19,6 +19,8 @@ LICENSE file or #include #include #include +#include +#include namespace gdstk { @@ -238,6 +240,17 @@ void FlexPath::remove_overlapping_points() { } ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { + std::set tags; + if (filter) { + tags.insert(tag); + return to_polygons(&tags, result); + } + else { + return to_polygons(nullptr , result); + } +} + +ErrorCode FlexPath::to_polygons(const std::set *_tags, Array& result) { remove_overlapping_points(); if (spine.point_array.count < 2) return ErrorCode::EmptyPath; @@ -246,7 +259,11 @@ ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { FlexPathElement* el = elements; for (uint64_t ne = 0; ne < num_elements; ne++, el++) { - if (filter && el->tag != tag) continue; + bool load = true; + if (_tags) { + load = _tags->find(el->tag) != _tags->end(); + } + if (!load) continue; const double* half_widths = (double*)el->half_width_and_offset.items; const double* offsets = half_widths + 1; @@ -302,7 +319,7 @@ ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { double angles[2] = {(cap_l - p1_l).angle(), (p1_r - cap_r).angle()}; Vec2 tension[2] = {Vec2{1, 1}, Vec2{1, 1}}; right_curve.interpolation(point_array, angles, angle_constraints, tension, 1, 1, - false, false); + false, false); } else if (el->end_type == EndType::Function) { Vec2 dir_l = cap_l - (p1 + n0 * half_widths[2 * 1]); dir_l.normalize(); @@ -388,8 +405,8 @@ ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { const double len_prev = len_next; len_next = (p_next - p).length(); len_factor = (fabs(sum_t.x) > fabs(sum_t.y)) - ? bend_dir * (n0.x - n1.x) / sum_t.x - : bend_dir * (n0.y - n1.y) / sum_t.y; + ? bend_dir * (n0.x - n1.x) / sum_t.x + : bend_dir * (n0.y - n1.y) / sum_t.y; center_radius = bend_radius - bend_dir * offsets[2 * i]; const double len_required = len_factor * center_radius; if (len_required > len_prev || len_required > len_next || @@ -498,7 +515,7 @@ ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { double final_angle = (-n1).angle(); if (final_angle < initial_angle) final_angle += 2 * M_PI; right_curve.arc(half_widths[2 * i], half_widths[2 * i], initial_angle, - final_angle, 0); + final_angle, 0); } else if (join_type == JoinType::Smooth) { right_curve.append(r1); Array point_array = {}; @@ -508,11 +525,11 @@ ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { double angles[2] = {tr0.angle(), tr1.angle()}; Vec2 tension[2] = {Vec2{1, 1}, Vec2{1, 1}}; right_curve.interpolation(point_array, angles, angle_constraints, - tension, 1, 1, false, false); + tension, 1, 1, false, false); } else if (join_type == JoinType::Function) { Array point_array = (*el->join_function)(r1, tr0, r2, tr1, p, half_widths[2 * i] * 2, - el->join_function_data); + el->join_function_data); right_curve.segment(point_array, false); point_array.clear(); } @@ -551,7 +568,7 @@ ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { double final_angle = n1.angle(); if (final_angle > initial_angle) final_angle -= 2 * M_PI; left_curve.arc(half_widths[2 * i], half_widths[2 * i], initial_angle, - final_angle, 0); + final_angle, 0); } else if (join_type == JoinType::Smooth) { left_curve.append(l1); Array point_array = {}; @@ -561,11 +578,11 @@ ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { double angles[2] = {tl0.angle(), tl1.angle()}; Vec2 tension[2] = {Vec2{1, 1}, Vec2{1, 1}}; left_curve.interpolation(point_array, angles, angle_constraints, - tension, 1, 1, false, false); + tension, 1, 1, false, false); } else if (join_type == JoinType::Function) { Array point_array = (*el->join_function)(l1, tl0, l2, tl1, p, half_widths[2 * i] * 2, - el->join_function_data); + el->join_function_data); left_curve.segment(point_array, false); point_array.clear(); } @@ -588,8 +605,8 @@ ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { if (half_widths[2 * (last)] != 0) left_curve.append(cap_r); } else if (el->end_type == EndType::HalfWidth || el->end_type == EndType::Extended) { const double extension = el->end_type == EndType::Extended - ? el->end_extensions.v - : half_widths[2 * (last)]; + ? el->end_extensions.v + : half_widths[2 * (last)]; if (extension > 0) left_curve.append(cap_l); left_curve.append(cap_l + extension * t0); if (half_widths[2 * (last)] != 0) left_curve.append(cap_r + extension * t0); @@ -610,7 +627,7 @@ ErrorCode FlexPath::to_polygons(bool filter, Tag tag, Array& result) { double angles[2] = {(cap_l - p0_l).angle(), (p0_r - cap_r).angle()}; Vec2 tension[2] = {Vec2{1, 1}, Vec2{1, 1}}; left_curve.interpolation(point_array, angles, angle_constraints, tension, 1, 1, - false, false); + false, false); } else if (el->end_type == EndType::Function) { Vec2 dir_r = cap_r - (p0 - n0 * half_widths[2 * (last - 1)]); dir_r.normalize(); diff --git a/src/gdsii.cpp b/src/gdsii.cpp index 65bc4354d..275ce6b9c 100644 --- a/src/gdsii.cpp +++ b/src/gdsii.cpp @@ -40,22 +40,22 @@ double gdsii_real_to_double(uint64_t real) { return (real & 0x8000000000000000) ? -result : result; } -ErrorCode gdsii_read_record(FILE* in, uint8_t* buffer, uint64_t& buffer_count) { +ErrorCode gdsii_read_record(FileWrapper* in, uint8_t* buffer, uint64_t& buffer_count) { if (buffer_count < 4) { if (error_logger) fputs("[GDSTK] Insufficient memory in buffer.\n", error_logger); return ErrorCode::InsufficientMemory; } - uint64_t read_length = fread(buffer, 1, 4, in); + uint64_t read_length = in->Read(buffer, 1, 4); if (read_length < 4) { DEBUG_PRINT("Read bytes (expected 4): %" PRIu64 "\n", read_length); - if (feof(in) != 0) { + if (in->IsEOF()) { if (error_logger) fputs("[GDSTK] Unable to read input file. End of file reached unexpectedly.\n", error_logger); } else { if (error_logger) fprintf(error_logger, "[GDSTK] Unable to read input file. Error number %d\n.", - ferror(in)); + in->Error()); } buffer_count = read_length; return ErrorCode::InputFileError; @@ -76,19 +76,19 @@ ErrorCode gdsii_read_record(FILE* in, uint8_t* buffer, uint64_t& buffer_count) { buffer_count = read_length; return ErrorCode::InsufficientMemory; } - read_length = fread(buffer + 4, 1, record_length - 4, in); + read_length = in->Read(buffer + 4, 1, record_length - 4); buffer_count = 4 + read_length; if (read_length < record_length - 4) { DEBUG_PRINT("Read bytes (expected %" PRIu32 "): %" PRIu64 "\n", record_length - 4, read_length); - if (feof(in) != 0) { + if (in->IsEOF()) { if (error_logger) fputs("[GDSTK] Unable to read input file. End of file reached unexpectedly.\n", error_logger); } else { if (error_logger) fprintf(error_logger, "[GDSTK] Unable to read input file. Error number %d\n.", - ferror(in)); + in->Error()); } return ErrorCode::InputFileError; } diff --git a/src/library.cpp b/src/library.cpp index 60e7e4a6b..927091618 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -14,6 +14,7 @@ LICENSE file or #include #include #include +#include #include #include @@ -913,7 +914,7 @@ ErrorCode Library::write_oas(const char* filename, double circle_tolerance, } Library read_gds(const char* filename, double unit, double tolerance, const Set* shape_tags, - ErrorCode* error_code) { + const Set* label_tags, ErrorCode* error_code) { const char* gdsii_record_names[] = { "HEADER", "BGNLIB", "LIBNAME", "UNITS", "ENDLIB", "BGNSTR", "STRNAME", "ENDSTR", "BOUNDARY", "PATH", "SREF", "AREF", @@ -945,8 +946,9 @@ Library read_gds(const char* filename, double unit, double tolerance, const Set< double width = 0; int16_t key = 0; - FILE* in = fopen(filename, "rb"); - if (in == NULL) { + FileWrapper* in = endsWithIgnoreCase(filename, ".gds.gz") ? (FileWrapper*)(new FileWrapperGZlib()) : (FileWrapper*)(new FileWrapperStd()); + + if (!in->Open(filename, "rb")) { fputs("[GDSTK] Unable to open GDSII file for input.\n", stderr); if (error_code) *error_code = ErrorCode::InputFileOpenError; return library; @@ -1043,7 +1045,8 @@ Library read_gds(const char* filename, double unit, double tolerance, const Set< } } map.clear(); - fclose(in); + in->Close(); + delete in; return library; } break; case GdsiiRecord::BGNSTR: @@ -1305,7 +1308,8 @@ Library read_gds(const char* filename, double unit, double tolerance, const Set< // case GdsiiRecord::UINTEGER: // case GdsiiRecord::USTRING: // case GdsiiRecord::REFLIBS: - // case GdsiiRecord::FONTS: + case GdsiiRecord::FONTS: + break; // case GdsiiRecord::GENERATIONS: // case GdsiiRecord::ATTRTABLE: // case GdsiiRecord::STYPTABLE: @@ -1340,12 +1344,27 @@ Library read_gds(const char* filename, double unit, double tolerance, const Set< } library.free_all(); - fclose(in); + in->Close(); + delete in; return Library{}; } -// TODO: verify modal variables are correctly updated Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* error_code) { + return read_oas(filename, unit, tolerance, NULL, NULL, error_code); +} + +// TODO: verify modal variables are correctly updated +Library read_oas(const char* filename, double unit, double tolerance, const Set* shape_tags, const Set* label_tags, ErrorCode* error_code) { + return read_oas(filename, unit, tolerance, shape_tags, label_tags, error_code, 0, 0); +} + +Library read_oas(const char* filename, double unit, + double tolerance, + const Set*shape_tags, + const Set*label_tags, + ErrorCode * error_code, + Tag fub_tag, double min_fub_dimension) +{ Library library = {}; OasisStream in = {}; @@ -1407,12 +1426,22 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* Vec2 modal_text_pos = {0, 0}; Vec2 modal_geom_pos = {0, 0}; Vec2 modal_geom_dim = {0, 0}; - Repetition modal_repetition = {RepetitionType::None}; - Label* modal_text_string = NULL; + Repetition modal_repetition = { RepetitionType::None, }; + memset(&modal_repetition, 0, sizeof(Repetition)); + modal_repetition.offsets.ensure_slots(5000000); + modal_repetition.coords.ensure_slots(5000000); + Label* modal_text_string = (Label*)allocate_clear(sizeof(Label)); + uint64_t modal_text_string_capacity = 256; + modal_text_string->text = (char*)malloc(modal_text_string_capacity); + void* modal_text_owner = NULL; + bool use_modal_text_string = false; + bool use_modal_text_owner = false; Reference* modal_placement_cell = NULL; Array modal_polygon_points = {}; modal_polygon_points.append(Vec2{0, 0}); + modal_polygon_points.ensure_slots(64); Array modal_path_points = {}; + modal_path_points.ensure_slots(64); modal_path_points.append(Vec2{0, 0}); double modal_path_halfwidth = 0; Vec2 modal_path_extensions = {0, 0}; @@ -1420,6 +1449,9 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* double modal_circle_radius = 0; Property* modal_property = NULL; PropertyValue* modal_property_value_list = NULL; + Array modal_trapezoid_points = {}; + modal_trapezoid_points.ensure_slots(4); + modal_trapezoid_points.count = 4; Property** next_property = &library.properties; @@ -1473,7 +1505,7 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* // "CBLOCK"}; OasisRecord record; - while ((error_code == NULL || *error_code == ErrorCode::NoError) && + while ((error_code == NULL || *error_code < ErrorCode::ChecksumError) && oasis_read(&record, 1, 1, in) == ErrorCode::NoError) { // DEBUG_PRINT("Record [%02u] %s\n", (uint8_t)record, // (uint8_t)record < COUNT(oasis_record_names) @@ -1665,12 +1697,12 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* case OasisRecord::LAYERNAME_DATA: case OasisRecord::LAYERNAME_TEXT: // Unused record - free_allocation(oasis_read_string(in, false, len)); + oasis_skip_string(in); for (uint32_t i = 2; i > 0; i--) { uint64_t type = oasis_read_unsigned_integer(in); if (type > 0) { - if (type == 4) oasis_read_unsigned_integer(in); - oasis_read_unsigned_integer(in); + if (type == 4) oasis_skip_unsigned_integer(in); + oasis_skip_unsigned_integer(in); } } break; @@ -1771,43 +1803,40 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* } } break; case OasisRecord::TEXT: { - Label* label = (Label*)allocate_clear(sizeof(Label)); - label->magnification = 1; - label->anchor = Anchor::SW; - cell->label_array.append(label); - next_property = &label->properties; + Tag temp_tag = 0; + //label->anchor = Anchor::SW; + uint8_t info; oasis_read(&info, 1, 1, in); if (info & 0x40) { // Explicit text if (info & 0x20) { // Reference number: use owner to temporarily store it - label->owner = (void*)oasis_read_unsigned_integer(in); - } else { - label->text = (char*)oasis_read_string(in, true, len); + modal_text_owner = (void*)oasis_read_unsigned_integer(in); + use_modal_text_owner = true; + use_modal_text_string = false; } - modal_text_string = label; - } else { - // Use modal_text_string - if (modal_text_string->text == NULL) { - label->owner = modal_text_string->owner; - } else { - label->text = copy_string(modal_text_string->text, NULL); + else { + oasis_read_string2(in, modal_text_string, modal_text_string_capacity, len); + use_modal_text_owner = false; + use_modal_text_string = true; } } if (info & 0x01) { modal_textlayer = (uint32_t)oasis_read_unsigned_integer(in); } - set_layer(label->tag, modal_textlayer); + set_layer(temp_tag, modal_textlayer); if (info & 0x02) { modal_texttype = (uint32_t)oasis_read_unsigned_integer(in); } - set_type(label->tag, modal_texttype); + set_type(temp_tag, modal_texttype); + bool keep_label = !(label_tags && !label_tags->has_value(temp_tag)); if (info & 0x10) { double x = factor * oasis_read_integer(in); if (modal_absolute_pos) { modal_text_pos.x = x; - } else { + } + else { modal_text_pos.x += x; } } @@ -1815,28 +1844,50 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* double y = factor * oasis_read_integer(in); if (modal_absolute_pos) { modal_text_pos.y = y; - } else { + } + else { modal_text_pos.y += y; } } - label->origin = modal_text_pos; + Label* label = NULL; + if (keep_label) + { + label = (Label*)allocate_clear(sizeof(Label)); + next_property = &label->properties; + label->magnification = 1; + label->tag = temp_tag; + label->origin = modal_text_pos; + if (use_modal_text_owner) label->owner = modal_text_owner; + else if (use_modal_text_string) { + label->text = (char*)malloc(strlen(modal_text_string->text + 1)); + strcpy(label->text, modal_text_string->text); + } + cell->label_array.append(label); + } if (info & 0x04) { oasis_read_repetition(in, factor, modal_repetition); - label->repetition.copy_from(modal_repetition); + if (keep_label) + { + if (modal_repetition.get_count() > 0) { + label->repetition.copy_from(modal_repetition); + } + } } } break; case OasisRecord::RECTANGLE: { - Polygon* polygon = (Polygon*)allocate_clear(sizeof(Polygon)); - cell->polygon_array.append(polygon); - next_property = &polygon->properties; uint8_t info; + Tag temp_tag = 0; oasis_read(&info, 1, 1, in); if (info & 0x01) { modal_layer = (uint32_t)oasis_read_unsigned_integer(in); } + set_layer(temp_tag, modal_layer); if (info & 0x02) { modal_datatype = (uint32_t)oasis_read_unsigned_integer(in); } + set_type(temp_tag, modal_datatype); + bool keep_rectangle = !(shape_tags && !shape_tags->has_value(temp_tag)); + if (info & 0x40) { modal_geom_dim.x = factor * oasis_read_unsigned_integer(in); } @@ -1861,32 +1912,66 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* modal_geom_pos.y += y; } } - *polygon = rectangle(modal_geom_pos, modal_geom_pos + modal_geom_dim, - make_tag(modal_layer, modal_datatype)); + if (fub_tag > 0 && temp_tag == fub_tag && modal_geom_dim.x < min_fub_dimension && modal_geom_dim.y < min_fub_dimension) + { + // Skip FUBs that are too small + keep_rectangle = false; + } + Polygon* polygon = NULL; + if (keep_rectangle) + { + polygon = (Polygon*)allocate_clear(sizeof(Polygon)); + *polygon = rectangle(modal_geom_pos, modal_geom_pos + modal_geom_dim, temp_tag); + } if (info & 0x04) { oasis_read_repetition(in, factor, modal_repetition); - polygon->repetition.copy_from(modal_repetition); + if (keep_rectangle) + polygon->repetition.copy_from(modal_repetition); + } + if (keep_rectangle) + { + next_property = &polygon->properties; + cell->polygon_array.append(polygon); + } + else + { + next_property = NULL; } } break; case OasisRecord::POLYGON: { - Polygon* polygon = (Polygon*)allocate_clear(sizeof(Polygon)); - cell->polygon_array.append(polygon); - next_property = &polygon->properties; uint8_t info; + Tag temp_tag = 0; oasis_read(&info, 1, 1, in); if (info & 0x01) { modal_layer = (uint32_t)oasis_read_unsigned_integer(in); } - set_layer(polygon->tag, modal_layer); + set_layer(temp_tag, modal_layer); if (info & 0x02) { modal_datatype = (uint32_t)oasis_read_unsigned_integer(in); } - set_type(polygon->tag, modal_datatype); + set_type(temp_tag, modal_datatype); + bool keep_polygon = !(shape_tags && !shape_tags->has_value(temp_tag)); + if (info & 0x20) { modal_polygon_points.count = 1; oasis_read_point_list(in, factor, true, modal_polygon_points); } - polygon->point_array.copy_from(modal_polygon_points); + if (fub_tag > 0 && temp_tag == fub_tag) + { + double min_x = DBL_MAX; + double max_x = -DBL_MAX; + double min_y = DBL_MAX; + double max_y = -DBL_MAX; + for (int i = 0; i < modal_polygon_points.count; i++) + { + min_x = std::min(min_x, modal_polygon_points[i].x); + max_x = std::max(max_x, modal_polygon_points[i].x); + min_y = std::min(min_y, modal_polygon_points[i].y); + max_y = std::max(max_y, modal_polygon_points[i].y); + } + if (max_x - min_x < min_fub_dimension && max_y - min_y < min_fub_dimension) + keep_polygon = false; // Skip FUBs that are too small + } if (info & 0x10) { double x = factor * oasis_read_integer(in); if (modal_absolute_pos) { @@ -1903,73 +1988,71 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* modal_geom_pos.y += y; } } - Vec2* v = polygon->point_array.items; - for (uint64_t i = polygon->point_array.count; i > 0; i--) { - *v++ += modal_geom_pos; + Polygon* polygon = NULL; + if (keep_polygon) + { + polygon = (Polygon*)allocate_clear(sizeof(Polygon)); + polygon->tag = temp_tag; + next_property = &polygon->properties; } + else + next_property = NULL; if (info & 0x04) { oasis_read_repetition(in, factor, modal_repetition); - polygon->repetition.copy_from(modal_repetition); + if (keep_polygon) + polygon->repetition.copy_from(modal_repetition); + } + if (keep_polygon) + { + polygon->point_array.copy_from(modal_polygon_points); + Vec2* v = polygon->point_array.items; + for (uint64_t i = polygon->point_array.count; i > 0; i--) { + *v++ += modal_geom_pos; + } + cell->polygon_array.append(polygon); } } break; case OasisRecord::PATH: { - FlexPath* path = (FlexPath*)allocate_clear(sizeof(FlexPath)); - FlexPathElement* element = - (FlexPathElement*)allocate_clear(sizeof(FlexPathElement)); - cell->flexpath_array.append(path); - next_property = &path->properties; - path->spine.tolerance = tolerance; - path->elements = element; - path->num_elements = 1; - path->simple_path = true; - path->scale_width = true; + Tag temp_tag = 0; uint8_t info; oasis_read(&info, 1, 1, in); if (info & 0x01) { modal_layer = (uint32_t)oasis_read_unsigned_integer(in); } - set_layer(element->tag, modal_layer); + set_layer(temp_tag, modal_layer); if (info & 0x02) { modal_datatype = (uint32_t)oasis_read_unsigned_integer(in); } - set_type(element->tag, modal_datatype); + set_type(temp_tag, modal_datatype); + bool keep_path = !(shape_tags && !shape_tags->has_value(temp_tag)); + if (info & 0x40) { modal_path_halfwidth = factor * oasis_read_unsigned_integer(in); } - element->half_width_and_offset.append(Vec2{modal_path_halfwidth, 0}); if (info & 0x80) { uint8_t extension_scheme; oasis_read(&extension_scheme, 1, 1, in); switch (extension_scheme & 0x0c) { - case 0x04: - modal_path_extensions.u = 0; - break; - case 0x08: - modal_path_extensions.u = modal_path_halfwidth; - break; - case 0x0c: - modal_path_extensions.u = factor * oasis_read_integer(in); + case 0x04: + modal_path_extensions.u = 0; + break; + case 0x08: + modal_path_extensions.u = modal_path_halfwidth; + break; + case 0x0c: + modal_path_extensions.u = factor * oasis_read_integer(in); } switch (extension_scheme & 0x03) { - case 0x01: - modal_path_extensions.v = 0; - break; - case 0x02: - modal_path_extensions.v = modal_path_halfwidth; - break; - case 0x03: - modal_path_extensions.v = factor * oasis_read_integer(in); + case 0x01: + modal_path_extensions.v = 0; + break; + case 0x02: + modal_path_extensions.v = modal_path_halfwidth; + break; + case 0x03: + modal_path_extensions.v = factor * oasis_read_integer(in); } } - if (modal_path_extensions.u == 0 && modal_path_extensions.v == 0) { - element->end_type = EndType::Flush; - } else if (modal_path_extensions.u == modal_path_halfwidth && - modal_path_extensions.v == modal_path_halfwidth) { - element->end_type = EndType::HalfWidth; - } else { - element->end_type = EndType::Extended; - element->end_extensions = modal_path_extensions; - } if (info & 0x20) { modal_path_points.count = 1; oasis_read_point_list(in, factor, false, modal_path_points); @@ -1990,31 +2073,66 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* modal_geom_pos.y += y; } } - path->spine.append(modal_geom_pos); - const Array skip_first = {0, modal_path_points.count - 1, - modal_path_points.items + 1}; - path->segment(skip_first, NULL, NULL, true); + FlexPath* path = NULL; + FlexPathElement* element = NULL; + if (keep_path) + { + path = (FlexPath*)allocate_clear(sizeof(FlexPath)); + element = (FlexPathElement*)allocate_clear(sizeof(FlexPathElement)); + path->spine.tolerance = tolerance; + path->elements = element; + path->num_elements = 1; + path->simple_path = true; + path->scale_width = true; + element->tag = temp_tag; + next_property = &path->properties; + element->half_width_and_offset.append(Vec2{ modal_path_halfwidth, 0 }); + if (modal_path_extensions.u == 0 && modal_path_extensions.v == 0) { + element->end_type = EndType::Flush; + } + else if (modal_path_extensions.u == modal_path_halfwidth && + modal_path_extensions.v == modal_path_halfwidth) { + element->end_type = EndType::HalfWidth; + } + else { + element->end_type = EndType::Extended; + element->end_extensions = modal_path_extensions; + } + path->spine.append(modal_geom_pos); + const Array skip_first = {(uint64_t)0, modal_path_points.count - 1, + modal_path_points.items + 1}; + path->segment(skip_first, NULL, NULL, true); + } if (info & 0x04) { oasis_read_repetition(in, factor, modal_repetition); - path->repetition.copy_from(modal_repetition); + if (keep_path) + path->repetition.copy_from(modal_repetition); + } + if (keep_path) + { + cell->flexpath_array.append(path); + } + else + { + next_property = NULL; } } break; case OasisRecord::TRAPEZOID_AB: case OasisRecord::TRAPEZOID_A: case OasisRecord::TRAPEZOID_B: { - Polygon* polygon = (Polygon*)allocate_clear(sizeof(Polygon)); - cell->polygon_array.append(polygon); - next_property = &polygon->properties; + Tag temp_tag = 0; uint8_t info; oasis_read(&info, 1, 1, in); if (info & 0x01) { modal_layer = (uint32_t)oasis_read_unsigned_integer(in); } - set_layer(polygon->tag, modal_layer); + set_layer(temp_tag, modal_layer); if (info & 0x02) { modal_datatype = (uint32_t)oasis_read_unsigned_integer(in); } - set_type(polygon->tag, modal_datatype); + set_type(temp_tag, modal_datatype); + bool keep_polygon = !(shape_tags && !shape_tags->has_value(temp_tag)); + if (info & 0x40) { modal_geom_dim.x = factor * oasis_read_unsigned_integer(in); } @@ -2048,9 +2166,8 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* modal_geom_pos.y += y; } } - Array* point_array = &polygon->point_array; - point_array->ensure_slots(4); - point_array->count = 4; + Array* point_array = &modal_trapezoid_points; + modal_trapezoid_points.count = 4; Vec2* r = point_array->items; Vec2* s = r + 1; Vec2* q = s + 1; @@ -2090,25 +2207,58 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* s->x = q->x - delta_b; } } + if (fub_tag > 0 && temp_tag == fub_tag) + { + double min_x = DBL_MAX; + double max_x = -DBL_MAX; + double min_y = DBL_MAX; + double max_y = -DBL_MAX; + for (int i = 0; i < modal_trapezoid_points.count; i++) + { + min_x = std::min(min_x, modal_trapezoid_points[i].x); + max_x = std::max(max_x, modal_trapezoid_points[i].x); + min_y = std::min(min_y, modal_trapezoid_points[i].y); + max_y = std::max(max_y, modal_trapezoid_points[i].y); + } + if (max_x - min_x < min_fub_dimension && max_y - min_y < min_fub_dimension) + keep_polygon = false; // Skip FUBs that are too small + } + Polygon* polygon = NULL; + if (keep_polygon) + { + polygon = (Polygon*)allocate_clear(sizeof(Polygon)); + polygon->tag = temp_tag; + next_property = &polygon->properties; + polygon->point_array.copy_from(modal_trapezoid_points); + } if (info & 0x04) { oasis_read_repetition(in, factor, modal_repetition); - polygon->repetition.copy_from(modal_repetition); - } + if (keep_polygon) + polygon->repetition.copy_from(modal_repetition); + } + if (keep_polygon) + { + cell->polygon_array.append(polygon); + } + else + { + next_property = NULL; + } } break; case OasisRecord::CTRAPEZOID: { - Polygon* polygon = (Polygon*)allocate_clear(sizeof(Polygon)); - cell->polygon_array.append(polygon); - next_property = &polygon->properties; + Tag temp_tag = 0; uint8_t info; oasis_read(&info, 1, 1, in); if (info & 0x01) { modal_layer = (uint32_t)oasis_read_unsigned_integer(in); } - set_layer(polygon->tag, modal_layer); + set_layer(temp_tag, modal_layer); if (info & 0x02) { modal_datatype = (uint32_t)oasis_read_unsigned_integer(in); } - set_type(polygon->tag, modal_datatype); + set_type(temp_tag, modal_datatype); + bool keep_polygon = !(shape_tags && !shape_tags->has_value(temp_tag)); + if (info & 0x80) { oasis_read(&modal_ctrapezoid_type, 1, 1, in); } @@ -2134,10 +2284,9 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* modal_geom_pos.y += y; } } - Array* point_array = &polygon->point_array; + Array* point_array = &modal_trapezoid_points; Vec2* v; if (modal_ctrapezoid_type > 15 && modal_ctrapezoid_type < 24) { - point_array->ensure_slots(3); point_array->count = 3; v = point_array->items; v[0] = modal_geom_pos; @@ -2153,131 +2302,169 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* v[3] = modal_geom_pos + Vec2{0, modal_geom_dim.y}; } switch (modal_ctrapezoid_type) { - case 0: - v[2].x -= modal_geom_dim.y; - break; - case 1: - v[1].x -= modal_geom_dim.y; - break; - case 2: - v[3].x += modal_geom_dim.y; - break; - case 3: - v[0].x += modal_geom_dim.y; - break; - case 4: - v[2].x -= modal_geom_dim.y; - v[3].x += modal_geom_dim.y; - break; - case 5: - v[0].x += modal_geom_dim.y; - v[1].x -= modal_geom_dim.y; - break; - case 6: - v[1].x -= modal_geom_dim.y; - v[3].x += modal_geom_dim.y; - break; - case 7: - v[0].x += modal_geom_dim.y; - v[2].x -= modal_geom_dim.y; - break; - case 8: - v[2].y -= modal_geom_dim.x; - break; - case 9: - v[3].y -= modal_geom_dim.x; - break; - case 10: - v[1].y += modal_geom_dim.x; - break; - case 11: - v[0].y += modal_geom_dim.x; - break; - case 12: - v[1].y += modal_geom_dim.x; - v[2].y -= modal_geom_dim.x; - break; - case 13: - v[0].y += modal_geom_dim.x; - v[3].y -= modal_geom_dim.x; - break; - case 14: - v[1].y += modal_geom_dim.x; - v[3].y -= modal_geom_dim.x; - break; - case 15: - v[0].y += modal_geom_dim.x; - v[2].y -= modal_geom_dim.x; - break; - case 16: - v[1].x += modal_geom_dim.x; - v[2].y += modal_geom_dim.x; + case 0: + v[2].x -= modal_geom_dim.y; + break; + case 1: + v[1].x -= modal_geom_dim.y; + break; + case 2: + v[3].x += modal_geom_dim.y; + break; + case 3: + v[0].x += modal_geom_dim.y; + break; + case 4: + v[2].x -= modal_geom_dim.y; + v[3].x += modal_geom_dim.y; + break; + case 5: + v[0].x += modal_geom_dim.y; + v[1].x -= modal_geom_dim.y; + break; + case 6: + v[1].x -= modal_geom_dim.y; + v[3].x += modal_geom_dim.y; + break; + case 7: + v[0].x += modal_geom_dim.y; + v[2].x -= modal_geom_dim.y; + break; + case 8: + v[2].y -= modal_geom_dim.x; + break; + case 9: + v[3].y -= modal_geom_dim.x; + break; + case 10: + v[1].y += modal_geom_dim.x; + break; + case 11: + v[0].y += modal_geom_dim.x; + break; + case 12: + v[1].y += modal_geom_dim.x; + v[2].y -= modal_geom_dim.x; + break; + case 13: + v[0].y += modal_geom_dim.x; + v[3].y -= modal_geom_dim.x; + break; + case 14: + v[1].y += modal_geom_dim.x; + v[3].y -= modal_geom_dim.x; + break; + case 15: + v[0].y += modal_geom_dim.x; + v[2].y -= modal_geom_dim.x; + break; + case 16: + v[1].x += modal_geom_dim.x; + v[2].y += modal_geom_dim.x; modal_geom_dim.y = modal_geom_dim.x; - break; - case 17: - v[1] += modal_geom_dim.x; - v[2].y += modal_geom_dim.x; + break; + case 17: + v[1] += modal_geom_dim.x; + v[2].y += modal_geom_dim.x; modal_geom_dim.y = modal_geom_dim.x; - break; - case 18: - v[1].x += modal_geom_dim.x; - v[2] += modal_geom_dim.x; + break; + case 18: + v[1].x += modal_geom_dim.x; + v[2] += modal_geom_dim.x; modal_geom_dim.y = modal_geom_dim.x; - break; - case 19: - v[0].x += modal_geom_dim.x; - v[1] += modal_geom_dim.x; - v[2].y += modal_geom_dim.x; + break; + case 19: + v[0].x += modal_geom_dim.x; + v[1] += modal_geom_dim.x; + v[2].y += modal_geom_dim.x; modal_geom_dim.y = modal_geom_dim.x; - break; - case 20: - v[1].x += 2 * modal_geom_dim.y; - v[2] += modal_geom_dim.y; + break; + case 20: + v[1].x += 2 * modal_geom_dim.y; + v[2] += modal_geom_dim.y; modal_geom_dim.x = 2 * modal_geom_dim.y; - break; - case 21: - v[0].x += modal_geom_dim.y; - v[1].x += 2 * modal_geom_dim.y; - v[1].y += modal_geom_dim.y; - v[2].y += modal_geom_dim.y; + break; + case 21: + v[0].x += modal_geom_dim.y; + v[1].x += 2 * modal_geom_dim.y; + v[1].y += modal_geom_dim.y; + v[2].y += modal_geom_dim.y; modal_geom_dim.x = 2 * modal_geom_dim.y; - break; - case 22: - v[1] += modal_geom_dim.x; - v[2].y += 2 * modal_geom_dim.x; + break; + case 22: + v[1] += modal_geom_dim.x; + v[2].y += 2 * modal_geom_dim.x; modal_geom_dim.y = 2 * modal_geom_dim.x; - break; - case 23: - v[0].x += modal_geom_dim.x; - v[1].x += modal_geom_dim.x; - v[1].y += 2 * modal_geom_dim.x; - v[2].y += modal_geom_dim.x; + break; + case 23: + v[0].x += modal_geom_dim.x; + v[1].x += modal_geom_dim.x; + v[1].y += 2 * modal_geom_dim.x; + v[2].y += modal_geom_dim.x; modal_geom_dim.y = 2 * modal_geom_dim.x; - break; - case 25: - v[2].y = v[3].y = modal_geom_pos.y + modal_geom_dim.x; - break; + break; + case 25: + v[2].y = v[3].y = modal_geom_pos.y + modal_geom_dim.x; + break; + } + if (fub_tag > 0 && temp_tag == fub_tag) + { + double min_x = DBL_MAX; + double max_x = -DBL_MAX; + double min_y = DBL_MAX; + double max_y = -DBL_MAX; + for (int i = 0; i < modal_trapezoid_points.count; i++) + { + min_x = std::min(min_x, modal_trapezoid_points[i].x); + max_x = std::max(max_x, modal_trapezoid_points[i].x); + min_y = std::min(min_y, modal_trapezoid_points[i].y); + max_y = std::max(max_y, modal_trapezoid_points[i].y); + } + if (max_x - min_x < min_fub_dimension && max_y - min_y < min_fub_dimension) + keep_polygon = false; // Skip FUBs that are too small + } + Polygon* polygon = NULL; + if (keep_polygon) + { + polygon = (Polygon*)allocate_clear(sizeof(Polygon)); + polygon->tag = temp_tag; + next_property = &polygon->properties; + polygon->point_array.copy_from(modal_trapezoid_points); } if (info & 0x04) { oasis_read_repetition(in, factor, modal_repetition); - polygon->repetition.copy_from(modal_repetition); + if (keep_polygon) + polygon->repetition.copy_from(modal_repetition); + } + if (keep_polygon) + { + cell->polygon_array.append(polygon); + } + else + { + next_property = NULL; } } break; case OasisRecord::CIRCLE: { - Polygon* polygon = (Polygon*)allocate_clear(sizeof(Polygon)); - cell->polygon_array.append(polygon); - next_property = &polygon->properties; uint8_t info; + Tag temp_tag = 0; oasis_read(&info, 1, 1, in); if (info & 0x01) { modal_layer = (uint32_t)oasis_read_unsigned_integer(in); } + set_layer(temp_tag, modal_layer); if (info & 0x02) { modal_datatype = (uint32_t)oasis_read_unsigned_integer(in); } + set_type(temp_tag, modal_datatype); + bool keep_circle = !(shape_tags && !shape_tags->has_value(temp_tag)); + if (info & 0x20) { modal_circle_radius = factor * oasis_read_unsigned_integer(in); } + if (fub_tag > 0 && temp_tag == fub_tag && (2 * modal_circle_radius) < min_fub_dimension) + keep_circle = false; // Skip FUBs that are too small + if (info & 0x10) { double x = factor * oasis_read_integer(in); if (modal_absolute_pos) { @@ -2294,73 +2481,90 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* modal_geom_pos.y += y; } } - *polygon = ellipse(modal_geom_pos, modal_circle_radius, modal_circle_radius, 0, 0, - 0, 0, tolerance, make_tag(modal_layer, modal_datatype)); + Polygon* polygon = NULL; + if (keep_circle) + { + polygon = (Polygon*)allocate_clear(sizeof(Polygon)); + *polygon = ellipse(modal_geom_pos, modal_circle_radius, modal_circle_radius, 0, 0, + 0, 0, tolerance, temp_tag); + next_property = &polygon->properties; + } if (info & 0x04) { oasis_read_repetition(in, factor, modal_repetition); - polygon->repetition.copy_from(modal_repetition); + if (keep_circle) + polygon->repetition.copy_from(modal_repetition); + } + if (keep_circle) + { + cell->polygon_array.append(polygon); + } + else + { + next_property = NULL; } } break; case OasisRecord::PROPERTY: case OasisRecord::LAST_PROPERTY: { - Property* property = (Property*)allocate_clear(sizeof(Property)); - *next_property = property; - next_property = &property->next; - uint8_t info; - if (record == OasisRecord::LAST_PROPERTY) { - info = 0x08; + if (next_property) + { + Property* property = (Property*)allocate_clear(sizeof(Property)); + *next_property = property; + next_property = &property->next; + uint8_t info; + if (record == OasisRecord::LAST_PROPERTY) { + info = 0x08; } else { - oasis_read(&info, 1, 1, in); - } - if (info & 0x04) { - // Explicit name - if (info & 0x02) { - // Reference number - property->name = (char*)oasis_read_unsigned_integer(in); - unfinished_property_name.append(property); - modal_property_unfinished = true; - } else { - property->name = (char*)oasis_read_string(in, true, len); - modal_property_unfinished = false; + oasis_read(&info, 1, 1, in); } - modal_property = property; + if (info & 0x04) { + // Explicit name + if (info & 0x02) { + // Reference number + property->name = (char*)oasis_read_unsigned_integer(in); + unfinished_property_name.append(property); + modal_property_unfinished = true; + } else { + property->name = (char*)oasis_read_string(in, true, len); + modal_property_unfinished = false; + } + modal_property = property; } else { - // Use modal variable - if (modal_property_unfinished) { - property->name = modal_property->name; - unfinished_property_name.append(property); + // Use modal variable + if (modal_property_unfinished) { + property->name = modal_property->name; + unfinished_property_name.append(property); } else { - property->name = copy_string(modal_property->name, NULL); - } - } - if (info & 0x08) { - // Use modal value list - property->value = property_values_copy(modal_property_value_list); - PropertyValue* src = modal_property_value_list; - PropertyValue* dst = property->value; - while (src) { - if (src->type == PropertyType::UnsignedInteger && - unfinished_property_value.contains(src)) { - unfinished_property_value.append(dst); + property->name = copy_string(modal_property->name, NULL); } - src = src->next; - dst = dst->next; } + if (info & 0x08) { + // Use modal value list + property->value = property_values_copy(modal_property_value_list); + PropertyValue* src = modal_property_value_list; + PropertyValue* dst = property->value; + while (src) { + if (src->type == PropertyType::UnsignedInteger && + unfinished_property_value.contains(src)) { + unfinished_property_value.append(dst); + } + src = src->next; + dst = dst->next; + } } else { - // Explicit value list - uint64_t num_values = info >> 4; - if (num_values == 15) { - num_values = oasis_read_unsigned_integer(in); - } - PropertyValue** next = &property->value; - for (; num_values > 0; num_values--) { - PropertyValue* property_value = - (PropertyValue*)allocate_clear(sizeof(PropertyValue)); - *next = property_value; - next = &property_value->next; - OasisDataType data_type; - oasis_read(&data_type, 1, 1, in); - switch (data_type) { + // Explicit value list + uint64_t num_values = info >> 4; + if (num_values == 15) { + num_values = oasis_read_unsigned_integer(in); + } + PropertyValue** next = &property->value; + for (; num_values > 0; num_values--) { + PropertyValue* property_value = + (PropertyValue*)allocate_clear(sizeof(PropertyValue)); + *next = property_value; + next = &property_value->next; + OasisDataType data_type; + oasis_read(&data_type, 1, 1, in); + switch (data_type) { case OasisDataType::RealPositiveInteger: case OasisDataType::RealNegativeInteger: case OasisDataType::RealPositiveReciprocal: @@ -2394,27 +2598,89 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* property_value->unsigned_integer = oasis_read_unsigned_integer(in); unfinished_property_value.append(property_value); } break; + } + } + modal_property_value_list = property->value; + } + } + else //No property to keep + { + uint8_t info; + if (record == OasisRecord::LAST_PROPERTY) { + info = 0x08; + } + else { + oasis_read(&info, 1, 1, in); + } + if (info & 0x04) { + // Explicit name + if (info & 0x02) { + // Reference number + oasis_skip_unsigned_integer(in); + modal_property_unfinished = true; + } + else { + oasis_skip_string(in); + modal_property_unfinished = false; + } + } + if (!(info & 0x08)) { + // Explicit value list + uint64_t num_values = info >> 4; + if (num_values == 15) { + num_values = oasis_read_unsigned_integer(in); + } + for (; num_values > 0; num_values--) { + OasisDataType data_type; + oasis_read(&data_type, 1, 1, in); + switch (data_type) { + case OasisDataType::RealPositiveInteger: + case OasisDataType::RealNegativeInteger: + case OasisDataType::RealPositiveReciprocal: + case OasisDataType::RealNegativeReciprocal: + case OasisDataType::RealPositiveRatio: + case OasisDataType::RealNegativeRatio: + case OasisDataType::RealFloat: + case OasisDataType::RealDouble: { + oasis_skip_real_by_type(in, data_type); + } break; + case OasisDataType::UnsignedInteger: { + oasis_skip_unsigned_integer(in); + } break; + case OasisDataType::SignedInteger: { + oasis_skip_integer(in); + } break; + case OasisDataType::AString: + case OasisDataType::BString: + case OasisDataType::NString: { + oasis_skip_string(in); + } break; + case OasisDataType::ReferenceA: + case OasisDataType::ReferenceB: + case OasisDataType::ReferenceN: { + oasis_skip_unsigned_integer(in); + } break; + } } } - modal_property_value_list = property->value; } } break; case OasisRecord::XNAME_IMPLICIT: { - oasis_read_unsigned_integer(in); - free_allocation(oasis_read_string(in, false, len)); + oasis_skip_unsigned_integer(in); + oasis_skip_string(in); if (error_logger) fputs("[GDSTK] Record type XNAME ignored.\n", error_logger); if (error_code) *error_code = ErrorCode::UnsupportedRecord; } break; case OasisRecord::XNAME: { - oasis_read_unsigned_integer(in); - free_allocation(oasis_read_string(in, false, len)); - oasis_read_unsigned_integer(in); + oasis_skip_unsigned_integer(in); + oasis_skip_string(in); + oasis_skip_unsigned_integer(in); if (error_logger) fputs("[GDSTK] Record type XNAME ignored.\n", error_logger); if (error_code) *error_code = ErrorCode::UnsupportedRecord; } break; case OasisRecord::XELEMENT: { - oasis_read_unsigned_integer(in); - free_allocation(oasis_read_string(in, false, len)); + oasis_skip_unsigned_integer(in); + oasis_skip_string(in); if (error_logger) fputs("[GDSTK] Record type XELEMENT ignored.\n", error_logger); if (error_code) *error_code = ErrorCode::UnsupportedRecord; } break; @@ -2428,7 +2694,7 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* if (info & 0x02) { modal_datatype = (uint32_t)oasis_read_unsigned_integer(in); } - free_allocation(oasis_read_string(in, false, len)); + oasis_skip_string(in); if (info & 0x10) { double x = factor * oasis_read_integer(in); if (modal_absolute_pos) { @@ -2550,9 +2816,11 @@ Library read_oas(const char* filename, double unit, double tolerance, ErrorCode* ErrorCode gds_units(const char* filename, double& unit, double& precision) { uint8_t buffer[65537]; uint64_t* data64 = (uint64_t*)(buffer + 4); - FILE* in = fopen(filename, "rb"); - if (in == NULL) { + FileWrapper* in = endsWithIgnoreCase(filename, ".gds.gz") ? (FileWrapper*)(new FileWrapperGZlib()) : (FileWrapper*)(new FileWrapperStd()); + + if (!in->Open(filename, "rb")) { fputs("[GDSTK] Unable to open GDSII file for input.\n", stderr); + delete in; return ErrorCode::InputFileOpenError; } @@ -2560,18 +2828,21 @@ ErrorCode gds_units(const char* filename, double& unit, double& precision) { uint64_t record_length = COUNT(buffer); ErrorCode error_code = gdsii_read_record(in, buffer, record_length); if (error_code != ErrorCode::NoError) { - fclose(in); + in->Close(); + delete in; return error_code; } if ((GdsiiRecord)buffer[2] == GdsiiRecord::UNITS) { big_endian_swap64(data64, 2); precision = gdsii_real_to_double(data64[1]); unit = precision / gdsii_real_to_double(data64[0]); - fclose(in); + in->Close(); + delete in; return ErrorCode::NoError; } } - fclose(in); + in->Close(); + delete in; fputs("[GDSTK] GDSII file missing units definition.\n", stderr); return ErrorCode::InvalidFile; } @@ -2581,7 +2852,7 @@ tm gds_timestamp(const char* filename, const tm* new_timestamp, ErrorCode* error uint8_t buffer[65537]; uint16_t* data16 = (uint16_t*)(buffer + 4); uint16_t new_tm_buffer[12]; - FILE* inout = NULL; + FileWrapper* inout = endsWithIgnoreCase(filename, ".gds.gz") ? (FileWrapper*)(new FileWrapperGZlib()) : (FileWrapper*)(new FileWrapperStd()); if (new_timestamp) { new_tm_buffer[0] = new_timestamp->tm_year + 1900; @@ -2592,14 +2863,17 @@ tm gds_timestamp(const char* filename, const tm* new_timestamp, ErrorCode* error new_tm_buffer[5] = new_timestamp->tm_sec; big_endian_swap16(new_tm_buffer, 6); memcpy(new_tm_buffer + 6, new_tm_buffer, 6 * sizeof(uint16_t)); - inout = fopen(filename, "r+b"); + if (!inout->Open(filename, "r+b")) { + if (error_logger) fputs("[GDSTK] Unable to open GDSII file.\n", error_logger); + if (error_code) *error_code = ErrorCode::InputFileOpenError; + return result; + } } else { - inout = fopen(filename, "rb"); - } - if (inout == NULL) { - if (error_logger) fputs("[GDSTK] Unable to open GDSII file.\n", error_logger); - if (error_code) *error_code = ErrorCode::InputFileOpenError; - return result; + if (!inout->Open(filename, "rb")) { + if (error_logger) fputs("[GDSTK] Unable to open GDSII file.\n", error_logger); + if (error_code) *error_code = ErrorCode::InputFileOpenError; + return result; + } } while (true) { @@ -2607,14 +2881,16 @@ tm gds_timestamp(const char* filename, const tm* new_timestamp, ErrorCode* error ErrorCode err = gdsii_read_record(inout, buffer, record_length); if (err != ErrorCode::NoError) { if (error_code) *error_code = err; - fclose(inout); + inout->Close(); + delete inout; return result; } GdsiiRecord record = (GdsiiRecord)buffer[2]; if (record == GdsiiRecord::BGNLIB) { if (record_length != 28) { - fclose(inout); + inout->Close(); + delete inout; if (error_logger) fputs("[GDSTK] Invalid or corrupted GDSII file.\n", error_logger); if (error_code) *error_code = ErrorCode::InvalidFile; return result; @@ -2627,37 +2903,42 @@ tm gds_timestamp(const char* filename, const tm* new_timestamp, ErrorCode* error result.tm_min = data16[4]; result.tm_sec = data16[5]; if (!new_timestamp) { - fclose(inout); + inout->Close(); + delete inout; return result; } - if (FSEEK64(inout, -24, SEEK_CUR) != 0) { - fclose(inout); + if ((inout->Seek(-24, SEEK_CUR)) != 0) { + inout->Close(); + delete inout; if (error_logger) fputs("[GDSTK] Unable to rewrite library timestamp.\n", error_logger); if (error_code) *error_code = ErrorCode::FileError; return result; } - fwrite(new_tm_buffer, sizeof(uint16_t), 12, inout); + inout->Write(new_tm_buffer, sizeof(uint16_t), 12); } else if (record == GdsiiRecord::BGNSTR && new_timestamp) { if (record_length != 28) { - fclose(inout); + inout->Close(); + delete inout; if (error_logger) fputs("[GDSTK] Invalid or corrupted GDSII file.\n", error_logger); if (error_code) *error_code = ErrorCode::InvalidFile; return result; } - if (FSEEK64(inout, -24, SEEK_CUR) != 0) { - fclose(inout); + if (inout->Seek(-24, SEEK_CUR) != 0) { + inout->Close(); + delete inout; if (error_logger) fputs("[GDSTK] Unable to rewrite cell timestamp.\n", error_logger); if (error_code) *error_code = ErrorCode::FileError; return result; } - fwrite(new_tm_buffer, sizeof(uint16_t), 12, inout); + inout->Write(new_tm_buffer, sizeof(uint16_t), 12); } else if (record == GdsiiRecord::ENDLIB) { break; } } - fclose(inout); + inout->Close(); + delete inout; return result; } @@ -2669,9 +2950,11 @@ ErrorCode gds_info(const char* filename, LibraryInfo& info) { uint64_t* data64 = (uint64_t*)(buffer + 4); char* str = (char*)(buffer + 4); - FILE* in = fopen(filename, "rb"); - if (in == NULL) { + FileWrapper* in = endsWithIgnoreCase(filename, ".gds.gz") ? (FileWrapper*)(new FileWrapperGZlib()) : (FileWrapper*)(new FileWrapperStd()); + + if (!in->Open(filename, "rb")) { if (error_logger) fputs("[GDSTK] Unable to open GDSII file for input.\n", error_logger); + delete in; return ErrorCode::InputFileOpenError; } @@ -2682,14 +2965,16 @@ ErrorCode gds_info(const char* filename, LibraryInfo& info) { uint64_t record_length = COUNT(buffer); ErrorCode err = gdsii_read_record(in, buffer, record_length); if (err != ErrorCode::NoError) { - fclose(in); + in->Close(); + delete in; return err; } uint64_t data_length; switch ((GdsiiRecord)(buffer[2])) { case GdsiiRecord::ENDLIB: - fclose(in); + in->Close(); + delete in; return error; break; case GdsiiRecord::STRNAME: { @@ -2912,5 +3197,8 @@ bool oas_validate(const char* filename, uint32_t* signature, ErrorCode* error_co return true; } +Library read_gds2(const char* filename, double unit, double tolerance, ErrorCode* error_code) { + return read_gds(filename, unit, tolerance,nullptr, nullptr,error_code); +} } // namespace gdstk diff --git a/src/oasis.cpp b/src/oasis.cpp index 298f3ce4e..f9ca6f285 100644 --- a/src/oasis.cpp +++ b/src/oasis.cpp @@ -42,6 +42,27 @@ ErrorCode oasis_read(void* buffer, size_t size, size_t count, OasisStream& in) { return in.error_code; } +ErrorCode oasis_skip(size_t size, size_t count, OasisStream& in) { + if (in.data) { + uint64_t total = size * count; + in.cursor += total; + if (in.cursor >= in.data + in.data_size) { + if (in.cursor > in.data + in.data_size) { + if (error_logger) + fputs("[GDSTK] Error seeking compressed data in file.\n", error_logger); + in.error_code = ErrorCode::InputFileError; + } + free_allocation(in.data); + in.data = NULL; + } + } + else if (fseek(in.file, long(size * count), SEEK_CUR)) { + if (error_logger) fputs("[GDSTK] Error seeking OASIS file.\n", error_logger); + in.error_code = ErrorCode::InputFileError; + } + return in.error_code; +} + static uint8_t oasis_peek(OasisStream& in) { uint8_t byte; if (in.data) { @@ -130,6 +151,37 @@ uint64_t oasis_read_unsigned_integer(OasisStream& in) { return result; } +ErrorCode oasis_skip_unsigned_integer(OasisStream& in) { + ErrorCode result = ErrorCode::NoError; + uint8_t byte; + + if ((result = oasis_read(&byte, 1, 1, in)) != ErrorCode::NoError) return result; + + uint8_t num_bits = 7; + while (byte & 0x80) { + if (oasis_read(&byte, 1, 1, in) != ErrorCode::NoError) return result; + num_bits += 7; + } + return result; +} + +void oasis_read_string2(OasisStream& in, Label* dest, uint64_t& capacity, uint64_t& count) { + count = oasis_read_unsigned_integer(in); + dest->text[0] = '\0'; + + if (count + 1 > capacity) { + dest->text = (char*)reallocate(dest->text, count + 1); + capacity = count + 1; + } + + if (oasis_read(dest->text, 1, count, in) != ErrorCode::NoError) { + dest->text[0] = '\0'; + count = (uint64_t)-1; + return; + } + dest->text[count++] = 0; +} + uint8_t* oasis_read_string(OasisStream& in, bool append_terminating_null, uint64_t& count) { uint8_t* bytes; count = oasis_read_unsigned_integer(in); @@ -143,7 +195,7 @@ uint8_t* oasis_read_string(OasisStream& in, bool append_terminating_null, uint64 if (oasis_read(bytes, 1, count, in) != ErrorCode::NoError) { free_allocation(bytes); bytes = NULL; - count = -1; + count = (uint64_t)-1; } if (append_terminating_null) { bytes[count++] = 0; @@ -160,6 +212,13 @@ uint8_t* oasis_read_string(OasisStream& in, bool append_terminating_null, uint64 return bytes; } +ErrorCode oasis_skip_string(OasisStream& in) +{ + uint64_t count; + count = oasis_read_unsigned_integer(in); + return oasis_skip(1, count, in); +} + static uint8_t oasis_read_int_internal(OasisStream& in, uint8_t skip_bits, int64_t& result) { uint8_t byte; if (oasis_read(&byte, 1, 1, in) != ErrorCode::NoError) return 0; @@ -182,12 +241,36 @@ static uint8_t oasis_read_int_internal(OasisStream& in, uint8_t skip_bits, int64 return bits; } +static ErrorCode oasis_skip_int_internal(OasisStream& in, uint8_t skip_bits) { + ErrorCode result = ErrorCode::NoError; + uint8_t byte; + if ((result = oasis_read(&byte, 1, 1, in)) != ErrorCode::NoError) return result; + + uint8_t num_bits = 7 - skip_bits; + while (byte & 0x80) { + if ((result = oasis_read(&byte, 1, 1, in)) != ErrorCode::NoError) return result; + if (num_bits > 56 && (byte >> (63 - num_bits)) > 0) { + result = ErrorCode::Overflow; + if (error_logger) + fputs("[GDSTK] Integer above maximal limit found. Clipping.\n", error_logger); + if (in.error_code == ErrorCode::NoError) in.error_code = ErrorCode::Overflow; + return result; + } + num_bits += 7; + } + return result; +} + int64_t oasis_read_integer(OasisStream& in) { int64_t value; if (oasis_read_int_internal(in, 1, value) > 0) return -value; return value; } +ErrorCode oasis_skip_integer(OasisStream& in) { + return oasis_skip_int_internal(in, 1); +} + void oasis_read_2delta(OasisStream& in, int64_t& x, int64_t& y) { int64_t value; switch ((OasisDirection)oasis_read_int_internal(in, 2, value)) { @@ -249,6 +332,21 @@ void oasis_read_3delta(OasisStream& in, int64_t& x, int64_t& y) { } } +ErrorCode oasis_skip_gdelta(OasisStream& in) +{ + ErrorCode result = ErrorCode::NoError; + uint8_t bits = oasis_peek(in); + if (in.error_code != ErrorCode::NoError) return in.error_code; + + if ((bits & 0x01) == 0) { + oasis_skip_int_internal(in, 4); + } + else { + oasis_skip_int_internal(in, 2); + oasis_skip_int_internal(in, 1); + } + return result; +} void oasis_read_gdelta(OasisStream& in, int64_t& x, int64_t& y) { uint8_t bits = oasis_peek(in); if (in.error_code != ErrorCode::NoError) return; @@ -333,6 +431,85 @@ double oasis_read_real_by_type(OasisStream& in, OasisDataType type) { return 0; } +ErrorCode oasis_skip_real_by_type(OasisStream& in, OasisDataType type) { + ErrorCode result; + switch ((OasisDataType)type) { + case OasisDataType::RealPositiveInteger: + return oasis_skip_unsigned_integer(in); + case OasisDataType::RealNegativeInteger: + return oasis_skip_unsigned_integer(in); + case OasisDataType::RealPositiveReciprocal: + return oasis_skip_unsigned_integer(in); + case OasisDataType::RealNegativeReciprocal: + return oasis_skip_unsigned_integer(in); + case OasisDataType::RealPositiveRatio: { + if ((result = oasis_skip_unsigned_integer(in)) != ErrorCode::NoError) return result; + return oasis_skip_unsigned_integer(in); + } + case OasisDataType::RealNegativeRatio: { + if ((result = oasis_skip_unsigned_integer(in)) != ErrorCode::NoError) return result; + return oasis_skip_unsigned_integer(in); + } + case OasisDataType::RealFloat: { + return oasis_skip(sizeof(float), 1, in); + } + case OasisDataType::RealDouble: { + return oasis_skip(sizeof(double), 1, in); + } + default: + result = ErrorCode::InvalidFile; + if (error_logger) fputs("[GDSTK] Unable to determine real value.\n", error_logger); + if (in.error_code == ErrorCode::NoError) in.error_code = ErrorCode::InvalidFile; + return result; + } +} + +ErrorCode oasis_skip_point_list(OasisStream& in) +{ + ErrorCode result = ErrorCode::NoError; + + uint8_t byte; + if ((result = oasis_read(&byte, 1, 1, in)) != ErrorCode::NoError) return result; + + uint64_t num = oasis_read_unsigned_integer(in); + if (in.error_code != ErrorCode::NoError) return in.error_code; + + switch ((OasisPointList)byte) { + case OasisPointList::ManhattanHorizontalFirst: + case OasisPointList::ManhattanVerticalFirst: { + for (uint64_t i = num; i > 0; i--) { + oasis_skip_integer(in); + } + } break; + case OasisPointList::Manhattan: { + for (uint64_t i = num; i > 0; i--) { + oasis_skip_int_internal(in, 2); + } + } break; + case OasisPointList::Octangular: { + for (uint64_t i = num; i > 0; i--) { + oasis_skip_int_internal(in, 3); + } + } break; + case OasisPointList::General: { + for (uint64_t i = num; i > 0; i--) { + oasis_skip_gdelta(in); + } + } break; + case OasisPointList::Relative: { + for (uint64_t i = num; i > 0; i--) { + oasis_skip_gdelta(in); + } + } break; + default: + result = ErrorCode::InvalidFile; + if (error_logger) fputs("[GDSTK] Point list type not supported.\n", error_logger); + if (in.error_code == ErrorCode::NoError) in.error_code = ErrorCode::InvalidFile; + return result; + } + return result; +} + uint64_t oasis_read_point_list(OasisStream& in, double scaling, bool closed, Array& result) { assert(result.count > 0); @@ -430,6 +607,74 @@ uint64_t oasis_read_point_list(OasisStream& in, double scaling, bool closed, Arr return num; } +ErrorCode oasis_skip_repetition(OasisStream& in) +{ + uint8_t type; + ErrorCode result = ErrorCode::NoError; + + if ((result = oasis_read(&type, 1, 1, in)) != ErrorCode::NoError) return result; + + if (type == 0) return result; + + switch (type) { + case 1: { + oasis_skip_unsigned_integer(in); + oasis_skip_unsigned_integer(in); + oasis_skip_unsigned_integer(in); + oasis_skip_unsigned_integer(in); + } break; + case 2: { + oasis_skip_unsigned_integer(in); + oasis_skip_unsigned_integer(in); + } break; + case 3: { + oasis_skip_unsigned_integer(in); + oasis_skip_unsigned_integer(in); + } break; + case 4: + case 5: { + uint64_t count = 1 + oasis_read_unsigned_integer(in); + if (type == 5) { + oasis_skip_unsigned_integer(in); + } + for (; count > 0; count--) { + oasis_skip_unsigned_integer(in); + } + } break; + case 6: + case 7: { + uint64_t count = 1 + oasis_read_unsigned_integer(in); + if (type == 7) { + oasis_skip_unsigned_integer(in); + } + for (; count > 0; count--) { + oasis_skip_unsigned_integer(in); + } + } break; + case 8: { + oasis_skip_unsigned_integer(in); + oasis_skip_unsigned_integer(in); + oasis_skip_gdelta(in); + oasis_skip_gdelta(in); + } break; + case 9: { + oasis_skip_unsigned_integer(in); + oasis_skip_gdelta(in); + } break; + case 10: + case 11: { + uint64_t count = 1 + oasis_read_unsigned_integer(in); + if (type == 11) { + oasis_skip_unsigned_integer(in); + } + for (; count > 0; count--) { + oasis_skip_gdelta(in); + } + } break; + } + return result; +} + void oasis_read_repetition(OasisStream& in, double scaling, Repetition& repetition) { uint8_t type; @@ -437,7 +682,7 @@ void oasis_read_repetition(OasisStream& in, double scaling, Repetition& repetiti if (type == 0) return; - repetition.clear(); + repetition.clear(false); switch (type) { case 1: { @@ -870,7 +1115,7 @@ void oasis_write_point_list(OasisStream& out, const Array points, double s scaled_points.clear(); } -void oasis_write_repetition(OasisStream& out, const Repetition repetition, double scaling) { +void oasis_write_repetition(OasisStream& out, const Repetition &repetition, double scaling) { switch (repetition.type) { case RepetitionType::Rectangular: { if (repetition.columns > 1 && repetition.rows > 1) { diff --git a/src/polygon.cpp b/src/polygon.cpp index c436b0b59..3d87ab3fd 100644 --- a/src/polygon.cpp +++ b/src/polygon.cpp @@ -45,10 +45,26 @@ void Polygon::clear() { } void Polygon::copy_from(const Polygon& polygon) { - tag = polygon.tag; - point_array.copy_from(polygon.point_array); - repetition.copy_from(polygon.repetition); - properties = properties_copy(polygon.properties); + + if (point_array.capacity >= polygon.point_array.capacity) { + repetition.clear(false); + properties_clear(properties); + + point_array.count = polygon.point_array.count; + memcpy(point_array.items, polygon.point_array.items, sizeof(Vec2) * point_array.count); + + tag = polygon.tag; + repetition.copy_from(polygon.repetition); + properties = properties_copy(polygon.properties); + } + else { + clear(); + point_array.copy_from(polygon.point_array); + tag = polygon.tag; + repetition.copy_from(polygon.repetition); + properties = properties_copy(polygon.properties); + } + } double Polygon::area() const { @@ -420,7 +436,7 @@ void Polygon::apply_repetition(Array& result) { Array offsets = {}; repetition.get_offsets(offsets); - repetition.clear(); + // repetition.clear(); do not clear to allow for multiple iteration on the polygon // Skip first offset (0, 0) Vec2* offset_p = offsets.items + 1; @@ -429,6 +445,7 @@ void Polygon::apply_repetition(Array& result) { Polygon* poly = (Polygon*)allocate_clear(sizeof(Polygon)); poly->copy_from(*this); poly->translate(*offset_p++); + poly->repetition.clear(); result.append_unsafe(poly); } @@ -1006,6 +1023,7 @@ ErrorCode Polygon::to_svg(FILE* out, double scaling, uint32_t precision) const { Polygon rectangle(const Vec2 corner1, const Vec2 corner2, Tag tag) { Polygon result = {}; + memset(&result, 0, sizeof(Polygon)); result.tag = tag; result.point_array.ensure_slots(4); result.point_array.count = 4; diff --git a/src/rawcell.cpp b/src/rawcell.cpp index c05c42503..10edd0335 100644 --- a/src/rawcell.cpp +++ b/src/rawcell.cpp @@ -45,7 +45,8 @@ void RawCell::clear() { if (source) { source->uses--; if (source->uses == 0) { - fclose(source->file); + source->file->Close(); + delete source->file; free_allocation(source); } source = NULL; @@ -83,7 +84,8 @@ ErrorCode RawCell::to_gds(FILE* out) { } source->uses--; if (source->uses == 0) { - fclose(source->file); + source->file->Close(); + delete source->file; free_allocation(source); } source = NULL; @@ -99,10 +101,13 @@ Map read_rawcells(const char* filename, ErrorCode* error_code) { RawSource* source = (RawSource*)allocate(sizeof(RawSource)); source->uses = 0; - source->file = fopen(filename, "rb"); - if (source->file == NULL) { + source->file = endsWithIgnoreCase(filename, ".gds.gz") + ? (FileWrapper*)(new FileWrapperGZlib()) + : (FileWrapper*)(new FileWrapperStd()); + if (!source->file->Open(filename, "rb")) { if (error_logger) fputs("[GDSTK] Unable to open input GDSII file.\n", error_logger); if (error_code) *error_code = ErrorCode::InputFileOpenError; + delete source->file; return result; } @@ -141,7 +146,8 @@ Map read_rawcells(const char* filename, ErrorCode* error_code) { } } if (source->uses == 0) { - fclose(source->file); + source->file->Close(); + delete source->file; free_allocation(source); } return result; @@ -150,7 +156,7 @@ Map read_rawcells(const char* filename, ErrorCode* error_code) { rawcell = (RawCell*)allocate_clear(sizeof(RawCell)); rawcell->source = source; source->uses++; - rawcell->offset = ftell(source->file) - record_length; + rawcell->offset = source->file->Tell() - record_length; rawcell->size = record_length; break; case 0x06: // STRNAME @@ -196,7 +202,8 @@ Map read_rawcells(const char* filename, ErrorCode* error_code) { } rawcell->clear(); } - fclose(source->file); + source->file->Close(); + delete source->file; free_allocation(source); result.clear(); if (error_logger) fprintf(error_logger, "[GDSTK] Invalid GDSII file %s.\n", filename); diff --git a/src/reference.cpp b/src/reference.cpp index 8868c4c93..096df6b38 100644 --- a/src/reference.cpp +++ b/src/reference.cpp @@ -5,9 +5,6 @@ Boost Software License - Version 1.0. See the accompanying LICENSE file or */ -#define __STDC_FORMAT_MACROS 1 -#define _USE_MATH_DEFINES - #include #include #include @@ -20,6 +17,8 @@ LICENSE file or #include #include #include +#include +#include namespace gdstk { @@ -198,7 +197,7 @@ void Reference::apply_repetition(Array& result) { Array offsets = {}; repetition.get_offsets(offsets); - repetition.clear(); + //repetition.clear(); do not clear to allow multiple iterations on the reference // Skip first offset (0, 0) double* offset_p = (double*)(offsets.items + 1); @@ -208,6 +207,7 @@ void Reference::apply_repetition(Array& result) { reference->copy_from(*this); reference->origin.x += *offset_p++; reference->origin.y += *offset_p++; + reference->repetition.clear(); result.append_unsafe(reference); } @@ -218,12 +218,20 @@ void Reference::apply_repetition(Array& result) { // Depth is passed as-is to Cell::get_polygons, where it is inspected and applied. void Reference::get_polygons(bool apply_repetitions, bool include_paths, int64_t depth, bool filter, Tag tag, Array& result) const { + + std::set filters; + if (filter)filters.insert(tag); + get_polygons(apply_repetitions, include_paths, depth, filter ? &filters : nullptr, result); +} + +void Reference::get_polygons(bool apply_repetitions, bool include_paths, int64_t depth, + std::set* _tags, Array& result) const { if (type != ReferenceType::Cell) return; Array array = {}; - cell->get_polygons(apply_repetitions, include_paths, depth, filter, tag, array); + cell->get_polygons(apply_repetitions, include_paths, depth, _tags, array); - Vec2 zero = {0, 0}; + Vec2 zero = { 0, 0 }; Array offsets = {}; if (repetition.type != RepetitionType::None) { repetition.get_offsets(offsets); @@ -330,16 +338,24 @@ void Reference::get_robustpaths(bool apply_repetitions, int64_t depth, bool filt void Reference::get_labels(bool apply_repetitions, int64_t depth, bool filter, Tag tag, Array& result) const { + std::set filters; + if (filter)filters.insert(tag); + get_labels(apply_repetitions, depth, filter ? &filters : nullptr, result); +} + +void Reference::get_labels(bool apply_repetitions, int64_t depth, std::set*_tags, + Array& result) const { if (type != ReferenceType::Cell) return; Array array = {}; - cell->get_labels(apply_repetitions, depth, filter, tag, array); + cell->get_labels(apply_repetitions, depth, _tags, array); - Vec2 zero = {0, 0}; + Vec2 zero = { 0, 0 }; Array offsets = {}; if (repetition.type != RepetitionType::None) { repetition.get_offsets(offsets); - } else { + } + else { offsets.count = 1; offsets.items = &zero; } diff --git a/src/repetition.cpp b/src/repetition.cpp index 486e68c30..778940940 100644 --- a/src/repetition.cpp +++ b/src/repetition.cpp @@ -44,16 +44,31 @@ void Repetition::print() const { } } -void Repetition::clear() { - if (type == RepetitionType::Explicit) { - offsets.clear(); - } else if (type == RepetitionType::ExplicitX || type == RepetitionType::ExplicitY) { - coords.clear(); +void Repetition::clear(bool deallocate) { + if (deallocate) + { + if (type == RepetitionType::Explicit) { + offsets.clear(); + } + else if (type == RepetitionType::ExplicitX || type == RepetitionType::ExplicitY) { + coords.clear(); + } + memset(this, 0, sizeof(Repetition)); + } + else + { + offsets.clear(deallocate); + coords.clear(deallocate); + type = RepetitionType::None; + columns = 0; + rows = 0; + memset(&spacing, 0, sizeof(Vec2)); + memset(&v1, 0, sizeof(Vec2)); + memset(&v2, 0, sizeof(Vec2)); } - memset(this, 0, sizeof(Repetition)); } -void Repetition::copy_from(const Repetition repetition) { +void Repetition::copy_from(const Repetition& repetition) { type = repetition.type; switch (type) { case RepetitionType::Rectangular: diff --git a/src/robustpath.cpp b/src/robustpath.cpp index fbac38636..419cb8f3d 100644 --- a/src/robustpath.cpp +++ b/src/robustpath.cpp @@ -18,6 +18,8 @@ LICENSE file or #include #include #include +#include +#include namespace gdstk { @@ -1270,13 +1272,28 @@ ErrorCode RobustPath::spine(Array &result) const { } ErrorCode RobustPath::to_polygons(bool filter, Tag tag, Array &result) const { + std::set tags; + if (filter) { + tags.insert(tag); + return to_polygons(&tags, result); + } + else { + return to_polygons(nullptr, result); + } +} + +ErrorCode RobustPath::to_polygons(const std::set *_tags, Array& result) const { ErrorCode error_code = ErrorCode::NoError; if (num_elements == 0 || subpath_array.count == 0) return error_code; const double tolerance_sq = tolerance * tolerance; - RobustPathElement *el = elements; + RobustPathElement* el = elements; for (uint64_t ne = 0; ne < num_elements; ne++, el++) { - if (filter && el->tag != tag) continue; + bool load = true; + if (_tags) { + load = _tags->find(el->tag) != _tags->end(); + } + if (!load) continue; Array left_side = {}; Array right_side = {}; @@ -1324,7 +1341,7 @@ ErrorCode RobustPath::to_polygons(bool filter, Tag tag, Array &result double angles[2] = {(-grad_l).angle(), grad_r.angle()}; Vec2 tension[2] = {Vec2{1, 1}, Vec2{1, 1}}; initial_cap.interpolation(point_array, angles, angle_constraints, tension, 1, 1, - false, false); + false, false); } else if (el->end_type == EndType::Function) { Vec2 dir_l = -left_gradient(subpath_array[0], el->offset_array[0], el->width_array[0], 0); @@ -1392,9 +1409,9 @@ ErrorCode RobustPath::to_polygons(bool filter, Tag tag, Array &result { // End cap const uint64_t last = subpath_array.count - 1; const Vec2 cap_l = left_position(subpath_array[last], el->offset_array[last], - el->width_array[last], 1); + el->width_array[last], 1); const Vec2 cap_r = right_position(subpath_array[last], el->offset_array[last], - el->width_array[last], 1); + el->width_array[last], 1); if (el->end_type == EndType::Flush) { final_cap.append(cap_r); if ((cap_l - cap_r).length_sq() > tolerance_sq) final_cap.append(cap_l); @@ -1422,18 +1439,18 @@ ErrorCode RobustPath::to_polygons(bool filter, Tag tag, Array &result point_array.count = 1; bool angle_constraints[2] = {true, true}; const Vec2 grad_l = left_gradient(subpath_array[last], el->offset_array[last], - el->width_array[last], 1); + el->width_array[last], 1); const Vec2 grad_r = right_gradient(subpath_array[last], el->offset_array[last], - el->width_array[last], 1); + el->width_array[last], 1); double angles[2] = {grad_r.angle(), (-grad_l).angle()}; Vec2 tension[2] = {Vec2{1, 1}, Vec2{1, 1}}; final_cap.interpolation(point_array, angles, angle_constraints, tension, 1, 1, - false, false); + false, false); } else if (el->end_type == EndType::Function) { Vec2 dir_l = -left_gradient(subpath_array[last], el->offset_array[last], - el->width_array[last], 1); + el->width_array[last], 1); Vec2 dir_r = right_gradient(subpath_array[last], el->offset_array[last], - el->width_array[last], 1); + el->width_array[last], 1); dir_l.normalize(); dir_r.normalize(); Array point_array = From eab99dea86bd2d2ed0d9eefb579acdb1be46ae1e Mon Sep 17 00:00:00 2001 From: "Michael L. Walker" Date: Fri, 27 Dec 2024 00:27:56 -0700 Subject: [PATCH 5/5] Fix memory leak --- src/library.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/library.cpp b/src/library.cpp index 927091618..2c8adbf34 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -2712,7 +2712,7 @@ Library read_oas(const char* filename, double unit, } } if (info & 0x04) { - oasis_read_repetition(in, factor, modal_repetition); + oasis_skip_repetition(in); } if (error_logger) fputs("[GDSTK] Record type XGEOMETRY ignored.\n", error_logger); if (error_code) *error_code = ErrorCode::UnsupportedRecord; @@ -2805,6 +2805,7 @@ Library read_oas(const char* filename, double unit, modal_repetition.clear(); modal_polygon_points.clear(); + modal_trapezoid_points.clear(); modal_path_points.clear(); unfinished_property_name.clear();