def transform(self, m: Matrix44) -> 'MText': """ Transform the MTEXT entity by transformation matrix `m` inplace. """ dxf = self.dxf old_extrusion = Vec3(dxf.extrusion) new_extrusion, _ = transform_extrusion(old_extrusion, m) if dxf.hasattr('rotation') and not dxf.hasattr('text_direction'): # MTEXT is not an OCS entity, but I don't know how else to convert # a rotation angle for an entity just defined by an extrusion vector. # It's correct for the most common case: extrusion=(0, 0, 1) ocs = OCS(old_extrusion) dxf.text_direction = ocs.to_wcs(Vec3.from_deg_angle(dxf.rotation)) dxf.discard('rotation') old_text_direction = Vec3(dxf.text_direction) new_text_direction = m.transform_direction(old_text_direction) old_char_height_vec = old_extrusion.cross( old_text_direction).normalize(dxf.char_height) new_char_height_vec = m.transform_direction(old_char_height_vec) oblique = new_text_direction.angle_between(new_char_height_vec) dxf.char_height = new_char_height_vec.magnitude * math.sin(oblique) if dxf.hasattr('width'): width_vec = old_text_direction.normalize(dxf.width) dxf.width = m.transform_direction(width_vec).magnitude dxf.insert = m.transform(dxf.insert) dxf.text_direction = new_text_direction dxf.extrusion = new_extrusion return self
def transform(self, m: Matrix44): self.bounding_box = BoundingBox([ m.transform(self.bounding_box.extmin), m.transform(self.bounding_box.extmax), ]) for e in self.entities: e.transform(m)
def transform(self, m: Matrix44) -> "Point": """Transform the POINT entity by transformation matrix `m` inplace.""" self.dxf.location = m.transform(self.dxf.location) transform_thickness_and_extrusion_without_ocs(self, m) # ignore dxf.angle! self.post_transform(m) return self
def transform(self, m: Matrix44) -> "MText": """Transform the MTEXT entity by transformation matrix `m` inplace.""" dxf = self.dxf old_extrusion = Vec3(dxf.extrusion) new_extrusion, _ = transform_extrusion(old_extrusion, m) self.convert_rotation_to_text_direction() old_text_direction = Vec3(dxf.text_direction) new_text_direction = m.transform_direction(old_text_direction) old_vertical_direction = old_extrusion.cross(old_text_direction) old_char_height_vec = old_vertical_direction.normalize(dxf.char_height) new_char_height_vec = m.transform_direction(old_char_height_vec) oblique = new_text_direction.angle_between(new_char_height_vec) dxf.char_height = new_char_height_vec.magnitude * math.sin(oblique) if dxf.hasattr("width"): width_vec = old_text_direction.normalize(dxf.width) dxf.width = m.transform_direction(width_vec).magnitude dxf.insert = m.transform(dxf.insert) dxf.text_direction = new_text_direction dxf.extrusion = new_extrusion if self.has_columns: hscale = m.transform_direction( old_text_direction.normalize()).magnitude vscale = m.transform_direction( old_vertical_direction.normalize()).magnitude self._columns.transform(m, hscale, vscale) # type: ignore self.post_transform(m) return self
def transform(self, m: Matrix44) -> 'XLine': """ Transform the XLINE/RAY entity by transformation matrix `m` inplace. """ self.dxf.start = m.transform(self.dxf.start) self.dxf.unit_vector = m.transform_direction( self.dxf.unit_vector).normalize() return self
def transform(self, m: Matrix44) -> 'Point': """ Transform POINT entity by transformation matrix `m` inplace. .. versionadded:: 0.13 """ self.dxf.location = m.transform(self.dxf.location) transform_thickness_and_extrusion_without_ocs(self, m) # ignore dxf.angle! return self
def transform_xdata_tags(tags: Tags, m: Matrix44) -> Iterator[DXFTag]: for tag in tags: code, value = tag if code == 1011: # move, scale, rotate and mirror yield dxftag(code, m.transform(Vec3(value))) elif code == 1012: # scale, rotate and mirror yield dxftag(code, m.transform_direction(Vec3(value))) elif code == 1013: # rotate and mirror vec = Vec3(value) length = vec.magnitude if length > 1e-12: vec = m.transform_direction(vec).normalize(length) yield dxftag(code, vec) else: yield tag elif code == 1041 or code == 1042: # scale distance and factor, works only for uniform scaling vec = m.transform_direction(Vec3(value, 0, 0)) yield dxftag(code, vec.magnitude) else: yield tag
def transform(self, m: Matrix44) -> None: """ Transform ellipse in place by transformation matrix `m`. """ new_center = m.transform(self.center) # 2021-01-28 removed % math.tau old_start_param = start_param = self.start_param old_end_param = end_param = self.end_param old_minor_axis = minor_axis(self.major_axis, self.extrusion, self.ratio) new_major_axis, new_minor_axis = m.transform_directions( (self.major_axis, old_minor_axis)) # Original ellipse parameters stay untouched until end of transformation dot_product = new_major_axis.normalize().dot( new_minor_axis.normalize()) if abs(dot_product) > 1e-6: new_major_axis, new_minor_axis, new_ratio = rytz_axis_construction( new_major_axis, new_minor_axis) new_extrusion = new_major_axis.cross(new_minor_axis).normalize() adjust_params = True else: # New axis are nearly orthogonal: new_ratio = new_minor_axis.magnitude / new_major_axis.magnitude # New normal vector: new_extrusion = new_major_axis.cross(new_minor_axis).normalize() # Calculate exact minor axis: new_minor_axis = minor_axis(new_major_axis, new_extrusion, new_ratio) adjust_params = False if adjust_params and not math.isclose( start_param, end_param, abs_tol=1e-9): # open ellipse, adjusting start- and end parameter x_axis = new_major_axis.normalize() y_axis = new_minor_axis.normalize() # TODO: use ellipse_param_span()? # 2021-01-28 this is possibly the source of errors! old_param_span = (end_param - start_param) % math.tau def param(vec: 'Vec3') -> float: dy = y_axis.dot(vec) / new_ratio # adjust to circle dx = x_axis.dot(vec) return math.atan2(dy, dx) % math.tau # transformed start- and end point of old ellipse start_point = m.transform( vertex(start_param, self.major_axis, old_minor_axis, self.center, self.ratio)) end_point = m.transform( vertex(end_param, self.major_axis, old_minor_axis, self.center, self.ratio)) start_param = param(start_point - new_center) end_param = param(end_point - new_center) # Test if drawing the correct side of the curve if not math.isclose(old_param_span, math.pi, abs_tol=1e-9): # Equal param span check works well, except for a span of exact # pi (180 deg). # TODO: use ellipse_param_span()? # 2021-01-28 this is possibly the source of errors! new_param_span = (end_param - start_param) % math.tau if not math.isclose( old_param_span, new_param_span, abs_tol=1e-9): start_param, end_param = end_param, start_param else: # param span is exact pi (180 deg) # expensive but it seem to work: old_chk_point = m.transform( vertex( mid_param(old_start_param, old_end_param), self.major_axis, old_minor_axis, self.center, self.ratio, )) new_chk_point = vertex( mid_param(start_param, end_param), new_major_axis, new_minor_axis, new_center, new_ratio, ) if not old_chk_point.isclose(new_chk_point, abs_tol=1e-9): start_param, end_param = end_param, start_param if new_ratio > 1: new_major_axis = minor_axis(new_major_axis, new_extrusion, new_ratio) new_ratio = 1.0 / new_ratio new_minor_axis = minor_axis(new_major_axis, new_extrusion, new_ratio) if not (math.isclose(start_param, 0) and math.isclose(end_param, math.tau)): start_param -= pi2 end_param -= pi2 # TODO: remove normalize start- and end params? # 2021-01-28 this is possibly the source of errors! start_param = start_param % math.tau end_param = end_param % math.tau if math.isclose(start_param, end_param): start_param = 0.0 end_param = math.tau self.center = new_center self.major_axis = new_major_axis self.minor_axis = new_minor_axis self.extrusion = new_extrusion self.ratio = new_ratio self.start_param = start_param self.end_param = end_param
def transform(self, mat: Matrix44): v0 = Vector(self.X, self.Y, self.Z) v1 = mat.transform(v0) self.X = v1.x self.Y = v1.y self.Z = v1.z