123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 |
- # Purpose: dimension lines as composite entities build with basic dxf entities, but not the DIMENSION entity.
- # Created: 10.03.2010, 2018 adapted for ezdxf
- # Copyright (c) 2010-2018, Manfred Moitzi
- # License: MIT License
- """
- Dimension lines as composite entities build with basic dxf entities, but not the DIMENSION entity.
- OBJECTS
- - LinearDimension
- - AngularDimension
- - ArcDimension
- - RadialDimension
- PUBLIC MEMBERS
- dimstyles
- dimstyle container
- - new(name, kwargs) to create a new dimstyle
- - get(name) to get a dimstyle, 'Default' if name does not exist
- - setup(drawing) create Blocks and Layers in drawing
- """
- from typing import Any, Dict, TYPE_CHECKING, Iterable, List, Tuple
- from math import radians, degrees, pi
- from abc import abstractmethod
- from ezdxf.math.vector import Vector, distance, lerp
- from ezdxf.math.line import ConstructionRay
- if TYPE_CHECKING:
- from ezdxf.eztypes import Drawing, GenericLayoutType, Vertex
- DIMENSIONS_MIN_DISTANCE = 0.05
- DIMENSIONS_FLOATINGPOINT = '.'
- ANGLE_DEG = 180. / pi
- ANGLE_GRAD = 200. / pi
- ANGLE_RAD = 1.
- class DimStyle(dict):
- """
- DimStyle parameter struct, a dumb object just to store values
- """
- default_values = [
- # tick block name, use setup to generate default blocks <dimblk> <dimblk1> <dimblk2>
- ('tick', 'DIMTICK_ARCH'),
- # scale factor for ticks-block <dimtsz> <dimasz>
- ('tickfactor', 1.),
- # tick2x means tick is drawn only for one side, insert tick a second
- # time rotated about 180 degree, but only one time at the dimension line
- # ends, this is useful for arrow-like ticks. hint: set dimlineext to 0. <none>
- ('tick2x', False),
- # dimension value scale factor, value = drawing-units * scale <dimlfac>
- ('scale', 100.),
- # round dimension value to roundval fractional digits <dimdec>
- ('roundval', 0),
- # round dimension value to half units, round 0.4, 0.6 to 0.5 <dimrnd>
- ('roundhalf', False),
- # dimension value text color <dimclrt>
- ('textcolor', 7),
- # dimension value text height <dimtxt>
- ('height', .5),
- # dimension text prefix and suffix like 'x=' ... ' cm' <dimpost>
- ('prefix', ''),
- ('suffix', ''),
- # dimension value text style <dimtxsty>
- ('style', 'OpenSansCondensed-Light'),
- # default layer for whole dimension object
- ('layer', 'DIMENSIONS'),
- # dimension line color index (0 from layer) <dimclrd>
- ('dimlinecolor', 7),
- # dimension line extensions (in dimline direction, left and right) <dimdle>
- ('dimlineext', .3),
- # draw dimension value text `textabove` drawing-units above the
- # dimension line <dimgap>
- ('textabove', 0.2),
- # switch extension line False=off, True=on <dimse1> <dimse2>
- ('dimextline', True),
- # dimension extension line color index (0 from layer) <dimclre>
- ('dimextlinecolor', 5),
- # gap between measure target point and end of extension line <dimexo>
- ('dimextlinegap', 0.3)
- ]
- def __init__(self, name: str, **kwargs):
- super().__init__(DimStyle.default_values)
- # dimstyle name
- self['name'] = name
- self.update(kwargs)
- def __getattr__(self, attr: str) -> Any:
- return self[attr]
- def __setattr__(self, attr: str, value: Any) -> None:
- self[attr] = value
- class DimStyles:
- """
- DimStyle container
- """
- def __init__(self):
- self._styles = {} # type: Dict[str, DimStyle]
- self.default = DimStyle('Default')
- self.new(
- "angle.deg",
- scale=ANGLE_DEG,
- suffix=str('°'),
- roundval=0,
- tick="DIMTICK_RADIUS",
- tick2x=True,
- dimlineext=0.,
- dimextline=False
- )
- self.new(
- "angle.grad",
- scale=ANGLE_GRAD,
- suffix='gon',
- roundval=0,
- tick="DIMTICK_RADIUS",
- tick2x=True,
- dimlineext=0.,
- dimextline=False
- )
- self.new(
- "angle.rad",
- scale=ANGLE_RAD,
- suffix='rad',
- roundval=3,
- tick="DIMTICK_RADIUS",
- tick2x=True,
- dimlineext=0.,
- dimextline=False
- )
- def get(self, name: str) -> DimStyle:
- """
- Get DimStyle() object by name.
- """
- return self._styles.get(name, self.default)
- def new(self, name: str, **kwargs) -> DimStyle:
- """
- Create a new dimstyle
- """
- style = DimStyle(name, **kwargs)
- self._styles[name] = style
- return style
- @staticmethod
- def setup(drawing: 'Drawing'):
- """
- Insert necessary definitions into drawing:
- ticks: DIMTICK_ARCH, DIMTICK_DOT, DIMTICK_ARROW
- """
- # default pen assignment:
- # 1 : 1.40mm - red
- # 2 : 0.35mm - yellow
- # 3 : 0.70mm - green
- # 4 : 0.50mm - cyan
- # 5 : 0.13mm - blue
- # 6 : 1.00mm - magenta
- # 7 : 0.25mm - white/black
- # 8, 9 : 2.00mm
- # >=10 : 1.40mm
- dimcolor = {'color': dimstyles.default.dimextlinecolor, 'layer': 'BYBLOCK'}
- color4 = {'color': 4, 'layer': 'BYBLOCK'}
- color7 = {'color': 7, 'layer': 'BYBLOCK'}
- block = drawing.blocks.new('DIMTICK_ARCH')
- block.add_line(start=(0., +.5), end=(0., -.5), dxfattribs=dimcolor)
- block.add_line(start=(-.2, -.2), end=(.2, +.2), dxfattribs=color4)
- block = drawing.blocks.new('DIMTICK_DOT')
- block.add_line(start=(0., .5), end=(0., -.5), dxfattribs=dimcolor)
- block.add_circle(center=(0, 0), radius=.1, dxfattribs=color4)
- block = drawing.blocks.new('DIMTICK_ARROW')
- block.add_line(start=(0., .5), end=(0., -.50), dxfattribs=dimcolor)
- block.add_solid([(0, 0), (.3, .05), (.3, -.05)], dxfattribs=color7)
- block = drawing.blocks.new('DIMTICK_RADIUS')
- block.add_solid([(0, 0), (.3, .05), (0.25, 0.), (.3, -.05)], dxfattribs=color7)
- dimstyles = DimStyles() # use this factory to create new dimstyles
- class _DimensionBase:
- """
- Abstract base class for dimension lines.
- """
- def __init__(self, dimstyle: str, layer: str, roundval: int):
- self.dimstyle = dimstyles.get(dimstyle)
- self.layer = layer
- self.roundval = roundval
- def prop(self, property_name: str) -> Any:
- """
- Get dimension line properties by `property_name` with the possibility to override several properties.
- """
- if property_name == 'layer':
- return self.layer if self.layer is not None else self.dimstyle.layer
- elif property_name == 'roundval':
- return self.roundval if self.roundval is not None else self.dimstyle.roundval
- else: # pass through self.dimstyle object DimStyle()
- return self.dimstyle[property_name]
- def format_dimtext(self, dimvalue: float) -> str:
- """
- Format the dimension text.
- """
- # TODO: consider roundhalf property
- dimtextfmt = "%." + str(self.prop('roundval')) + "f"
- dimtext = dimtextfmt % dimvalue
- if DIMENSIONS_FLOATINGPOINT in dimtext:
- # remove successional zeros
- dimtext.rstrip('0')
- # remove floating point as last char
- dimtext.rstrip(DIMENSIONS_FLOATINGPOINT)
- return self.prop('prefix') + dimtext + self.prop('suffix')
- @abstractmethod
- def render(self, layout: 'GenericLayoutType'):
- pass
- class LinearDimension(_DimensionBase):
- """
- Simple straight dimension line with two or more measure points, build with basic DXF entities. This is NOT a dxf
- dimension entity. And This is a 2D element, so all z-values will be ignored!
- """
- def __init__(self, pos: 'Vertex', measure_points: Iterable['Vertex'], angle: float = 0., dimstyle: str = 'Default',
- layer: str = None, roundval: int = None):
- """
- LinearDimension Constructor.
- Args:
- pos: location as (x, y) tuple of dimension line, line goes through this point
- measure_points: list of points as (x, y) tuples to dimension (two or more)
- angle: angle (in degree) of dimension line
- dimstyle: dimstyle name, 'Default' - style is the default value
- layer: dimension line layer, override the default value of dimstyle
- roundval: count of decimal places
- """
- super().__init__(dimstyle, layer, roundval)
- self.angle = angle
- self.measure_points = list(measure_points)
- self.text_override = [""] * self.section_count
- self.dimlinepos = Vector(pos)
- self.layout = None
- def set_text(self, section: int, text: str) -> None:
- """
- Set and override the text of the dimension text for the given dimension line section.
- """
- self.text_override[section] = text
- def _setup(self) -> None:
- """
- Calc setup values and determines the point order of the dimension line points.
- """
- self.measure_points = [Vector(point) for point in self.measure_points] # type: List[Vector]
- dimlineray = ConstructionRay(self.dimlinepos, angle=radians(self.angle)) # Type: ConstructionRay
- self.dimline_points = [self._get_point_on_dimline(point, dimlineray) for point in
- self.measure_points] # type: List[Vector]
- self.point_order = self._indices_of_sorted_points(self.dimline_points) # type: List[int]
- self._build_vectors()
- def _get_dimline_point(self, index: int) -> 'Vertex':
- """
- Get point on the dimension line, index runs left to right.
- """
- return self.dimline_points[self.point_order[index]]
- def _get_section_points(self, section: int) -> Tuple[Vector, Vector]:
- """
- Get start and end point on the dimension line of dimension section.
- """
- return self._get_dimline_point(section), self._get_dimline_point(section + 1)
- def _get_dimline_bounds(self) -> Tuple[Vector, Vector]:
- """
- Get the first and the last point of dimension line.
- """
- return self._get_dimline_point(0), self._get_dimline_point(-1)
- @property
- def section_count(self) -> int:
- """ count of dimline sections """
- return len(self.measure_points) - 1
- @property
- def point_count(self) -> int:
- """ count of dimline points """
- return len(self.measure_points)
- def render(self, layout: 'GenericLayoutType') -> None:
- """ build dimension line object with basic dxf entities """
- self._setup()
- self._draw_dimline(layout)
- if self.prop('dimextline'):
- self._draw_extension_lines(layout)
- self._draw_text(layout)
- self._draw_ticks(layout)
- @staticmethod
- def _indices_of_sorted_points(points: Iterable['Vertex']) -> List[int]:
- """ get indices of points, for points sorted by x, y values """
- indexed_points = [(point, idx) for idx, point in enumerate(points)]
- indexed_points.sort()
- return [idx for point, idx in indexed_points]
- def _build_vectors(self) -> None:
- """ build unit vectors, parallel and normal to dimension line """
- point1, point2 = self._get_dimline_bounds()
- self.parallel_vector = (Vector(point2) - Vector(point1)).normalize()
- self.normal_vector = self.parallel_vector.orthogonal()
- @staticmethod
- def _get_point_on_dimline(point: 'Vertex', dimray: ConstructionRay) -> Vector:
- """ get the measure target point projection on the dimension line """
- return dimray.intersect(dimray.orthogonal(point))
- def _draw_dimline(self, layout: 'GenericLayoutType') -> None:
- """ build dimension line entity """
- start_point, end_point = self._get_dimline_bounds()
- dimlineext = self.prop('dimlineext')
- if dimlineext > 0:
- start_point = start_point - (self.parallel_vector * dimlineext)
- end_point = end_point + (self.parallel_vector * dimlineext)
- attribs = {
- 'color': self.prop('dimlinecolor'),
- 'layer': self.prop('layer'),
- }
- layout.add_line(
- start=start_point,
- end=end_point,
- dxfattribs=attribs,
- )
- def _draw_extension_lines(self, layout: 'GenericLayoutType') -> None:
- """ build the extension lines entities """
- dimextlinegap = self.prop('dimextlinegap')
- attribs = {
- 'color': self.prop('dimlinecolor'),
- 'layer': self.prop('layer'),
- }
- for dimline_point, target_point in zip(self.dimline_points, self.measure_points):
- if distance(dimline_point, target_point) > max(dimextlinegap, DIMENSIONS_MIN_DISTANCE):
- direction_vector = (target_point - dimline_point).normalize()
- target_point = target_point - (direction_vector * dimextlinegap)
- layout.add_line(
- start=dimline_point,
- end=target_point,
- dxfattribs=attribs,
- )
- def _draw_text(self, layout: 'GenericLayoutType') -> None:
- """ build the dimension value text entity """
- attribs = {
- 'height': self.prop('height'),
- 'color': self.prop('textcolor'),
- 'layer': self.prop('layer'),
- 'rotation': self.angle,
- 'style': self.prop('style'),
- }
- for section in range(self.section_count):
- dimvalue_text = self._get_dimvalue_text(section)
- insert_point = self._get_text_insert_point(section)
- layout.add_text(
- text=dimvalue_text,
- dxfattribs=attribs,
- ).set_pos(insert_point, align='MIDDLE_CENTER')
- def _get_dimvalue_text(self, section: int) -> str:
- """ get the dimension value as text, distance from point1 to point2 """
- override = self.text_override[section]
- if len(override):
- return override
- point1, point2 = self._get_section_points(section)
- dimvalue = distance(point1, point2) * self.prop('scale')
- return self.format_dimtext(dimvalue)
- def _get_text_insert_point(self, section: int) -> Vector:
- """ get the dimension value text insert point """
- point1, point2 = self._get_section_points(section)
- dist = self.prop('height') / 2. + self.prop('textabove')
- return lerp(point1, point2) + (self.normal_vector * dist)
- def _draw_ticks(self, layout: 'GenericLayoutType') -> None:
- """ insert the dimension line ticks, (markers on the dimension line) """
- attribs = {
- 'xscale': self.prop('tickfactor'),
- 'yscale': self.prop('tickfactor'),
- 'layer': self.prop('layer'),
- }
- def add_tick(index: int, rotate: bool = False) -> None:
- """ build the insert-entity for the tick block """
- attribs['rotation'] = self.angle + (180. if rotate else 0.)
- layout.add_blockref(
- insert=self._get_dimline_point(index),
- name=self.prop('tick'),
- dxfattribs=attribs,
- )
- if self.prop('tick2x'):
- for index in range(0, self.point_count - 1):
- add_tick(index, False)
- for index in range(1, self.point_count):
- add_tick(index, True)
- else:
- for index in range(self.point_count):
- add_tick(index, False)
- class AngularDimension(_DimensionBase):
- """
- Draw an angle dimensioning line at dimline pos from start to end, dimension text is the angle build of the three
- points start-center-end.
- """
- DEG = ANGLE_DEG
- GRAD = ANGLE_GRAD
- RAD = ANGLE_RAD
- def __init__(self, pos: 'Vertex', center: 'Vertex', start: 'Vertex', end: 'Vertex',
- dimstyle: str = 'angle.deg', layer: str = None, roundval: int = None):
- """
- AngularDimension constructor.
- Args:
- pos: location as (x, y) tuple of dimension line, line goes through this point
- center: center point as (x, y) tuple of angle
- start: line from center to start is the first side of the angle
- end: line from center to end is the second side of the angle
- dimstyle: dimstyle name, 'Default' - style is the default value
- layer: dimension line layer, override the default value of dimstyle
- roundval: count of decimal places
- """
- super().__init__(dimstyle, layer, roundval)
- self.dimlinepos = Vector(pos)
- self.center = Vector(center)
- self.start = Vector(start)
- self.end = Vector(end)
- def _setup(self) -> None:
- """ setup calculation values """
- self.pos_radius = distance(self.center, self.dimlinepos) # type: float
- self.radius = distance(self.center, self.start) # type: float
- self.start_vector = (self.start - self.center).normalize() # type: Vector
- self.end_vector = (self.end - self.center).normalize() # type: Vector
- self.start_angle = self.start_vector.angle # type: float
- self.end_angle = self.end_vector.angle # type: float
- def render(self, layout: 'GenericLayoutType') -> None:
- """ build dimension line object with basic dxf entities """
- self._setup()
- self._draw_dimension_line(layout)
- if self.prop('dimextline'):
- self._draw_extension_lines(layout)
- self._draw_dimension_text(layout)
- self._draw_ticks(layout)
- def _draw_dimension_line(self, layout: 'GenericLayoutType') -> None:
- """ draw the dimension line from start- to endangle. """
- layout.add_arc(
- radius=self.pos_radius,
- center=self.center,
- start_angle=degrees(self.start_angle),
- end_angle=degrees(self.end_angle),
- dxfattribs={
- 'layer': self.prop('layer'),
- 'color': self.prop('dimlinecolor'),
- }
- )
- def _draw_extension_lines(self, layout: 'GenericLayoutType') -> None:
- """ build the extension lines entities """
- for vector in [self.start_vector, self.end_vector]:
- layout.add_line(
- start=self._get_extline_start(vector),
- end=self._get_extline_end(vector),
- dxfattribs={
- 'layer': self.prop('layer'),
- 'color': self.prop('dimextlinecolor'),
- }
- )
- def _get_extline_start(self, vector: Vector) -> Vector:
- return self.center + (vector * self.prop('dimextlinegap'))
- def _get_extline_end(self, vector: Vector) -> Vector:
- return self.center + (vector * self.pos_radius)
- def _draw_dimension_text(self, layout: 'GenericLayoutType') -> None:
- attribs = {
- 'height': self.prop('height'),
- 'rotation': degrees((self.start_angle + self.end_angle) / 2 - pi / 2.),
- 'layer': self.prop('layer'),
- 'style': self.prop('style'),
- 'color': self.prop('textcolor'),
- }
- layout.add_text(
- text=self._get_dimtext(),
- dxfattribs=attribs,
- ).set_pos(self._get_text_insert_point(), align='MIDDLE_CENTER')
- def _get_text_insert_point(self) -> Vector:
- midvector = ((self.start_vector + self.end_vector) / 2.).normalize()
- length = self.pos_radius + self.prop('textabove') + self.prop('height') / 2.
- return self.center + (midvector * length)
- def _draw_ticks(self, layout: 'GenericLayoutType') -> None:
- attribs = {
- 'xscale': self.prop('tickfactor'),
- 'yscale': self.prop('tickfactor'),
- 'layer': self.prop('layer'),
- }
- for vector, mirror in [(self.start_vector, False), (self.end_vector, self.prop('tick2x'))]:
- insert_point = self.center + (vector * self.pos_radius)
- rotation = vector.angle + pi / 2.
- attribs['rotation'] = degrees(rotation + (pi if mirror else 0.))
- layout.add_blockref(
- insert=insert_point,
- name=self.prop('tick'),
- dxfattribs=attribs,
- )
- def _get_dimtext(self) -> str:
- # set scale = ANGLE_DEG for degrees (circle = 360 deg)
- # set scale = ANGLE_GRAD for grad(circle = 400 grad)
- # set scale = ANGLE_RAD for rad(circle = 2*pi)
- angle = (self.end_angle - self.start_angle) * self.prop('scale')
- return self.format_dimtext(angle)
- class ArcDimension(AngularDimension):
- """
- Arc is defined by start- and endpoint on arc and the center point, or by three points lying on the arc if acr3points
- is True. Measured length goes from start- to endpoint. The dimension line goes through the dimlinepos.
- """
- def __init__(self, pos: 'Vertex', center: 'Vertex', start: 'Vertex', end: 'Vertex', arc3points: bool = False,
- dimstyle: str = 'Default', layer: str = None, roundval: int = None):
- """
- Args:
- pos: location as (x, y) tuple of dimension line, line goes through this point
- center: center point of arc
- start: start point of arc
- end: end point of arc
- arc3points: if **True** arc is defined by three points on the arc (center, start, end)
- dimstyle: dimstyle name, 'Default' - style is the default value
- layer: dimension line layer, override the default value of dimstyle
- roundval: count of decimal places
- """
- super().__init__(pos, center, start, end, dimstyle, layer, roundval)
- self.arc3points = arc3points
- def _setup(self) -> None:
- super()._setup()
- if self.arc3points:
- self.center = center_of_3points_arc(self.center, self.start, self.end)
- def _get_extline_start(self, vector: Vector) -> Vector:
- return self.center + (vector * (self.radius + self.prop('dimextlinegap')))
- def _get_extline_end(self, vector: Vector) -> Vector:
- return self.center + (vector * self.pos_radius)
- def _get_dimtext(self) -> str:
- arc_length = (self.end_angle - self.start_angle) * self.radius * self.prop('scale')
- return self.format_dimtext(arc_length)
- class RadialDimension(_DimensionBase):
- """
- Draw a radius dimension line from `target` in direction of `center` with length drawing units. RadialDimension has
- a special tick!!
- """
- def __init__(self, center: 'Vertex', target: 'Vertex', length: float = 1., dimstyle: str = 'Default',
- layer: str = None, roundval: int = None):
- """
- Args:
- center: center point of radius
- target: target point of radius
- length: length of radius arrow (drawing length)
- dimstyle: dimstyle name, 'Default' - style is the default value
- layer: dimension line layer, override the default value of dimstyle
- roundval: count of decimal places
- """
- super().__init__(dimstyle, layer, roundval)
- self.center = Vector(center)
- self.target = Vector(target)
- self.length = float(length)
- def _setup(self) -> None:
- self.target_vector = (self.target - self.center).normalize() # type: Vector
- self.radius = distance(self.center, self.target) # type: float
- def render(self, layout: 'GenericLayoutType') -> None:
- """ build dimension line object with basic dxf entities """
- self._setup()
- self._draw_dimension_line(layout)
- self._draw_dimension_text(layout)
- self._draw_ticks(layout)
- def _draw_dimension_line(self, layout: 'GenericLayoutType') -> None:
- start_point = self.center + (self.target_vector * (self.radius - self.length))
- layout.add_line(
- start=start_point, end=self.target,
- dxfattribs={
- 'color': self.prop('dimlinecolor'),
- 'layer': self.prop('layer'),
- },
- )
- def _draw_dimension_text(self, layout: 'GenericLayoutType') -> None:
- layout.add_text(
- text=self._get_dimtext(),
- dxfattribs={
- 'height': self.prop('height'),
- 'rotation': self.target_vector.angle_deg,
- 'layer': self.prop('layer'),
- 'style': self.prop('style'),
- 'color': self.prop('textcolor'),
- }
- ).set_pos(self._get_insert_point(), align='MIDDLE_RIGHT')
- def _get_insert_point(self) -> Vector:
- return self.target - (self.target_vector * (self.length + self.prop('textabove')))
- def _get_dimtext(self) -> str:
- return self.format_dimtext(self.radius * self.prop('scale'))
- def _draw_ticks(self, layout: 'GenericLayoutType') -> None:
- layout.add_blockref(
- insert=self.target,
- name='DIMTICK_RADIUS',
- dxfattribs={
- 'rotation': self.target_vector.angle_deg + 180,
- 'xscale': self.prop('tickfactor'),
- 'yscale': self.prop('tickfactor'),
- 'layer': self.prop('layer'),
- }
- )
- def center_of_3points_arc(point1: 'Vertex', point2: 'Vertex', point3: 'Vertex') -> Vector:
- """
- Calc center point of 3 point arc. ConstructionCircle is defined by 3 points on the circle: point1, point2 and point3.
- """
- ray1 = ConstructionRay(point1, point2)
- ray2 = ConstructionRay(point1, point3)
- midpoint1 = lerp(point1, point2)
- midpoint2 = lerp(point1, point3)
- center_ray1 = ray1.orthogonal(midpoint1)
- center_ray2 = ray2.orthogonal(midpoint2)
- return center_ray1.intersect(center_ray2)
|