New general transformation interface based on homogeneous transformation matrices. Supported transformations are scale & reflection, rotate and translate.

Transformation works best for entities with WCS vertices only like POINT, LINE or MESH. Uniform scale transformation works well for OCS entities like TEXT or INSERT. Problems exist for non uniform scaling and reflections for OCS entities including text or curves, especially the HATCH entity with arc- or ellipse edge paths, but ARC and ELLIPSE entities itself should work as expected.

Good support for:

- POINT
- LINE
- ELLIPSE
- MESH
- SPLINE
- 3D POLYLINE, POLYMESH & POLYFACE
- SOLID
- TRACE
- 3DFACE
- XLINE
- RAY
- IMAGE

Problems with non uniform scaling and/or reflections:

- CIRCLE, must be converted to ELLIPSE for non uniform scaling
- ARC, must be converted to ELLIPSE for non uniform scaling
- LWPOLYLINE, must be exploded for non uniform scaling if has arcs; ARC converted to ELLIPSE
- 2D POLYLINE, must be exploded for non uniform scaling if has arcs; ARC converted to ELLIPSE
- HATCH with arc edges or bulges in polyline paths, have to be converted into ellipse edges for non uniform scaling
- INSERT: DXF attributes can only represent orthogonal target coordinate systems
- TEXT, ATTRIB, ATTDEF, MTEXT, SHAPE: transformations are limited by available DXF attributes

Untested:

- HELIX
- LIGHT
- LEADER
- TOLERANCE
- DIMENSION

Unsupported:

- ACAD_TABLE, MLEADER, MLINE: just preserved entity types
- ACIS entities like 3DSOLID, BODY or REGION (no access to geometry data)
- Proxy entities (unknown data)
- External references
- Underlays
- VIEWPORT

This new transformation interface also improves results for non uniform scaling for `Insert.virtual_entities()`

and `Insert.explode()`

, therefore the argument `non_uniform_scaling`

to explicit enable non uniform scaling is
marked as deprecated.

Example: rotate first line in `"my.dxf"`

90 degrees about the z-axis

```
import math
import ezdxf
from ezdxf.math import Matrix44
doc = ezdxf.readfile('my.dxf')
msp = doc.modelspace()
line = msp.query('LINE').first
if line:
m = Matrix44.z_rotate(math.pi/2)
line.transform(m)
```

Specialized entity transformation interfaces:

`translate(dx, dy, dz)`

, translation in x-, y- and z-axis`scale(sx, sy, sz)`

, use negative values for reflections`scale_uniform(s)`

, uniform scaling in x-, y- and z-axis`rotate_axis(axis, angle)`

, rotate about arbitrary axis, rotation center is the origin at (0, 0, 0)`rotate_x(angle)`

, rotation about the x-axis`rotate_y(angle)`

, rotation about the y-axis`rotate_z(angle)`

, rotation about the z-axis

Simplified example:

```
...
if line:
line.rotate_z(math.pi/2)
```

The new drawing add-on by Matt Broadway is a translation layer to send DXF data to a render backend.

Basic supported for following backends are included:

Both packages are optional and **not required** to install *ezdxf*.

The implementation uses a `Frontend`

object to break DXF entities down into graphic primitives and send this data to
the `Backend`

object. Not all DXF entities are supported yet and embedded ACIS data like in BODY, 3DSOLID or REGION
will never be supported. Some of these missing DXF entities may get support in the future
(LEADER, MLEADER, ACAD_TABLE). Support of start- and end width attributes for 2D polylines is also planned.

There are two example scripts to show how to use the `drawing`

add-on to implement a DXF converter or DXF viewer.

- draw_cad.py uses matplotlib as backend to convert DXF documents into pixel- or vector graphic.
- cad_viewer.py is a DXF viewer, using PyQt5 as backend.

Both are basic implementations without support for lineweights, linetypes, hatch pattern or multiple fonts and 3D objects are rendered flat into the xy-plane in wire-frame style. Additional features are planned, but don't expect a TrueView replacement, this is beyond our capabilities, time resources and the performance of a Python based project.

