API Reference

A collection of classes for 2D/3D geometric modelling.

class opensolid.Tolerance

Manages a thread-local tolerance value.

Many functions in OpenSolid require a tolerance to be set. You should generally choose a value that is much smaller than any meaningful size/dimension in the geometry you’re modelling, but significantly larger than any expected numerical roundoff that might occur. A good default choice is roughly one-billionth of the overall size of your geometry; for ‘human-scale’ things (say, from an earring up to a house) that means that one nanometer is a reasonable value to use.

Passing a tolerance into every function that needed one would get very verbose, and it’s very common to choose a single tolerance value and use it throughout a project. However, it’s also occasionally necessary to set a different tolerance for some code. This class allows managing tolerances using Python’s with statement, e.g.:

with Tolerance(Length.nanometer):
    do_something()
    do_something_else()
    with Tolerance(Angle.degrees(0.001)):
        compare_two_angles()
    do_more_things()

In the above code, the Length.nanometer tolerance value will be used for do_something() and do_something_else() (and any functions they call). The Angle.degrees(0.001)) tolerance value will then be used for compare_two_angles(), and then the Length.nanometer tolerance value will be restored and used for do_more_things().

static current() float | Length | Area | Angle | None

Get the current tolerance value.

class opensolid.Length

A length in millimeters, meters, inches etc.

Represented internally as a value in meters.

zero: Length = Length.meters(0.0)

The zero value.

meter: Length = Length.meters(1.0)

One meter.

centimeter: Length = Length.meters(0.01)

One centimeter.

millimeter: Length = Length.meters(0.001)

One millimeter.

micrometer: Length = Length.meters(1e-06)

One micrometer.

nanometer: Length = Length.meters(1e-09)

One nanometer.

inch: Length = Length.meters(0.0254)

One inch.

pixel: Length = Length.meters(0.0002645833333333333)

One CSS pixel, equal to 1/96 of an inch.

static meters(value: float) Length

Construct a length from a number of meters.

static centimeters(value: float) Length

Construct a length from a number of centimeters.

static millimeters(value: float) Length

Construct a length value from a number of millimeters.

static micrometers(value: float) Length

Construct a length from a number of micrometers.

static nanometers(value: float) Length

Construct a length from a number of nanometers.

static inches(value: float) Length

Construct a length from a number of inches.

static pixels(value: float) Length

Construct a length from a number of CSS pixels.

in_meters() float

Convert a length to a number of meters.

in_centimeters() float

Convert a length to a number of centimeters.

in_millimeters() float

Convert a length to a number of millimeters.

in_micrometers() float

Convert a length to a number of micrometers.

in_nanometers() float

Convert a length to a number of nanometers.

in_inches() float

Convert a length to a number of inches.

in_pixels() float

Convert a length into a number of CSS pixels.

is_zero() bool

Check if a length is zero, within the current tolerance.

__eq__(other: object) bool

Return self == other.

Note that this is an exact comparison; for a tolerant comparison (one which will return true if two values are almost equal) you’ll likely want to use an is_zero() method instead.

__lt__(other: Length) bool

Return self < other.

__le__(other: Length) bool

Return self <= other.

__ge__(other: Length) bool

Return self >= other.

__gt__(other: Length) bool

Return self > other.

__add__(rhs: Length) Length
__add__(rhs: LengthRange) LengthRange
__add__(rhs: LengthCurve) LengthCurve

Return self + rhs.

__sub__(rhs: Length) Length
__sub__(rhs: LengthRange) LengthRange
__sub__(rhs: LengthCurve) LengthCurve

Return self - rhs.

__mul__(rhs: float) Length
__mul__(rhs: Length) Area
__mul__(rhs: Range) LengthRange
__mul__(rhs: LengthRange) AreaRange
__mul__(rhs: Curve) LengthCurve
__mul__(rhs: LengthCurve) AreaCurve
__mul__(rhs: Direction2d) Displacement2d
__mul__(rhs: Vector2d) Displacement2d
__mul__(rhs: Displacement2d) AreaVector2d

Return self * rhs.

__truediv__(rhs: float) Length
__truediv__(rhs: Length) float
__truediv__(rhs: Range) LengthRange
__truediv__(rhs: LengthRange) Range
__truediv__(rhs: Curve) LengthCurve
__truediv__(rhs: LengthCurve) Curve

Return self / rhs.

__floordiv__(rhs: Length) int

Return self // rhs.

__mod__(rhs: Length) Length

Return self % rhs.

__rmul__(lhs: float) Length

Return lhs * self.

class opensolid.Area

An area in square meters, square inches etc.

Represented internally as a value in square meters.

zero: Area = Area.square_meters(0.0)

The zero value.

square_meter: Area = Area.square_meters(1.0)

One square meter.

square_inch: Area = Area.square_meters(0.00064516)

One square inch.

static square_meters(value: float) Area

Construct an area from a number of square meters.

static square_inches(value: float) Area

Construct an area from a number of square inches.

in_square_meters() float

Convert an area to a number of square meters.

in_square_inches() float

Convert an area to a number of square inches.

is_zero() bool

Check if an area is zero, within the current tolerance.

__eq__(other: object) bool

Return self == other.

Note that this is an exact comparison; for a tolerant comparison (one which will return true if two values are almost equal) you’ll likely want to use an is_zero() method instead.

__lt__(other: Area) bool

Return self < other.

__le__(other: Area) bool

Return self <= other.

__ge__(other: Area) bool

Return self >= other.

__gt__(other: Area) bool

Return self > other.

__add__(rhs: Area) Area
__add__(rhs: AreaRange) AreaRange
__add__(rhs: AreaCurve) AreaCurve

Return self + rhs.

__sub__(rhs: Area) Area
__sub__(rhs: AreaRange) AreaRange
__sub__(rhs: AreaCurve) AreaCurve

Return self - rhs.

__mul__(rhs: float) Area
__mul__(rhs: Range) AreaRange
__mul__(rhs: Curve) AreaCurve
__mul__(rhs: Direction2d) AreaVector2d
__mul__(rhs: Vector2d) AreaVector2d

Return self * rhs.

