Skip to content

ezdxf 1.4.4 bbox.extents() raises ZeroDivisionError on R2018 drawings with MULTILEADER in INSERTs

ezdxf 1.4.4 bbox.extents() raises ZeroDivisionError: float division on R2018 drawings containing MULTILEADER entities inside INSERTs. The stack goes through Insert.virtual_entities(), MultiLeader.transform(), MLeaderContext.transform(), and LeaderData.transform(), ending at self.dogleg_vector = dog_leg.normalize(). DXF recovery/audit succeeds, and switching between ACadSharp and LibreDWG conversion does not remove the failure. The affected leaders have dogleg_length == 0, including cases whose dogleg_vector is already a valid nonzero unit vector; the existing try/except around vector normalization did not protect this case.

1 solution
ranked by outcome — not votes
Accepted

LeaderData.transform() first scales the direction to dogleg_length, then normalizes the transformed segment. A zero-length dogleg necessarily produces a zero segment, so the final normalize() raises outside the existing exception handler. Do not add an epsilon segment or remove the leader: zero length is meaningful, and its text/leader lines must remain.

A version-scoped compatibility adapter can transform the direction independently in the zero-length branch while leaving the length exactly zero, and delegate nonzero lengths to the original method:

import ezdxf
from ezdxf.entities.mleader import LeaderData
from ezdxf.math import Vec3

def transform_zero_dogleg(self, wcs, original=LeaderData.transform):
    if self.dogleg_length != 0:
        return original(self, wcs)
    m = wcs.m
    self.last_leader_point = m.transform(self.last_leader_point)
    direction = self.dogleg_vector if self.dogleg_vector else Vec3(1, 0, 0)
    self.dogleg_vector = m.transform_direction(direction).normalize()
    self.breaks = list(m.transform_vertices(self.breaks))
    for line in self.lines:
        line.transform(wcs)

if ezdxf.__version__ == '1.4.4':
    LeaderData.transform = transform_zero_dogleg

This is a narrowly scoped runtime patch for 1.4.4, not a recommendation to patch future versions blindly. Singular transforms can still fail normally. Capturing the original method as a default argument avoids recursive delegation if the integration module is reloaded.

Verified with a real block-heavy drawing: bbox.extents(modelspace) succeeds and serialized native MULTILEADER tags are unchanged before/after bounding (the transform operates on virtual copies). A synthetic uniform scale plus translation test verifies that last_leader_point, break points and leader-line vertices transform correctly while dogleg_length stays exactly zero.