Compare commits

...

8 commits

4 changed files with 20 additions and 20 deletions

View file

@ -4,7 +4,6 @@
**Homepage:** https://mpxd.net/code/jan/fatamorgana **Homepage:** https://mpxd.net/code/jan/fatamorgana
* [PyPI](https://pypi.org/project/fatamorgana) * [PyPI](https://pypi.org/project/fatamorgana)
* [Github mirror](https://github.com/anewusername/fatamorgana)
**Capabilities:** **Capabilities:**
* This package is a work-in-progress and is largely untested -- it works for * This package is a work-in-progress and is largely untested -- it works for
@ -28,12 +27,7 @@
Install with pip from PyPi (preferred): Install with pip from PyPi (preferred):
```bash ```bash
pip3 install fatamorgana pip install fatamorgana
```
Install directly from git repository:
```bash
pip3 install git+https://mpxd.net/code/jan/fatamorgana.git@release
``` ```
## Documentation ## Documentation
@ -44,7 +38,6 @@ To read the inline help,
import fatamorgana import fatamorgana
help(fatamorgana.OasisLayout) help(fatamorgana.OasisLayout)
``` ```
The documentation is currently very sparse and I expect to improve it whenever possible!
## Examples ## Examples

View file

@ -2,7 +2,7 @@
This module contains all datatypes and parsing/writing functions for This module contains all datatypes and parsing/writing functions for
all abstractions below the 'record' or 'block' level. all abstractions below the 'record' or 'block' level.
""" """
from typing import Any, IO, Union from typing import Any, IO, Union, TYPE_CHECKING
from collections.abc import Sequence from collections.abc import Sequence
from fractions import Fraction from fractions import Fraction
from enum import Enum from enum import Enum
@ -250,6 +250,7 @@ def write_uint(stream: IO[bytes], n: int) -> int:
Raises: Raises:
SignedError: if `n` is negative. SignedError: if `n` is negative.
""" """
n = int(n)
if n < 0: if n < 0:
raise SignedError(f'uint must be positive: {n}') raise SignedError(f'uint must be positive: {n}')
@ -295,6 +296,7 @@ def encode_sint(sint: int) -> int:
Returns: Returns:
Unsigned integer encoding for the input. Unsigned integer encoding for the input.
""" """
sint = int(sint)
return (abs(sint) << 1) | (sint < 0) return (abs(sint) << 1) | (sint < 0)
@ -1211,6 +1213,10 @@ class GridRepetition:
InvalidDataError: if `b_count` and `b_vector` inputs conflict InvalidDataError: if `b_count` and `b_vector` inputs conflict
with each other or if `a_count < 1`. with each other or if `a_count < 1`.
""" """
a_count = int(a_count)
if b_count is not None:
b_count = int(b_count)
if b_vector is None or b_count is None: if b_vector is None or b_count is None:
if b_vector is not None or b_count is not None: if b_vector is not None or b_count is not None:
raise InvalidDataError('Repetition has only one of' raise InvalidDataError('Repetition has only one of'
@ -1595,7 +1601,7 @@ def read_point_list(
def write_point_list( def write_point_list(
stream: IO[bytes], stream: IO[bytes],
points: list[Sequence[int]], points: 'list[Sequence[int]] | NDArray',
fast: bool = False, fast: bool = False,
implicit_closed: bool = True implicit_closed: bool = True
) -> int: ) -> int:
@ -1618,6 +1624,8 @@ def write_point_list(
Number of bytes written. Number of bytes written.
""" """
# If we're in a hurry, just write the points as arbitrary Deltas # If we're in a hurry, just write the points as arbitrary Deltas
if _USE_NUMPY:
points = numpy.asarray(points, dtype=int)
if fast: if fast:
size = write_uint(stream, 4) size = write_uint(stream, 4)
size += write_uint(stream, len(points)) size += write_uint(stream, len(points))

View file

@ -1434,7 +1434,7 @@ class Placement(Record):
size += self.name.write(stream) # type: ignore size += self.name.write(stream) # type: ignore
if mm: if mm:
size += write_real(stream, self.magnification) # type: ignore size += write_real(stream, self.magnification) # type: ignore
if aa: if aq:
size += write_real(stream, self.angle) # type: ignore size += write_real(stream, self.angle) # type: ignore
if xx: if xx:
size += write_sint(stream, self.x) # type: ignore size += write_sint(stream, self.x) # type: ignore
@ -1717,8 +1717,8 @@ class Polygon(Record, GeometryMixin):
repetition: repetition_t | None repetition: repetition_t | None
point_list: point_list_t | None point_list: point_list_t | None
""" """
List of offsets from the initial vertex (x, y) to the remaining List of offsets between consecutive vertices, starting from the initial
vertices, `[[dx0, dy0], [dx1, dy1], ...]`. vertex (x, y): `[[dx0, dy0], [dx1, dy1], ...]`.
The list is an implicitly closed path, vertices are [int, int]. The list is an implicitly closed path, vertices are [int, int].
The initial vertex is located at (x, y) and is not represented in `point_list`. The initial vertex is located at (x, y) and is not represented in `point_list`.
`None` means reuse modal. `None` means reuse modal.
@ -1744,7 +1744,7 @@ class Polygon(Record, GeometryMixin):
self.point_list = point_list self.point_list = point_list
self.properties = [] if properties is None else properties self.properties = [] if properties is None else properties
if point_list is not None and len(point_list) < 3: if point_list is not None and len(point_list) < 2:
warn('Polygon with < 3 points', stacklevel=2) warn('Polygon with < 3 points', stacklevel=2)
def get_point_list(self) -> point_list_t: def get_point_list(self) -> point_list_t:
@ -1827,8 +1827,8 @@ class Path(Record, GeometryMixin):
repetition: repetition_t | None = None repetition: repetition_t | None = None
point_list: point_list_t | None = None point_list: point_list_t | None = None
""" """
List of offsets from the initial vertex (x, y) to the remaining vertices, List of offsets between consecutive vertices, starting from the initial
`[[dx0, dy0], [dx1, dy1], ...]`. vertex (x, y): `[[dx0, dy0], [dx1, dy1], ...]`.
The initial vertex is located at (x, y) and is not represented in `point_list`. The initial vertex is located at (x, y) and is not represented in `point_list`.
Offsets are [int, int]; `None` means reuse modal. Offsets are [int, int]; `None` means reuse modal.
""" """
@ -1960,7 +1960,7 @@ class Path(Record, GeometryMixin):
dd = self.datatype is not None dd = self.datatype is not None
ll = self.layer is not None ll = self.layer is not None
size = write_uint(stream, 21) size = write_uint(stream, 22)
size += write_bool_byte(stream, (ee, ww, pp, xx, yy, rr, dd, ll)) size += write_bool_byte(stream, (ee, ww, pp, xx, yy, rr, dd, ll))
if ll: if ll:
size += write_uint(stream, self.layer) # type: ignore size += write_uint(stream, self.layer) # type: ignore

View file

@ -34,15 +34,14 @@ keywords = [
] ]
classifiers = [ classifiers = [
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Development Status :: 3 - Alpha", "Development Status :: 4 - Beta",
"Environment :: Other Environment",
"Intended Audience :: Developers", "Intended Audience :: Developers",
"Intended Audience :: Information Technology", "Intended Audience :: Information Technology",
"Intended Audience :: Manufacturing", "Intended Audience :: Manufacturing",
"Intended Audience :: Science/Research", "Intended Audience :: Science/Research",
"License :: OSI Approved :: GNU Affero General Public License v3", "License :: OSI Approved :: GNU Affero General Public License v3",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
"Topic :: File Formats",
] ]
requires-python = ">=3.11" requires-python = ">=3.11"
dynamic = ["version"] dynamic = ["version"]