Path

class photonforge.Path(origin, width, offset=0, caps=(0, 0), scale_profile=True)

Planar path object.

Parameters:
  • origin (Sequence[float] | complex) – Path starting vertex.

  • width (float) – Path width.

  • offset (float) – Othogonal offset from the central path spine.

  • caps (tuple[float | Literal["round"], float | Literal["round"]]) – End caps specification for both path ends. Each value represents the fraction of the width by which the path is extended. Each value can also be set to "round" for rounded caps.

  • scale_profile (bool) – Indicate whether the width and offset of this path should scale when the path is scaled.

Note

Arguments width and offset are values in the constructor, but can be an interpolation specification in all section builders (e.g., Path.segment()). The specification can be:

  • value: same as (value, "linear").

  • (value, "constant"): constant value over the whole section.

  • (to_value, "linear"): linear interpolation from the current value to to_value.

  • (from_value, to_value, "linear"): linear interpolation from from_value to to_value.

  • (to_value, "smooth"): smooth interpolation from the current value to to_value (uses a 3rd degree polynomial with zero derivatives at both endpoints).

  • (from_value, to_value, "smooth"): smooth interpolation from from_value to to_value.

  • (value_expression, derivative_expression): string expresssions evaluated along the path to get the width/offset value and its derivative, parametrized by the independet variable "u", which varies from 0 to 1 along the path. See the example below and the documentation on Expression for available operators.

  • expression: Expression with 1 parameter and at least 2 expressions. The last 2 expressions are used as position and derivative, respectively.

Example

>>> path = Path((0, 0), 0.5)
>>> path.segment((3, 0), ("0.5 + 0.5 * u^2", "u"))
>>> e = Expression(
...     "s", [("p", 3), "0.5 - 0.5 * s^p", "-0.5 * p * s^(p - 1)"]
... )
>>> path.segment((6, 0), e)

Methods

add_gds_property(value)

Add a custom property to this object compatible with GDSII files.

arc(initial_angle, final_angle[, radius, ...])

Add a circular, elliptical, or Euler arc to this path.

area()

Structure area.

at(u[, output])

Return position, width, offset and gradient at a specific path location.

bezier(controls[, width, offset, relative, ...])

Add a Bézier curve to this path.

bounds()

Calculate the structure bounds

center()

Get the central vertices of the path, accounting for offsets.

copy(self)

Create a copy of this structure.

interpolate(distances[, include_offset, output])

Path positions at specific distances from the origin along the path.

left_vertices()

Get the left-side vertices of the path.

length([include_offset])

Length of the path.

mirror([axis_endpoint, axis_origin])

Mirror this structure.

parametric(position[, gradient, width, ...])

Add a parametric curve to this path.

perimeter()

Structure perimeter.

right_vertices()

Get the right-side vertices of the path.

rotate(rotation[, center])

Rotate this structure.

s_bend(endpoint[, euler_fraction, ...])

Add an S bend section to the path.

scale(scaling[, center])

Scale this structure.

segment(endpoint[, width, offset, ...])

Add a straight segment to this path.

spine()

Get the central vertices of the path, not taking offsets into account.

to_polygon()

Create a Polygon from this structure.

transform([translation, rotation, scaling, ...])

Apply a transformation to this structure: self = translate(rotate(mirror(scale(self))))

translate(translation)

Translate this structure.

turn(angle[, radius, euler_fraction, ...])

Add a circular or Euler turn to this path.

updated_copy(width[, offset, ...])

Create a copy of this path with a new width and offset.

Attributes

caps

Path cap extensions.

json

(DEPRECATED) Json representation of this layer specification.

origin

Path origin.

properties

Object properties.

scale_profile

Profile scaling flag.

size

Number of path sections (read only).

x_max

Upper bound in the x axis.

x_mid

Bounding box center in the x axis.

x_min

Lower bound in the x axis.

y_max

Upper bound in the y axis.

y_mid

Bounding box center in the y axis.

y_min

Lower bound in the y axis.

add_gds_property(value)

Add a custom property to this object compatible with GDSII files.

Parameters:
  • attribute (int) – Property number.

  • value (str) – Property value.

arc(initial_angle, final_angle, radius=None, rotation=0, euler_fraction=None, endpoint=None, width=None, offset=None, min_evals=0, max_evals=10000)

Add a circular, elliptical, or Euler arc to this path.