Convert CIRCLE and ARC to ELLIPSE entities by default the source ARC will be replaced by the new ELLIPSE entity:

```
for arc in msp.query('ARC'):
arc.to_ellipse()
```

Set argument `replace`

to `False`

to add an additional ELLIPSE entity without deleting the source ARC:

```
for arc in msp.query('ARC'):
arc.to_ellipse(replace=False)
```

Convert CIRCLE, ARC and ELLIPSE to SPLINE entities:

```
for arc in msp.query('ARC'):
arc.to_spline()
```

The SPLINE entities have the best approximation with a minimum number of control points.

Constructors to create rational splines from arc (`BSpline.from_arc()`

) and ellipses (`BSpline.from_ellipse()`

).

Decomposition of non-rational B-splines into multiple Bezier curves by `BSpline.bezier_decomposition()`

to
feed B-splines into render engines with Bezier curve support. Works best with non-rational B-splines of 3rd degree,
perhaps the the most common used B-spline, yielding cubic bezier curves, which are supported by many render engines.

Interface between the SPLINE DXF entity class and the construction tool `BSpline()`

, `Spline.construction_tool()`

returns the spline as `BSpline()`

object and `Spline.apply_construction_tool()`

transfer data from the `BSpline()`

to
the DXF entity. The same interface exist for the ELLIPSE entity and the `ConstructionEllipse()`

class.

Interface to NURBS-Python to convert `BSpline()`

objects to
NURBS-Python curves by `BSpline.to_nurbs_python_curve()`

and back by `BSpline.from_nurbs_python_curve()`

. This
requires the installation of the `geomdl`

package which is the PyPI name of NURBS-Python:

```
pip install --user geomdl
```

An interface to surfaces and volumes may follow, but only from NURBS-Python to *ezdxf*, because
without ACIS support, *ezdxf* is restricted to mesh objects.

Rewritten spline interpolation without and with end derivative (tangents) support as function
`global_spline_interpolation()`

including helper tools to estimate tangents and end tangent magnitudes.
A new `local_bspline_interpolation()`

function and a fast `cubic_bezier_interpolation()`

function also exist.

A faster linear equation solver for interpolation tasks was required: the new `LUDecomposition()`

is faster than the
previous `gauss_*_solver()`

functions and a new banded diagonal matrix solver `BandedMatrixLU()`

for even faster
results for bigger matrices was added, `compact_banded_matrix()`

is a helper function to create banded diagonal
matrices and `detect_banded_matrix()`

is its sidekick to auto-detect the required parameters.

Integrated derivative computation into `BSpline()`

and `Bezier()`

from special derivative classes. Instead of
overriding the `point()`

method, a new `derivative()`

method exists which returns the curve point and derivatives.

Most of this new math tools are based on two books:

- B-Splines: "The NURBS Book" by Piegl and Tiller
- Linear Equation Solver: "Numerical Receipes" by Press, Teukolsky, Vetterling and Flannery

- BUGFIX: remove white space from structure tags like "SECTION "
- BUGFIX:
`MeshBuilder.from_polyface()`

processing error of POLYMESH entities

- NEW: general transformation interface:
`DXFGraphic.transform(m)`

, transform entity by a transformation matrix`m`

inplace - NEW: specialized entity transformation interfaces:
`DXFGraphic.translate(dx, dy, dz)`

`DXFGraphic.scale(sx, sy, sz)`

`DXFGraphic.scale_uniform(s)`

`DXFGraphic.rotate_axis(axis, angle)`

`DXFGraphic.rotate_x(angle)`

`DXFGraphic.rotate_y(angle)`

`DXFGraphic.rotate_z(angle)`

- NEW: drawing add-on by Matt Broadway is a translation
layer to send DXF data to a render backend, supported backends for now:
matplotlib and PyQt5, both packages
are optional and not required to install
*ezdxf*. - NEW:
`DXFGraphic.unlink_from_layout()`

to unlink entity from associated layout - NEW:
`Arc.angles(num)`

, yields`num`

angles from start- to end angle in counter clockwise order - NEW:
`Circle.to_ellipse()`