__truediv__(rhs: float) Area
__truediv__(rhs: Area) float
__truediv__(rhs: Length) Length
__truediv__(rhs: Range) AreaRange
__truediv__(rhs: LengthRange) LengthRange
__truediv__(rhs: AreaRange) Range
__truediv__(rhs: Curve) AreaCurve
__truediv__(rhs: LengthCurve) LengthCurve
__truediv__(rhs: AreaCurve) Curve

Return self / rhs.

__floordiv__(rhs: Area) int

Return self // rhs.

__mod__(rhs: Area) Area

Return self % rhs.

__rmul__(lhs: float) Area

Return lhs * self.

class opensolid.Angle

An angle in degrees, radians, turns etc.

Represented internally as a value in radians.

zero: Angle = Angle.degrees(0.0)

The zero value.

golden_angle: Angle = Angle.degrees(137.50776405003785)

The [golden angle](https://en.wikipedia.org/wiki/Golden_angle).

radian: Angle = Angle.degrees(57.29577951308232)

One radian.

degree: Angle = Angle.degrees(1.0)

One degree.

full_turn: Angle = Angle.degrees(360.0)

One full turn, or 360 degrees.

half_turn: Angle = Angle.degrees(180.0)

One half turn, or 180 degrees.

quarter_turn: Angle = Angle.degrees(90.0)

One quarter turn, or 90 degrees.

pi: Angle = Angle.degrees(180.0)

π radians, or 180 degrees.

two_pi: Angle = Angle.degrees(360.0)

2π radians, or 360 degrees.

static radians(value: float) Angle

Construct an angle from a number of radians.

static degrees(value: float) Angle

Construct an angle from a number of degrees.

static turns(value: float) Angle

Construct an angle from a number of turns.

One turn is equal to 360 degrees.

static acos(value: float) Angle

Compute the inverse cosine of a value.

static asin(value: float) Angle

Compute the inverse sine of a value.

static atan(value: float) Angle

Compute the inverse tangent of a value.

in_radians() float

Convert an angle to a number of radians.

in_degrees() float

Convert an angle to a number of degrees.

in_turns() float

Convert an angle to a number of turns.

One turn is equal to 360 degrees.

is_zero() bool

Check if an angle is zero, within the current tolerance.

sin() float

Compute the sine of an angle.

cos() float

Compute the cosine of an angle.

tan() float

Compute the tangent of an angle.

__eq__(other: object) bool

Return self == other.

Note that this is an exact comparison; for a tolerant comparison (one which will return true if two values are almost equal) you’ll likely want to use an is_zero() method instead.

__lt__(other: Angle) bool

Return self < other.

__le__(other: Angle) bool

Return self <= other.

__ge__(other: Angle) bool

Return self >= other.

__gt__(other: Angle) bool

Return self > other.

__add__(rhs: Angle) Angle
__add__(rhs: AngleRange) AngleRange
__add__(rhs: AngleCurve) AngleCurve

Return self + rhs.

__sub__(rhs: Angle) Angle
__sub__(rhs: AngleRange) AngleRange
__sub__(rhs: AngleCurve) AngleCurve

Return self - rhs.

__mul__(rhs: float) Angle
__mul__(rhs: Range) AngleRange
__mul__(rhs: Curve) AngleCurve

Return self * rhs.

__truediv__(rhs: float) Angle
__truediv__(rhs: Angle) float
__truediv__(rhs: Range) AngleRange
__truediv__(rhs: AngleRange) Range
__truediv__(rhs: Curve) AngleCurve
__truediv__(rhs: AngleCurve) Curve

Return self / rhs.

__floordiv__(rhs: Angle) int

Return self // rhs.

__mod__(rhs: Angle) Angle

Return self % rhs.

__rmul__(lhs: float) Angle

Return lhs * self.

class opensolid.Range

A range of unitless values, with a lower bound and upper bound.

unit: Range = Range.from_endpoints(0.0,1.0)

The range with endoints [0,1].

static constant(value: float) Range

Construct a zero-width range containing a single value.

static from_endpoints(a: float, b: float) Range

Construct a range from its lower and upper bounds.

The order of the two arguments does not matter; the minimum of the two will be used as the lower bound of the range and the maximum will be used as the upper bound.

static hull(values: list[float]) Range

Build a range containing all values in the given non-empty list.

static aggregate(ranges: list[Range]) Range

Build a range containing all ranges in the given non-empty list.

endpoints() tuple[float, float]

Get the lower and upper bounds of a range.

lower_bound() float

Get the lower bound of a range.

upper_bound() float

Get the upper bound of a range.

intersection(other: Range) Range | None

Attempt to find the intersection of two ranges.

includes(value: float) bool

Check if a given value is included in a range.

Note that this does not use a tolerance, so use with care - for example, a value just outside the range (due to numerical roundoff) will be reported as not included.

contains(other: Range) bool

Check if one range contains another.

Note that this does not use a tolerance, so use with care - for example, a range that extends just outside another range (due to numerical roundoff) will be reported as not contained by that range.

__add__(rhs: float) Range
__add__(rhs: Range) Range

Return self + rhs.

__sub__(rhs: float) Range
__sub__(rhs: Range) Range

Return self - rhs.

__mul__(rhs: float) Range
__mul__(rhs: Range) Range
__mul__(rhs: Length) LengthRange
__mul__(rhs: Angle) AngleRange
__mul__(rhs: LengthRange) LengthRange
__mul__(rhs: AreaRange) AreaRange

Return self * rhs.

__truediv__(rhs: float) Range
__truediv__(rhs: Range) Range

Return self / rhs.

__radd__(lhs: float) Range

Return lhs + self.

__rsub__(lhs: float) Range

Return lhs - self.

__rmul__(lhs: float) Range

Return lhs * self.

__rtruediv__(lhs: float) Range

Return lhs / self.

class opensolid.LengthRange

A range of length values, with a lower bound and upper bound.

static constant(value: Length) LengthRange

Construct a zero-width range containing a single value.

static from_endpoints(a: Length, b: Length) LengthRange

Construct a range from its lower and upper bounds.

The order of the two arguments does not matter; the minimum of the two will be used as the lower bound of the range and the maximum will be used as the upper bound.

static meters(a: float, b: float) LengthRange

Construct a length range from lower and upper bounds given in meters.

static centimeters(a: float, b: float) LengthRange

Construct a length range from lower and upper bounds given in centimeters.

static millimeters(a: float, b: float) LengthRange

Construct a length range from lower and upper bounds given in millimeters.

static inches(a: float, b: float) LengthRange

Construct a length range from lower and upper bounds given in inches.

static hull(values: list[Length]) LengthRange

Build a range containing all values in the given non-empty list.

static aggregate(ranges: list[LengthRange]) LengthRange

Build a range containing all ranges in the given non-empty list.

endpoints() tuple[Length, Length]

Get the lower and upper bounds of a range.

intersection(other: LengthRange) LengthRange | None

Attempt to find the intersection of two ranges.

includes(value: Length) bool

Check if a given value is included in a range.

Note that this does not use a tolerance, so use with care - for example, a value just outside the range (due to numerical roundoff) will be reported as not included.

contains(other: LengthRange) bool

Check if one range contains another.

Note that this does not use a tolerance, so use with care - for example, a range that extends just outside another range (due to numerical roundoff) will be reported as not contained by that range.

__add__(rhs: LengthRange) LengthRange
__add__(rhs: Length) LengthRange

Return self + rhs.

__sub__(rhs: LengthRange) LengthRange
__sub__(rhs: Length) LengthRange

Return self - rhs.

__mul__(rhs: float) LengthRange
__mul__(rhs: LengthRange) AreaRange
__mul__(rhs: Length) AreaRange
__mul__(rhs: Range) LengthRange

Return self * rhs.

__truediv__(rhs: float) LengthRange
__truediv__(rhs: LengthRange) Range
__truediv__(rhs: Length) Range
__truediv__(rhs: Range) LengthRange

Return self / rhs.

__rmul__(lhs: float) LengthRange

Return lhs * self.

class opensolid.AreaRange

A range of area values, with a lower bound and upper bound.

static constant(value: Area) AreaRange

Construct a zero-width range containing a single value.

static square_meters(a: float, b: float) AreaRange

Construct an area range from lower and upper bounds given in square meters.

static from_endpoints(a: Area, b: Area) AreaRange

Construct a range from its lower and upper bounds.

The order of the two arguments does not matter; the minimum of the two will be used as the lower bound of the range and the maximum will be used as the upper bound.

static hull(values: list[Area]) AreaRange

Build a range containing all values in the given non-empty list.

static aggregate(ranges: list[AreaRange]) AreaRange

Build a range containing all ranges in the given non-empty list.

endpoints() tuple[Area, Area]

Get the lower and upper bounds of a range.

intersection(other: AreaRange) AreaRange | None

Attempt to find the intersection of two ranges.

includes(value: Area) bool

Check if a given value is included in a range.

Note that this does not use a tolerance, so use with care - for example, a value just outside the range (due to numerical roundoff) will be reported as not included.

contains(other: AreaRange) bool

Check if one range contains another.

Note that this does not use a tolerance, so use with care - for example, a range that extends just outside another range (due to numerical roundoff) will be reported as not contained by that range.

__add__(rhs: AreaRange) AreaRange
__add__(rhs: Area) AreaRange

Return self + rhs.

__sub__(rhs: AreaRange) AreaRange
__sub__(rhs: Area) AreaRange

Return self - rhs.

__mul__(rhs: float) AreaRange
__mul__(rhs: Range) AreaRange

Return self * rhs.

__truediv__(rhs: float) AreaRange
__truediv__(rhs: AreaRange) Range
__truediv__(rhs: Length) LengthRange
__truediv__(rhs: Area) Range
__truediv__(rhs: Range) AreaRange
__truediv__(rhs: LengthRange) LengthRange

Return self / rhs.

__rmul__(lhs: float) AreaRange

Return lhs * self.

class opensolid.AngleRange

A range of angle values, with a lower bound and upper bound.

static constant(value: Angle) AngleRange

Construct a zero-width range containing a single value.

static from_endpoints(a: Angle, b: Angle) AngleRange

Construct a range from its lower and upper bounds.

The order of the two arguments does not matter; the minimum of the two will be used as the lower bound of the range and the maximum will be used as the upper bound.

static radians(a: float, b: float) AngleRange

Construct an angle range from lower and upper bounds given in radians.

static degrees(a: float, b: float) AngleRange

Construct an angle range from lower and upper bounds given in degrees.

static turns(a: float, b: float) AngleRange

Construct an angle range from lower and upper bounds given in turns.

static hull(values: list[Angle]) AngleRange

Build a range containing all values in the given non-empty list.

static aggregate(ranges: list[AngleRange]) AngleRange

Build a range containing all ranges in the given non-empty list.

endpoints() tuple[Angle, Angle]

Get the lower and upper bounds of a range.

intersection(other: AngleRange) AngleRange | None

Attempt to find the intersection of two ranges.

includes(value: Angle) bool

Check if a given value is included in a range.

Note that this does not use a tolerance, so use with care - for example, a value just outside the range (due to numerical roundoff) will be reported as not included.

contains(other: AngleRange) bool

Check if one range contains another.

Note that this does not use a tolerance, so use with care - for example, a range that extends just outside another range (due to numerical roundoff) will be reported as not contained by that range.

__add__(rhs: AngleRange) AngleRange
__add__(rhs: Angle) AngleRange

Return self + rhs.

__sub__(rhs: AngleRange) AngleRange
__sub__(rhs: Angle) AngleRange

Return self - rhs.

__mul__(rhs: float) AngleRange

Return self * rhs.

__truediv__(rhs: float) AngleRange
__truediv__(rhs: AngleRange) Range
__truediv__(rhs: Range) AngleRange

Return self / rhs.

__rmul__(lhs: float) AngleRange

Return lhs * self.

class opensolid.Color

An RGB color value.

red: Color = Color.rgb_255(204,0,0)

Scarlet Red from the Tango icon theme.

dark_red: Color = Color.rgb_255(164,0,0)

Dark Scarlet Red from the Tango icon theme.

light_orange: Color = Color.rgb_255(252,175,62)

Light Orange from the Tango icon theme.

orange: Color = Color.rgb_255(245,121,0)

Orange from the Tango icon theme.

dark_orange: Color = Color.rgb_255(206,92,0)

Dark Orange from the Tango icon theme.

light_yellow: Color = Color.rgb_255(255,233,79)

Light Butter from the Tango icon theme.

yellow: Color = Color.rgb_255(237,212,0)

Butter from the Tango icon theme.

dark_yellow: Color = Color.rgb_255(196,160,0)

Dark Butter from the Tango icon theme.

light_green: Color = Color.rgb_255(138,226,52)

Light Chameleon from the Tango icon theme.

green: Color = Color.rgb_255(115,210,22)

Chameleon from the Tango icon theme.

dark_green: Color = Color.rgb_255(78,154,6)

Dark Chameleon from the Tango icon theme.

light_blue: Color = Color.rgb_255(114,159,207)

Light Sky Blue from the Tango icon theme.

blue: Color = Color.rgb_255(52,101,164)

Sky Blue from the Tango icon theme.

dark_blue: Color = Color.rgb_255(32,74,135)

Dark Sky Blue from the Tango icon theme.

light_purple: Color = Color.rgb_255(173,127,168)

Light Plum from the Tango icon theme.

purple: Color = Color.rgb_255(117,80,123)

Plum from the Tango icon theme.

dark_purple: Color = Color.rgb_255(92,53,102)

Dark Plum from the Tango icon theme.

light_brown: Color = Color.rgb_255(233,185,110)

Light Chocolate from the Tango icon theme.

brown: Color = Color.rgb_255(193,125,17)

Chocolate from the Tango icon theme.

dark_brown: Color = Color.rgb_255(143,89,2)

Dark Chocolate from the Tango icon theme.

black: Color = Color.rgb_255(0,0,0)

Black.

white: Color = Color.rgb_255(255,255,255)

White.

light_grey: Color = Color.rgb_255(238,238,236)

Aluminium 1/6 from the Tango icon theme.

grey: Color = Color.rgb_255(211,215,207)

Aluminium 2/6 from the Tango icon theme.

dark_grey: Color = Color.rgb_255(186,189,182)

Aluminium 3/6 from the Tango icon theme.

light_gray: Color = Color.rgb_255(238,238,236)

Aluminium 1/6 from the Tango icon theme.

gray: Color = Color.rgb_255(211,215,207)

Aluminium 2/6 from the Tango icon theme.

dark_gray: Color = Color.rgb_255(186,189,182)

Aluminium 3/6 from the Tango icon theme.

light_charcoal: Color = Color.rgb_255(136,138,133)

Aluminium 4/6 from the Tango icon theme.

charcoal: Color = Color.rgb_255(85,87,83)

Aluminium 5/6 from the Tango icon theme.

dark_charcoal: Color = Color.rgb_255(46,52,54)

Aluminium 6/6 from the Tango icon theme.

static rgb(red: float, green: float, blue: float) Color

Construct a color from its RGB components, in the range [0,1].

static rgb_255(red: int, green: int, blue: int) Color

Construct a color from its RGB components, in the range [0,255].

static hsl(hue: Angle, saturation: float, lightness: float) Color

Construct a color from its hue, saturation and lightness values.

static from_hex(hex_string: str) Color

Construct a color from a hex string such as ‘#f3f3f3’ or ‘f3f3f3’.

to_hex() str

Convert a color to a hex string such as ‘#f3f3f3’.

components() tuple[float, float, float]

Get the RGB components of a color as values in the range [0,1].

components_255() tuple[int, int, int]

Get the RGB components of a color as values in the range [0,255].

class opensolid.Vector2d

A unitless vector in 2D.

zero: Vector2d = Vector2d.xy(0.0,0.0)

The zero vector.

static unit(direction: Direction2d) Vector2d

Construct a unit vector in the given direction.

static xy(x_component: float, y_component: float) Vector2d

Construct a vector from its X and Y components.

static y(y_component: float) Vector2d

Construct a vector from just a Y component.

The X component will be set to zero.

static x(x_component: float) Vector2d

Construct a vector from just an X component.

The Y component will be set to zero.

static polar(magnitude: float, angle: Angle) Vector2d

Construct a vector from its magnitude (length) and angle.

static from_components(components: tuple[float, float]) Vector2d

Construct a vector from a pair of X and Y components.

components() tuple[float, float]

Get the X and Y components of a vector.

x_component() float

Get the X component of a vector.

y_component() float

Get the Y component of a vector.

direction() Direction2d

Attempt to get the direction of a vector.

The current tolerance will be used to check if the vector is zero (and therefore does not have a direction).

angle() Angle

Get the angle of a vector.

The angle is measured counterclockwise from the positive X axis, so:

  • A vector in the positive X direction has an angle of zero.

  • A vector in the positive Y direction has an angle of 90 degrees.

  • A vector in the negative Y direction has an angle of -90 degrees.

  • It is not defined whether a vector exactly in the negative X direction has an angle of -180 or +180 degrees. (Currently it is reported as having an angle of +180 degrees, but this should not be relied upon.)

The returned angle will be between -180 and +180 degrees.

is_zero() bool

Check if a vector is zero, within the current tolerance.

__add__(rhs: Vector2d) Vector2d

Return self + rhs.

__sub__(rhs: Vector2d) Vector2d

Return self - rhs.

__mul__(rhs: float) Vector2d
__mul__(rhs: Length) Displacement2d
__mul__(rhs: Area) AreaVector2d

Return self * rhs.

__truediv__(rhs: float) Vector2d

Return self / rhs.

dot(rhs: Vector2d) float
dot(rhs: Displacement2d) Length
dot(rhs: AreaVector2d) Area
dot(rhs: Direction2d) float

Compute the dot product of two vector-like values.

cross(rhs: Vector2d) float
cross(rhs: Displacement2d) Length
cross(rhs: AreaVector2d) Area
cross(rhs: Direction2d) float

Compute the cross product of two vector-like values.

__rmul__(lhs: float) Vector2d

Return lhs * self.

class opensolid.Displacement2d

A displacement vector in 2D.

zero: Displacement2d = Displacement2d.meters(0.0,0.0)

The zero vector.

static xy(x_component: Length, y_component: Length) Displacement2d

Construct a vector from its X and Y components.

static x(x_component: Length) Displacement2d

Construct a vector from just an X component.

The Y component will be set to zero.

static y(y_component: Length) Displacement2d

Construct a vector from just a Y component.

The X component will be set to zero.

static polar(magnitude: Length, angle: Angle) Displacement2d

Construct a vector from its magnitude (length) and angle.

static meters(x_component: float, y_component: float) Displacement2d

Construct a vector from its X and Y components given in meters.

static centimeters(x_component: float, y_component: float) Displacement2d

Construct a vector from its X and Y components given in centimeters.

static millimeters(x_component: float, y_component: float) Displacement2d

Construct a vector from its X and Y components given in millimeters.

static inches(x_component: float, y_component: float) Displacement2d

Construct a vector from its X and Y components given in inches.

static from_components(components: tuple[Length, Length]) Displacement2d

Construct a vector from a pair of X and Y components.

components() tuple[Length, Length]

Get the X and Y components of a vector.

x_component() Length

Get the X component of a vector.

y_component() Length

Get the Y component of a vector.

direction() Direction2d

Attempt to get the direction of a vector.

The current tolerance will be used to check if the vector is zero (and therefore does not have a direction).

angle() Angle

Get the angle of a vector.

The angle is measured counterclockwise from the positive X axis, so:

  • A vector in the positive X direction has an angle of zero.

  • A vector in the positive Y direction has an angle of 90 degrees.

  • A vector in the negative Y direction has an angle of -90 degrees.

  • It is not defined whether a vector exactly in the negative X direction has an angle of -180 or +180 degrees. (Currently it is reported as having an angle of +180 degrees, but this should not be relied upon.)

The returned angle will be between -180 and +180 degrees.

is_zero() bool

Check if a displacement is zero, within the current tolerance.

__add__(rhs: Displacement2d) Displacement2d

Return self + rhs.

__sub__(rhs: Displacement2d) Displacement2d

Return self - rhs.

__mul__(rhs: float) Displacement2d
__mul__(rhs: Length) AreaVector2d

Return self * rhs.

__truediv__(rhs: float) Displacement2d
__truediv__(rhs: Length) Vector2d

Return self / rhs.

dot(rhs: Displacement2d) Area
dot(rhs: Vector2d) Length
dot(rhs: Direction2d) Length

Compute the dot product of two vector-like values.

cross(rhs: Displacement2d) Area
cross(rhs: Vector2d) Length
cross(rhs: Direction2d) Length

Compute the cross product of two vector-like values.

__rmul__(lhs: float) Displacement2d

Return lhs * self.

class opensolid.AreaVector2d

A vector in 2D with units of area.

zero: AreaVector2d = AreaVector2d.square_meters(0.0,0.0)

The zero vector.

static xy(x_component: Area, y_component: Area) AreaVector2d

Construct a vector from its X and Y components.

static x(x_component: Area) AreaVector2d

Construct a vector from just an X component.

The Y component will be set to zero.

static y(y_component: Area) AreaVector2d

Construct a vector from just a Y component.

The X component will be set to zero.

static polar(magnitude: Area, angle: Angle) AreaVector2d

Construct a vector from its magnitude (length) and angle.

static square_meters(x_component: float, y_component: float) AreaVector2d

Construct a vector from its X and Y components given in square meters.

static from_components(components: tuple[Area, Area]) AreaVector2d

Construct a vector from a pair of X and Y components.

components() tuple[Area, Area]

Get the X and Y components of a vector.

x_component() Area

Get the X component of a vector.

y_component() Area

Get the Y component of a vector.

direction() Direction2d

Attempt to get the direction of a vector.

The current tolerance will be used to check if the vector is zero (and therefore does not have a direction).

angle() Angle

Get the angle of a vector.

The angle is measured counterclockwise from the positive X axis, so:

  • A vector in the positive X direction has an angle of zero.

  • A vector in the positive Y direction has an angle of 90 degrees.

  • A vector in the negative Y direction has an angle of -90 degrees.

  • It is not defined whether a vector exactly in the negative X direction has an angle of -180 or +180 degrees. (Currently it is reported as having an angle of +180 degrees, but this should not be relied upon.)

The returned angle will be between -180 and +180 degrees.

is_zero() bool

Check if an area vector is zero, within the current tolerance.

__add__(rhs: AreaVector2d) AreaVector2d

Return self + rhs.

__sub__(rhs: AreaVector2d) AreaVector2d

Return self - rhs.

__mul__(rhs: float) AreaVector2d

Return self * rhs.

__truediv__(rhs: float) AreaVector2d
__truediv__(rhs: Length) Displacement2d
__truediv__(rhs: Area) Vector2d

Return self / rhs.

dot(rhs: Vector2d) Area
dot(rhs: Direction2d) Area

Compute the dot product of two vector-like values.

cross(rhs: Vector2d) Area
cross(rhs: Direction2d) Area

Compute the cross product of two vector-like values.

__rmul__(lhs: float) AreaVector2d

Return lhs * self.

class opensolid.Direction2d

A direction in 2D.

This is effectively a type-safe unit vector.

x: Direction2d = Direction2d.degrees(0.0)

Alias for ‘positiveX’.

y: Direction2d = Direction2d.degrees(90.0)

Alias for ‘positiveY’.

positive_x: Direction2d = Direction2d.degrees(0.0)

The positive X direction.

positive_y: Direction2d = Direction2d.degrees(90.0)

The positive Y direction.

negative_x: Direction2d = Direction2d.degrees(180.0)

The negative X direction.

negative_y: Direction2d = Direction2d.degrees(-90.0)

The negative Y direction.

static from_angle(angle: Angle) Direction2d

Construct a direction from an angle.

The angle is measured counterclockwise from the positive X direction, so:

  • An angle of zero corresponds to the positive X direction

  • An angle of 90 degrees corresponds to the positive Y direction

  • An angle of 180 degrees (or -180 degrees) corresponds to the negative X direction

static degrees(value: float) Direction2d

Construct a direction from an angle given in degrees.

See ‘fromAngle’ for details.

static radians(value: float) Direction2d

Construct a direction from an angle given in radians.

See ‘fromAngle’ for details.

to_angle() Angle

Convert a direction to an angle.

The angle is measured counterclockwise from the positive X direction, so:

  • The positive X direction has an angle of zero.

  • The positive Y direction has an angle of 90 degrees.

  • The negative Y direction has an angle of -90 degrees.

  • It is not defined whether the negative X direction has an angle of -180 or +180 degrees. (Currently it is reported as having an angle of +180 degrees, but this should not be relied upon.)

The returned angle will be between -180 and +180 degrees.

angle_to(other: Direction2d) Angle

Measure the signed angle from one direction to another.

The angle will be measured counterclockwise from the first direction to the second, and will always be between -180 and +180 degrees.

components() tuple[float, float]

Get the X and Y components of a direction.

x_component() float

Get the X component of a direction.

y_component() float

Get the Y component of a direction.

__mul__(rhs: float) Vector2d
__mul__(rhs: Length) Displacement2d
__mul__(rhs: Area) AreaVector2d

Return self * rhs.

dot(rhs: Direction2d) float
dot(rhs: Vector2d) float
dot(rhs: Displacement2d) Length
dot(rhs: AreaVector2d) Area

Compute the dot product of two vector-like values.

cross(rhs: Direction2d) float
cross(rhs: Vector2d) float
cross(rhs: Displacement2d) Length
cross(rhs: AreaVector2d) Area

Compute the cross product of two vector-like values.

__rmul__(lhs: float) Vector2d

Return lhs * self.

class opensolid.Point2d

A point in 2D, defined by its X and Y coordinates.

origin: Point2d = Point2d.meters(0.0,0.0)

The point with coordinates (0,0).

static xy(x_coordinate: Length, y_coordinate: Length) Point2d

Construct a point from its X and Y coordinates.

static x(x_coordinate: Length) Point2d

Construct a point along the X axis, with the given X coordinate.

static y(y_coordinate: Length) Point2d

Construct a point along the Y axis, with the given Y coordinate.

static meters(x_coordinate: float, y_coordinate: float) Point2d

Construct a point from its X and Y coordinates given in meters.

static centimeters(x_coordinate: float, y_coordinate: float) Point2d

Construct a point from its X and Y coordinates given in centimeters.

static millimeters(x_coordinate: float, y_coordinate: float) Point2d

Construct a point from its X and Y coordinates given in millimeters.

static inches(x_coordinate: float, y_coordinate: float) Point2d

Construct a point from its X and Y coordinates given in inches.

static from_coordinates(coordinates: tuple[Length, Length]) Point2d

Construct a point from a pair of X and Y coordinates.

coordinates() tuple[Length, Length]

Get the X and Y coordinates of a point.

x_coordinate() Length

Get the X coordinate of a point.

y_coordinate() Length

Get the Y coordinate of a point.

distance_to(other: Point2d) Length

Compute the distance from one point to another.

midpoint(other: Point2d) Point2d

Find the midpoint between two points.

__sub__(rhs: Point2d) Displacement2d
__sub__(rhs: Displacement2d) Point2d

Return self - rhs.

__add__(rhs: Displacement2d) Point2d

Return self + rhs.

class opensolid.UvPoint

A point in UV parameter space.

origin: UvPoint = UvPoint.uv(0.0,0.0)

The point with coordinates (0,0).

static uv(u_coordinate: float, v_coordinate: float) UvPoint

Construct a point from its X and Y coordinates.

static u(u_coordinate: float) UvPoint

Construct a point along the X axis, with the given X coordinate.

static v(v_coordinate: float) UvPoint

Construct a point along the Y axis, with the given Y coordinate.

static from_coordinates(coordinates: tuple[float, float]) UvPoint

Construct a point from a pair of X and Y coordinates.

coordinates() tuple[float, float]

Get the U and V coordinates of a point.

u_coordinate() float

Get the U coordinate of a point.

v_coordinate() float

Get the V coordinate of a point.

distance_to(other: UvPoint) float

Compute the distance from one point to another.

midpoint(other: UvPoint) UvPoint

Find the midpoint between two points.

__sub__(rhs: UvPoint) Vector2d
__sub__(rhs: Vector2d) UvPoint

Return self - rhs.

__add__(rhs: Vector2d) UvPoint

Return self + rhs.

class opensolid.Bounds2d

A bounding box in 2D.

static xy(x_coordinate: LengthRange, y_coordinate: LengthRange) Bounds2d

Construct a bounding box from its X and Y coordinate ranges.

static constant(point: Point2d) Bounds2d

Construct a zero-size bounding box containing a single point.

static from_corners(p1: Point2d, p2: Point2d) Bounds2d

Construct a bounding box from two corner points.

static hull(points: list[Point2d]) Bounds2d

Construct a bounding box containing all points in the given non-empty list.

static aggregate(bounds: list[Bounds2d]) Bounds2d

Construct a bounding box containing all bounding boxes in the given non-empty list.

coordinates() tuple[LengthRange, LengthRange]

Get the X and Y coordinate ranges of a bounding box.

x_coordinate() LengthRange

Get the X coordinate range of a bounding box.

y_coordinate() LengthRange

Get the Y coordinate range of a bounding box.

class opensolid.UvBounds

A bounding box in UV parameter space.

static uv(u_coordinate: Range, v_coordinate: Range) UvBounds

Construct a bounding box from its X and Y coordinate ranges.

static constant(point: UvPoint) UvBounds

Construct a zero-size bounding box containing a single point.

static from_corners(p1: UvPoint, p2: UvPoint) UvBounds

Construct a bounding box from two corner points.

static hull(points: list[UvPoint]) UvBounds

Construct a bounding box containing all points in the given non-empty list.

static aggregate(bounds: list[UvBounds]) UvBounds

Construct a bounding box containing all bounding boxes in the given non-empty list.

coordinates() tuple[Range, Range]

Get the X and Y coordinate ranges of a bounding box.

u_coordinate() Range

Get the X coordinate range of a bounding box.

v_coordinate() Range

Get the Y coordinate range of a bounding box.

class opensolid.Curve

A parametric curve definining a unitless value in terms of a parameter value.

zero: Curve = <opensolid.Curve object>

A curve equal to zero everywhere.

t: Curve = <opensolid.Curve object>

A curve parameter.

In other words, a curve whose value is equal to its input parameter. When defining parametric curves, you will typically start with ‘Curve.t’ and then use arithmetic operators etc. to build up more complex curves.

static constant(value: float) Curve

Create a curve with the given constant value.

squared() Curve

Compute the square of a curve.

sqrt() Curve

Compute the square root of a curve.

evaluate(parameter_value: float) float

Evaluate a curve at a given parameter value.

The parameter value should be between 0 and 1.

zeros() list[Zero]

Find all points at which the given curve is zero.

This includes not only points where the curve crosses zero, but also where it is tangent to zero. For example, y=x-3 crosses zero at x=3, while y=(x-3)^2 is tangent to zero at x=3.

We define y=x-3 as having a zero of order 0 at x=3, since only the “derivative of order zero” (the curve itself) is zero at that point. Similarly, y=(x-3)^2 has a zero of order 1 at x=3, since the first derivative (but not the second derivative) is zero at that point.

Currently, this function up to third-order zeros (e.g. y=x^4 has a third-order zero at x=0, since everything up to the third derivative is zero at x=0).

The current tolerance is used to determine whether a given point should be considered a zero, and of what order. For example, the curve y=x^2-0.0001 is exactly zero at x=0.01 and x=-0.01. However, note that the curve is also very close to zero at x=0, and at that point the first derivative is also zero. In many cases, it is reasonable to assume that the 0.0001 is an artifact of numerical roundoff, and the curve actually has a single zero of order 1 at x=0. The current tolerance is used to choose which case to report. In this example, a tolerance of 0.000001 would mean that we consider 0.0001 a meaningful value (not just roundoff), so we would end up reporting two order-0 zeros at x=0.01 and x=-0.01. On the other hand, a tolerance of 0.01 would mean that we consider 0.0001 as just roundoff error, so we would end up reporting a single order-1 zero at x=0 (the point at which the first derivative is zero).

is_zero() bool

Check if a curve is zero everywhere, within the current tolerance.

__add__(rhs: float) Curve
__add__(rhs: Curve) Curve

Return self + rhs.

__sub__(rhs: float) Curve
__sub__(rhs: Curve) Curve

Return self - rhs.

__mul__(rhs: float) Curve
__mul__(rhs: Curve) Curve
__mul__(rhs: Length) LengthCurve
__mul__(rhs: Area) AreaCurve
__mul__(rhs: Angle) AngleCurve
__mul__(rhs: LengthCurve) LengthCurve
__mul__(rhs: AngleCurve) AngleCurve

Return self * rhs.

__truediv__(rhs: float) Curve
__truediv__(rhs: Curve) Curve

Return self / rhs.

__radd__(lhs: float) Curve

Return lhs + self.

__rsub__(lhs: float) Curve

Return lhs - self.

__rmul__(lhs: float) Curve

Return lhs * self.

__rtruediv__(lhs: float) Curve

Return lhs / self.

class Zero

A point where a given curve is equal to zero.

location() float

Get the parameter value at which the curve is zero.

order() int

Check whether the zero is a crossing zero, a tangent zero etc.

  • An order 0 zero means the curve crosses zero at the given location, with a non-zero first derivative.

  • An order 1 zero means the first derivative is also zero at the given location, but the second derivative is not (that is, the curve just ‘touches’ zero at that point).

  • An order 2 zero means the first and second derivatives are zero at the given location, etc.

sign() int

Check whether the curve ‘curves up’ or ‘curves down’ at the zero.

A positive sign means that the curve is positive to the right of the zero (for a crossing zero, that means the curve will be negative to the left, but for an order 1 tangent zero, that means the curve will also be positive to the left!). Similarly, a negative sign means that the curve is negative to the right of the zero.

class opensolid.LengthCurve

A parametric curve definining a length in terms of a parameter value.

zero: LengthCurve = <opensolid.LengthCurve object>

A curve equal to zero everywhere.

static constant(value: Length) LengthCurve

Create a curve with the given constant value.

evaluate(parameter_value: float) Length

Evaluate a curve at a given parameter value.

The parameter value should be between 0 and 1.

zeros() list[Zero]

Find all points at which the given curve is zero.

This includes not only points where the curve crosses zero, but also where it is tangent to zero. For example, y=x-3 crosses zero at x=3, while y=(x-3)^2 is tangent to zero at x=3.

We define y=x-3 as having a zero of order 0 at x=3, since only the “derivative of order zero” (the curve itself) is zero at that point. Similarly, y=(x-3)^2 has a zero of order 1 at x=3, since the first derivative (but not the second derivative) is zero at that point.

Currently, this function up to third-order zeros (e.g. y=x^4 has a third-order zero at x=0, since everything up to the third derivative is zero at x=0).

The current tolerance is used to determine whether a given point should be considered a zero, and of what order. For example, the curve y=x^2-0.0001 is exactly zero at x=0.01 and x=-0.01. However, note that the curve is also very close to zero at x=0, and at that point the first derivative is also zero. In many cases, it is reasonable to assume that the 0.0001 is an artifact of numerical roundoff, and the curve actually has a single zero of order 1 at x=0. The current tolerance is used to choose which case to report. In this example, a tolerance of 0.000001 would mean that we consider 0.0001 a meaningful value (not just roundoff), so we would end up reporting two order-0 zeros at x=0.01 and x=-0.01. On the other hand, a tolerance of 0.01 would mean that we consider 0.0001 as just roundoff error, so we would end up reporting a single order-1 zero at x=0 (the point at which the first derivative is zero).

is_zero() bool

Check if a curve is zero everywhere, within the current tolerance.

__add__(rhs: LengthCurve) LengthCurve
__add__(rhs: Length) LengthCurve

Return self + rhs.

__sub__(rhs: LengthCurve) LengthCurve
__sub__(rhs: Length) LengthCurve

Return self - rhs.

__mul__(rhs: float) LengthCurve
__mul__(rhs: LengthCurve) AreaCurve
__mul__(rhs: Length) AreaCurve
__mul__(rhs: Curve) LengthCurve

Return self * rhs.

__truediv__(rhs: float) LengthCurve
__truediv__(rhs: LengthCurve) Curve
__truediv__(rhs: Length) Curve
__truediv__(rhs: Curve) LengthCurve

Return self / rhs.

__rmul__(lhs: float) LengthCurve

Return lhs * self.

class opensolid.AreaCurve

A parametric curve definining an area in terms of a parameter value.

zero: AreaCurve = <opensolid.AreaCurve object>

A curve equal to zero everywhere.

static constant(value: Area) AreaCurve

Create a curve with the given constant value.

evaluate(parameter_value: float) Area

Evaluate a curve at a given parameter value.

The parameter value should be between 0 and 1.

zeros() list[Zero]

Find all points at which the given curve is zero.

This includes not only points where the curve crosses zero, but also where it is tangent to zero. For example, y=x-3 crosses zero at x=3, while y=(x-3)^2 is tangent to zero at x=3.

We define y=x-3 as having a zero of order 0 at x=3, since only the “derivative of order zero” (the curve itself) is zero at that point. Similarly, y=(x-3)^2 has a zero of order 1 at x=3, since the first derivative (but not the second derivative) is zero at that point.

Currently, this function up to third-order zeros (e.g. y=x^4 has a third-order zero at x=0, since everything up to the third derivative is zero at x=0).

The current tolerance is used to determine whether a given point should be considered a zero, and of what order. For example, the curve y=x^2-0.0001 is exactly zero at x=0.01 and x=-0.01. However, note that the curve is also very close to zero at x=0, and at that point the first derivative is also zero. In many cases, it is reasonable to assume that the 0.0001 is an artifact of numerical roundoff, and the curve actually has a single zero of order 1 at x=0. The current tolerance is used to choose which case to report. In this example, a tolerance of 0.000001 would mean that we consider 0.0001 a meaningful value (not just roundoff), so we would end up reporting two order-0 zeros at x=0.01 and x=-0.01. On the other hand, a tolerance of 0.01 would mean that we consider 0.0001 as just roundoff error, so we would end up reporting a single order-1 zero at x=0 (the point at which the first derivative is zero).

is_zero() bool

Check if a curve is zero everywhere, within the current tolerance.

__add__(rhs: AreaCurve) AreaCurve

Return self + rhs.

__sub__(rhs: AreaCurve) AreaCurve

Return self - rhs.

__mul__(rhs: float) AreaCurve
__mul__(rhs: Curve) AreaCurve

Return self * rhs.

__truediv__(rhs: float) AreaCurve
__truediv__(rhs: AreaCurve) Curve
__truediv__(rhs: Length) LengthCurve
__truediv__(rhs: Area) Curve
__truediv__(rhs: Curve) AreaCurve
__truediv__(rhs: LengthCurve) LengthCurve

Return self / rhs.

__rmul__(lhs: float) AreaCurve

Return lhs * self.

class opensolid.AngleCurve

A parametric curve definining an angle in terms of a parameter value.

zero: AngleCurve = <opensolid.AngleCurve object>

A curve equal to zero everywhere.

static constant(value: Angle) AngleCurve

Create a curve with the given constant value.

sin() Curve

Compute the sine of a curve.

cos() Curve

Compute the cosine of a curve.

evaluate(parameter_value: float) Angle

Evaluate a curve at a given parameter value.

The parameter value should be between 0 and 1.

zeros() list[Zero]

Find all points at which the given curve is zero.

This includes not only points where the curve crosses zero, but also where it is tangent to zero. For example, y=x-3 crosses zero at x=3, while y=(x-3)^2 is tangent to zero at x=3.

We define y=x-3 as having a zero of order 0 at x=3, since only the “derivative of order zero” (the curve itself) is zero at that point. Similarly, y=(x-3)^2 has a zero of order 1 at x=3, since the first derivative (but not the second derivative) is zero at that point.

Currently, this function up to third-order zeros (e.g. y=x^4 has a third-order zero at x=0, since everything up to the third derivative is zero at x=0).

The current tolerance is used to determine whether a given point should be considered a zero, and of what order. For example, the curve y=x^2-0.0001 is exactly zero at x=0.01 and x=-0.01. However, note that the curve is also very close to zero at x=0, and at that point the first derivative is also zero. In many cases, it is reasonable to assume that the 0.0001 is an artifact of numerical roundoff, and the curve actually has a single zero of order 1 at x=0. The current tolerance is used to choose which case to report. In this example, a tolerance of 0.000001 would mean that we consider 0.0001 a meaningful value (not just roundoff), so we would end up reporting two order-0 zeros at x=0.01 and x=-0.01. On the other hand, a tolerance of 0.01 would mean that we consider 0.0001 as just roundoff error, so we would end up reporting a single order-1 zero at x=0 (the point at which the first derivative is zero).

is_zero() bool

Check if a curve is zero everywhere, within the current tolerance.

__add__(rhs: AngleCurve) AngleCurve
__add__(rhs: Angle) AngleCurve

Return self + rhs.

__sub__(rhs: AngleCurve) AngleCurve
__sub__(rhs: Angle) AngleCurve

Return self - rhs.

__mul__(rhs: float) AngleCurve
__mul__(rhs: Curve) AngleCurve

Return self * rhs.

__truediv__(rhs: float) AngleCurve
__truediv__(rhs: AngleCurve) Curve
__truediv__(rhs: Angle) Curve
__truediv__(rhs: Curve) AngleCurve

Return self / rhs.

__rmul__(lhs: float) AngleCurve

Return lhs * self.

class opensolid.Drawing2d

A set of functions for constructing 2D drawings.

black_stroke: Attribute = <opensolid.Drawing2d.Attribute object>

Black stroke for curves and borders.

no_fill: Attribute = <opensolid.Drawing2d.Attribute object>

Set shapes to have no fill.

static to_svg(view_box: Bounds2d, entities: list[Entity]) str

Render some entities to SVG.

The given bounding box defines the overall size of the drawing, and in general should contain all the drawing entities (unless you want to crop some of them).

static polygon(attributes: list[Attribute], vertices: list[Point2d]) Entity

Create a polygon with the given attributes and vertices.

static circle(attributes: list[Attribute], center_point: Point2d, radius: Length) Entity

Create a circle with the given attributes, center point and radius.

static stroke_color(color: Color) Attribute

Set the stroke color for curves and borders.

static fill_color(color: Color) Attribute

Set the fill color for shapes.

class Entity

A drawing entity such as a shape or group.

class Attribute

A drawing attribute such as fill color or stroke width.