Parameters:
  • initial_angle (float) – Starting angle of the arc (in degrees).

  • final_angle (float) – Ending angle of the arc (in degrees).

  • radius (float | Sequence[float] | None) – Arc radius. A sequence of 2 numbers can be passed to create an elliptical arc. If None, look for deafult in config.default_kwargs.

  • rotation (float) – For elliptical arcs, the rotation of the main axis (in degrees).

  • euler_fraction (float | None) – Fraction of the bend that is created using an Euler spiral (see note). It cannot be used for elliptical arcs. If None, look for deafult in config.default_kwargs.

  • endpoint (Sequence[float] | complex | None) – If set, force the arc to end exactly at these coordinates, compensating any numerical inaccuracies from the arc computation.

  • width (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path width over this section. It can be a number (linear interpolation from the current width over the whole section) or an interpolation specification (see the note in the class documentation).

  • offset (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path offset over this section. It can be a number (linear interpolation from the current offset over the whole section) or an interpolation specification (see the note in the class documentation).

  • min_evals (int) – Minimal number of evaluations when calculating the path boundaries and intersections.

  • max_evals (int) – Maximal number of evaluations when calculating the path boundaries and intersections.

Returns:

This path.

Return type:

Path

Example

>>> path = Path((0, 0), 0.5)
>>> path.arc(0, 90, 10, euler_fraction=0.5)
>>> path.arc(270, 90, (10, 6))

Note

The Euler bend fraction is implemented following the coefficient \(p\) in the work by Florian Vogelbacher et al., “Analysis of silicon nitride partial Euler waveguide bends,” Opt. Express 27, 31394-31406 (2019), doi: 10.1364/OE.27.031394.

The defaults are read from a dictionary under the key "Path" in config.default_kwargs, or directly at the root.

area()

Structure area.

Returns:

Area of the structure.

Return type:

float

at(u, output='all')

Return position, width, offset and gradient at a specific path location.

Parameters:
  • u (float) – Parameter that defines the location along the path, ranging from 0 to Path.size.

  • output (Literal["all", "position", "width", "offset", "gradient"]) – Output selection setting.

Returns:

Tuple with position, width, offset and gradient. If output is not “all”, only the requested value is returned.

Return type:

tuple[ndarray, float, float, ndarray] | ndarray | float

Note

This function evaluates the path at a single path section identified by the integral part of u. It does not take into account intersection calculations between adjacent sections.

Example

>>> path = Path((0, 0), 0.5).segment([(10, 0), (10, 6)], 1)
>>> path.at(0.5)
(array([5., 0.]), 0.625, 0.0, array([10.,  0.]))
>>> path.at(path.size)
(array([10.,  6.]), 1.0, 0.0, array([0., 6.]))

See also

Path.interpolate() for length-based parametrization including intersections.

bezier(controls, width=None, offset=None, relative=False, min_evals=0, max_evals=10000)

Add a Bézier curve to this path.

Parameters:
  • controls (Sequence[Sequence[float] | complex]) – Bézier curve control points (at least 2).

  • width (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path width over this section. It can be a number (linear interpolation from the current width over the whole section) or an interpolation specification (see the note in the class documentation).

  • offset (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path offset over this section. It can be a number (linear interpolation from the current offset over the whole section) or an interpolation specification (see the note in the class documentation).

  • relative (bool) – If set, the controls are calculated relative to the current end point of the path.

  • min_evals (int) – Minimal number of evaluations when calculating the path boundaries and intersections.

  • max_evals (int) – Maximal number of evaluations when calculating the path boundaries and intersections.

Returns:

This path.

Return type:

Path

Example

>>> path = Path((0, 0), 0.5)
>>> path.bezier([(10, 0), (10, 5), (0, 10)])
bounds()

Calculate the structure bounds

Returns:

The lower-left and upper-right corners of the bounding box of the structure: ((min_x, min_y), (max_x, max_y)).

Return type:

tuple[ndarray, ndarray]

Example

>>> polygon = Polygon([(0, 1), (1, 2), (3, -1)])
>>> bounds = polygon.bounds()
>>> print(bounds)
((0.0, -1.0), (3.0, 2.0))
caps

Path cap extensions.

Type:

tuple[float | Literal[“round”], float | Literal[“round”]]

center()

Get the central vertices of the path, accounting for offsets.

Returns:

Array of coordinates.

Return type:

ndarray

copy(self)

Create a copy of this structure.

Returns:

New copy.

Return type:

Path

interpolate(distances, include_offset=True, output='all')

Path positions at specific distances from the origin along the path.

Parameters:
  • distances (Sequence[float] | float) – Distances along the path to interpolate. Values below 0 will return the path origin and values above Path.length() will return its endpoint.

  • include_offset (bool) – If True, the positions are calculated based on Path.center() vertices, otherwise on Path.spine().

  • output (Literal["all", "position", "width", "offset", "gradient"]) – Output selection setting.

Returns:

Tuple with interpolated position, width, offset and gradient. If output is not “all”, only the requested value is returned.

Return type:

tuple[ndarray, ndarray, ndarray, ndarray] | ndarray

Note

Gradients are returned normalized.

json

(DEPRECATED) Json representation of this layer specification.

Type:

str

left_vertices()

Get the left-side vertices of the path.

Returns:

Array of coordinates.

Return type:

ndarray

length(include_offset=True)

Length of the path.

Parameters:

include_offset (bool) – If True, the length is measured at the Path.center() vertices, otherwise at the Path.spine().

Returns:

Path length.

Return type:

float

mirror(axis_endpoint=(1, 0), axis_origin=(0, 0))

Mirror this structure.

Parameters:
  • axis_endpoint (Sequence[float] | complex) – Mirror axis endpoint.

  • axis_origin (Sequence[float] | complex) – Mirror axis origin.

Returns:

This object.

Return type:

Path

origin

Path origin.

Type:

ndarray

parametric(position, gradient=None, width=None, offset=None, relative=True, min_evals=0, max_evals=10000)

Add a parametric curve to this path.

Parameters:
  • position (tuple[str, str] | Expression) – String expressions with the path position parametrized by a scalar "u", that varies from 0 to 1 along the path. Alternatively, an Expression with 1 parameter and at least 4 expressions can be used. The last 4 expressions are used, respectively, as horizontal and vertical positions and horizontal and vertical positon derivatives.

  • gradient (tuple[str, str] | None) – String expressions of values analogous to position to evaluate the path gradient. This parameter is required if position is a string tuple, and forbidden if it is an Expression.

  • width (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path width over this section. It can be a number (linear interpolation from the current width over the whole section) or an interpolation specification (see the note in the class documentation).

  • offset (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path offset over this section. It can be a number (linear interpolation from the current offset over the whole section) or an interpolation specification (see the note in the class documentation).

  • relative (bool) – If set, the position returned by the function is relative to the current end point of the path.

  • min_evals (int) – Minimal number of evaluations when calculating the path boundaries and intersections.

  • max_evals (int) – Maximal number of evaluations when calculating the path boundaries and intersections.

Returns:

This path.

Return type:

Path

Example

>>> path = Path((0, 0), 0.25)
>>> path.parametric(("-5 * u", "5 * u^2"), (-5, "10 * u"))
>>> spiral = Expression(
...     "u",
...     [
...         ("r0", 2),
...         ("dr", 2),
...         ("r", "r0 + dr * u"),
...         ("k", "1.5 * 2 * pi"),
...         ("c", "cos(k * u)"),
...         ("s", "sin(k * u)"),
...         ("x", "r * c - r0"),
...         ("y", "r * s"),
...         ("dx", "dr * c - r * k * s"),
...         ("dy", "dr * s + r * k * c"),
...     ],
... )
>>> path.parametric(spiral)
perimeter()

Structure perimeter.

Returns:

Perimeter of the structure.

Return type:

float

properties

Object properties.

Type:

Properties

right_vertices()

Get the right-side vertices of the path.

Returns:

Array of coordinates.

Return type:

ndarray

rotate(rotation, center=(0, 0))

Rotate this structure.

Parameters:
  • rotation (float) – Rotation angle (in degrees).

  • center (Sequence[float, float] | complex) – Center of rotation.

Returns:

This object.

Return type:

Path

s_bend(endpoint, euler_fraction=None, direction=None, width=None, offset=None, relative=False, min_evals=0, max_evals=10000)

Add an S bend section to the path.

Parameters:
  • endpoint (Sequence[float] | complex) – S bend endpoint.

  • euler_fraction (float | None) – Fraction of the bend that is created using an Euler spiral (see Path.arc()). If None, look for deafult in config.default_kwargs (under a "Path" dictionary or root).

  • direction (Sequence[float] | complex | None) – Direction of the S bend. If None, use current path direction.

  • width (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path width over this section. It can be a number (linear interpolation from the current width over the whole section) or an interpolation specification (see the note in the class documentation).

  • offset (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path offset over this section. It can be a number (linear interpolation from the current offset over the whole section) or an interpolation specification (see the note in the class documentation).

  • relative (bool) – If set, the end point is calculated relative to the current end point of the path.

  • min_evals (int) – Minimal number of evaluations when calculating the path boundaries and intersections.

  • max_evals (int) – Maximal number of evaluations when calculating the path boundaries and intersections.

Returns:

This path.

Return type:

Path

Example

>>> path = Path((0, 0), 0.5)
>>> path.s_bend((-6, 1), direction=(-1, 0))
>>> path.s_bend((-12, -1))
scale(scaling, center=(0, 0))

Scale this structure.

Parameters:
  • scaling (float) – Magnification factor.

  • center (Sequence[float, float] | complex) – Center of scaling.

Returns:

This object.

Return type:

Path

scale_profile

Profile scaling flag.

Type:

bool

segment(endpoint, width=None, offset=None, join_limit=-1.0, relative=False, min_evals=0, max_evals=10000)

Add a straight segment to this path.

Parameters:
  • endpoint (Sequence[float] | complex | Sequence[Sequence[float] | complex]) – End point or list of end points.

  • width (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path width over this section. It can be a number (linear interpolation from the current width over the whole section) or an interpolation specification (see the note in the class documentation).

  • offset (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path offset over this section. It can be a number (linear interpolation from the current offset over the whole section) or an interpolation specification (see the note in the class documentation).

  • join_limit (float | Literal["round"]) – If the join between segments would create an intersection point beyond this limit (as a fraction of the local width), the join is beveled. A negative value disables beveling. This value can also be set to “round” to create rounded joins.

  • relative (bool) – If set, the end point is calculated relative to the current end point of the path.

  • min_evals (int) – Minimal number of evaluations when calculating the path boundaries and intersections.

  • max_evals (int) – Maximal number of evaluations when calculating the path boundaries and intersections.

Returns:

This path.

Return type:

Path

size

Number of path sections (read only).

Type:

int

spine()

Get the central vertices of the path, not taking offsets into account.

Returns:

Array of coordinates.

Return type:

ndarray

to_polygon()

Create a Polygon from this structure.

Returns:

New polygon instance.

Return type:

Polygon

Examples

>>> rectangle = Rectangle((0, 0), (2, 1), rotation=45)
>>> polygon = rectangle.to_polygon()
>>> circle = Circle(5, (0, 0), inner_radius=3)
>>> polygon = circle.to_polygon()
>>> path = Path((0, 0), 0.5).s_bend((10, 2))
>>> polygon = path.to_polygon()
transform(translation=(0, 0), rotation=0, scaling=1, x_reflection=False)

Apply a transformation to this structure: self = translate(rotate(mirror(scale(self))))

Parameters:
  • translation (Sequence[float, float] | complex) – Translation vector.

  • rotation (float) – Rotation angle (in degrees).

  • scaling (float) – Magnification factor.

  • x_reflection (bool) – Mirror across the horizontal axis.

Returns:

This object.

Return type:

Path

translate(translation)

Translate this structure.

Parameters:

translation (Sequence[float, float] | complex) – Translation vector.

Returns:

This object.

Return type:

Path

turn(angle, radius=None, euler_fraction=None, endpoint=None, width=None, offset=None, min_evals=0, max_evals=10000)

Add a circular or Euler turn to this path.

Parameters:
  • angle (float) – Turning angle (in degrees). Positive (negative) values make a counter-clockwise (clockwise) turn.

  • radius (float | None) – Arc radius. If None, look for deafult in config.default_kwargs.

  • euler_fraction (float | None) – Fraction of the bend that is created using an Euler spiral (see Path.arc()). If None, look for deafult in config.default_kwargs.

  • endpoint (Sequence[float] | complex | None) – If set, force the arc to end exactly at these coordinates, compensating any numerical inaccuracies from the arc computation.

  • width (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path width over this section. It can be a number (linear interpolation from the current width over the whole section) or an interpolation specification (see the note in the class documentation).

  • offset (float | tuple[float, Literal["constant", "linear", "smooth"]] | tuple[float, float, Literal["constant", "linear", "smooth"]] | tuple[str, str] | Expression) – Path offset over this section. It can be a number (linear interpolation from the current offset over the whole section) or an interpolation specification (see the note in the class documentation).

  • min_evals (int) – Minimal number of evaluations when calculating the path boundaries and intersections.

  • max_evals (int) – Maximal number of evaluations when calculating the path boundaries and intersections.

Returns:

This path.

Return type:

Path

Note

The defaults are read from a dictionary under the key "Path" in config.default_kwargs, or directly at the root.

updated_copy(width, offset=0, constant_width=False, constant_offset=False, relative=False)

Create a copy of this path with a new width and offset.

Parameters:
  • width (float) – New path width.

  • offset (float) – New path offset.

  • constant_width (bool) – If True, the new path will have constant width Otherwise, the original width variations are used.

  • constant_offset (bool) – If True, the new path will have constant offset Otherwise, the original offset variations are used.

  • relative (bool) – If True, arguments width and offset are added to the current values.

Returns:

New path.

Return type:

Path

x_max

Upper bound in the x axis.

Type:

float

x_mid

Bounding box center in the x axis.

Type:

float

x_min

Lower bound in the x axis.

Type:

float

y_max

Upper bound in the y axis.

Type:

float

y_mid

Bounding box center in the y axis.

Type:

float

y_min

Lower bound in the y axis.

Type:

float