, convert CIRCLE/ARC to ELLIPSE entity - NEW:
`Circle.to_spline()`

, convert CIRCLE/ARC to SPLINE entity - NEW:
`Ellipse.params(num)`

, yields`num`

params from start- to end param in counter clockwise order - NEW:
`Ellipse.construction_tool()`

, return ellipse data as`ConstructionEllipse()`

- NEW:
`Ellipse.apply_construction_tool()`

, apply`ConstructionEllipse()`

data - NEW:
`Ellipse.to_spline()`

, convert ELLIPSE to SPLINE entity - NEW:
`Ellipse.from_arc()`

, create a new ELLIPSE entity from CIRCLE or ARC entity (constructor) - NEW:
`Spline.construction_tool()`

, return spline data as`ezdxf.math.BSpline()`

- NEW:
`Spline.apply_construction_tool()`

, apply`ezdxf.math.BSpline()`

data - NEW:
`Spline.from_arc()`

, create a new SPLINE entity from CIRCLE, ARC or ELLIPSE entity (constructor) - NEW:
`Hatch.set_pattern_scale()`

to set scaling of pattern definition - NEW:
`Hatch.set_pattern_angle()`

to set rotation angle of pattern definition - NEW:
`Hatch.paths.polyline_to_edge_path()`

convert polyline paths with bulge values to edge paths with lines and arcs - NEW:
`Hatch.paths.arc_edges_to_ellipse_edges()`

convert arc edges to ellipse edges - NEW:
`Hatch.paths.ellipse_edges_to_spline_edges()`

convert ellipse edges to spline edges - NEW:
`Hatch.paths.all_to_spline_edges()`

convert all curves to approximated spline edges - NEW:
`Hatch.paths.all_to_line_edges()`

convert all curves to approximated line edges - NEW:
`Text.plain_text()`

returns text content without formatting codes - NEW:
`ezdxf.math.ConstructionEllipse()`

- NEW:
`ezdxf.math.linspace()`

like`numpy.linspace()`

- NEW:
`ezdxf.math.global_bspline_interpolation()`

supports start- and end tangent constraints - NEW:
`ezdxf.math.estimate_tangents()`

curve tangent estimator for given fit points - NEW:
`ezdxf.math.estimate_end_tangent_magnitude()`

curve end tangent magnitude estimator for given fit points - NEW:
`ezdxf.math.rational_spline_from_arc()`

returns a rational B-spline for a circular arc - NEW:
`ezdxf.math.rational_spline_from_ellipse()`

returns a rational B-spline for an elliptic arc - NEW:
`ezdxf.math.local_cubic_bspline_interpolation()`

- NEW:
`ezdxf.math.cubic_bezier_from_arc()`

returns an approximation for a circular 2D arc by multiple cubic Bezier curves - NEW:
`ezdxf.math.cubic_bezier_from_ellipse()`

returns an approximation for an elliptic arc by multiple cubic Bezier curves - NEW:
`ezdxf.math.cubic_bezier_interpolation()`

returns an interpolation curve for arbitrary data points as multiple cubic Bezier curves - NEW:
`ezdxf.math.LUDecomposition`

linear equation solver, for more linear algebra tools see module`ezdxf.math.linalg`

- NEW:
`ezdxf.render.random_2d_path()`

generate random 2D path for testing purpose - NEW:
`ezdxf.render.random_3d_path()`

generate random 3D path for testing purpose - NEW:
`BSpline()`

uses normalized knot vector for 'clamped' curves by default (open uniform knots) - NEW:
`BSpline.points()`

compute multiple points - NEW:
`BSpline.derivative()`

compute point and derivative up to n <= degree - NEW:
`BSpline.derivatives()`

compute multiple points and derivatives up to n <= degree - NEW:
`BSpline.params()`

return evenly spaced B-spline params from start- to end param - NEW:
`BSpline.reverse()`

returns a new reversed B-spline - NEW:
`BSpline.from_arc()`

B-spline from an arc, best approximation with a minimum number of control points - NEW:
`BSpline.from_ellipse()`

B-spline from an ellipse, best approximation with a minimum number of control points - NEW:
`BSpline.from_fit_points()`

B-spline from fit points - NEW:
`BSpline.arc_approximation()`

B-spline approximation from arc vertices as fit points - NEW:
`BSpline.ellipse_approximation()`

B-spline approximation from ellipse vertices as fit points - NEW:
`BSpline.transform()`

transform B-spline by transformation matrix inplace - NEW:
`BSpline.transform()`

transform B-spline by transformation matrix inplace - NEW:
`BSpline.to_nurbs_python_curve()`

and`BSpline.from_nurbs_python_curve()`

, interface to NURBS-Python,`NURBS-Python`

is now a testing dependency - NEW:
`BSpline.bezier_decomposition()`

decompose a non-rational B-spline into multiple Bezier curves - NEW:
`BSpline.cubic_bezier_approximation()`

approximate any B-spline by multiple cubic Bezier curves - NEW:
`Bezier.points()`

compute multiple points - NEW:
`Bezier.derivative()`

compute point, 1st and 2nd derivative for one parameter - NEW:
`Bezier.derivatives()`

compute point and derivative for multiple parameters - CHANGE:
`Hatch`

full support for rotated patterns. - CHANGE:
`Hatch.set_pattern_definition()`

added argument`angle`

for pattern rotation. - CHANGE:
`Hatch.path.add_arc`

renamed argument`is_counter_clockwise`

to`ccw`

, type`bool`

and`True`

by default - CHANGE:
`Hatch.path.add_ellipse`

renamed argument`is_counter_clockwise`

to`ccw`

, type`bool`

and`True`

by default - CHANGE: renamed 2D
`ConstructionXXX.move()`

methods to`translate()`

- CHANGE: renamed old
`Insert.scale()`

to`Insert.set_scale()`

, name conflict with transformation interface - CHANGE: renamed
`Spline.set_periodic()`

to`Spline.set_closed()`

- CHANGE: renamed
`Spline.set_periodic_rational()`

to`Spline.set_closed_rational()`

- CHANGE: renamed
`ezdxf.math.bspline_control_frame()`

to`ezdxf.math.global_bspline_interpolation()`

- REMOVED:
`ezdxf.math.Matrix33`

class,`UCS`

and`OCS`

uses`Matrix44`

for transformations - REMOVED:
`ezdxf.math.BRCS`

class and`Insert.brcs()`

- REMOVED:
`ezdxf.math.ConstructionTool`

base class - REMOVED:
`ezdxf.math.normalize_angle(angle)`

, replace call by expression:`angle % math.tau`

- REMOVED:
`ezdxf.math.DBSpline`

, integrated as`BSpline.derivatives()`

- REMOVED:
`ezdxf.math.DBSplineU`

, integrated as`BSplineU.derivatives()`

- REMOVED:
`ezdxf.math.DBSplineClosed`

, integrated as`BSplineClosed.derivatives()`

- REMOVED:
`ezdxf.math.DBezier`

, integrated as`Bezier.derivatives()`

- REMOVED:
`BaseLayout.add_spline_approx()`

, incorrect and nobody noticed it - so it's not really needed, if required use the`geomdl.fitting.approximate_curve()`

function from the package NURBS-Python, see example`using_nurbs_python.py`

- REMOVED:
`ezdxf.math.bspline_control_frame_approx()`

, incorrect and nobody noticed it - so it's not really needed - DEPRECATED:
`DXFGraphic.transform_to_wcs(ucs)`

, replace call by`DXFGraphic.transform(ucs.matrix)`

- DEPRECATED:
`non_uniform_scaling`

argument for`Insert.explode()`

- DEPRECATED:
`non_uniform_scaling`

argument for`Insert.virtual_entities()`

- DEPRECATED: getter and edit methods in
`Hatch`

for attributes`paths`

,`gradient`

,`pattern`

and`seeds`

- DEPRECATED:
`Spline.edit_data()`

all attributes accessible by properties - BUGFIX:
`ezdxf.math.intersection_ray_ray_3d()`

- BUGFIX:
`Spline.set_periodic()`

created invalid data for BricsCAD - misleading information by Autodesk