1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
|
# Copyright (c) 2019-2022 Manfred Moitzi
# License: MIT License
import pytest
from ezdxf.entities.circle import Circle
from ezdxf.lldxf.const import DXF12, DXF2000
from ezdxf.lldxf.tagwriter import TagCollector, basic_tags_from_text
from ezdxf.math import Vec3, Matrix44, OCS, NonUniformScalingError
TEST_CLASS = Circle
TEST_TYPE = "CIRCLE"
ENTITY_R12 = """0
CIRCLE
5
0
8
0
10
0.0
20
0.0
30
0.0
40
1.0
"""
ENTITY_R2000 = """0
CIRCLE
5
0
330
0
100
AcDbEntity
8
0
100
AcDbCircle
10
0.0
20
0.0
30
0.0
40
1.0
"""
@pytest.fixture(params=[ENTITY_R12, ENTITY_R2000])
def entity(request):
return TEST_CLASS.from_text(request.param)
def test_registered():
from ezdxf.entities.factory import ENTITY_CLASSES
assert TEST_TYPE in ENTITY_CLASSES
def test_default_init():
entity = TEST_CLASS()
assert entity.dxftype() == TEST_TYPE
assert entity.dxf.handle is None
assert entity.dxf.owner is None
def test_negative_radius():
circle = Circle.new(dxfattribs={"radius": -1})
assert circle.dxf.radius == -1, "Radius < 0 is valid"
def test_zero_radius():
circle = Circle.new(dxfattribs={"radius": 0})
assert circle.dxf.radius == 0, "Radius == 0 is valid"
def test_extrusion_can_not_be_a_null_vector():
circle = Circle.new(dxfattribs={"extrusion": (0, 0, 0)})
assert circle.dxf.extrusion == (0, 0, 1), "expected default extrusion"
def test_default_new():
entity = TEST_CLASS.new(
handle="ABBA",
owner="0",
dxfattribs={
"color": "7",
"center": (1, 2, 3),
"radius": 2.5,
},
)
assert entity.dxf.layer == "0"
assert entity.dxf.color == 7
assert entity.dxf.linetype == "BYLAYER"
assert entity.dxf.center == (1, 2, 3)
assert entity.dxf.center.x == 1, "is not Vec3 compatible"
assert entity.dxf.center.y == 2, "is not Vec3 compatible"
assert entity.dxf.center.z == 3, "is not Vec3 compatible"
assert entity.dxf.radius == 2.5
# can set DXF R2007 value
entity.dxf.shadow_mode = 1
assert entity.dxf.shadow_mode == 1
assert entity.dxf.extrusion == (0.0, 0.0, 1.0)
assert entity.dxf.hasattr("extrusion") is False, "just the default value"
def test_load_from_text(entity):
assert entity.dxf.layer == "0"
assert entity.dxf.color == 256, "default color is 256 (by layer)"
assert entity.dxf.center == (0, 0, 0)
assert entity.dxf.radius == 1
def test_get_point_2d_circle():
radius = 2.5
z = 3.0
circle = TEST_CLASS.new(
handle="ABBA",
owner="0",
dxfattribs={
"center": (1, 2, z),
"radius": radius,
},
)
vertices = list(circle.vertices([90]))
assert vertices[0].isclose(Vec3(1, 2 + radius, z))
def test_get_point_with_ocs():
circle = TEST_CLASS.new(
handle="ABBA",
owner="0",
dxfattribs={
"center": (1, 2, 3),
"radius": 2.5,
"extrusion": (0, 0, -1),
},
)
vertices = list(circle.vertices([90, 180]))
assert vertices[0].isclose(Vec3(-1, 4.5, -3), abs_tol=1e-6)
assert vertices[1].isclose(Vec3(1.5, 2, -3), abs_tol=1e-6)
@pytest.mark.parametrize(
"txt,ver", [(ENTITY_R2000, DXF2000), (ENTITY_R12, DXF12)]
)
def test_write_dxf(txt, ver):
expected = basic_tags_from_text(txt)
circle = TEST_CLASS.from_text(txt)
collector = TagCollector(dxfversion=ver, optional=True)
circle.export_dxf(collector)
assert collector.tags == expected
collector2 = TagCollector(dxfversion=ver, optional=False)
circle.export_dxf(collector2)
assert collector.has_all_tags(collector2)
def test_circle_default_ocs():
circle = Circle.new(dxfattribs={"center": (2, 3, 4), "thickness": 2})
# 1. rotation - 2. scaling - 3. translation
m = Matrix44.chain(Matrix44.scale(2, 2, 3), Matrix44.translate(1, 1, 1))
# default extrusion is (0, 0, 1), therefore scale(2, 2, ..) is a uniform
# scaling in the xy-play of the OCS
circle.transform(m)
assert circle.dxf.center == (5, 7, 13)
assert circle.dxf.extrusion == (0, 0, 1)
assert circle.dxf.thickness == 6
def test_circle_fast_translation():
circle = Circle.new(
dxfattribs={"center": (2, 3, 4), "extrusion": Vec3.random()}
)
ocs = circle.ocs()
offset = Vec3(1, 2, 3)
center = ocs.to_wcs(circle.dxf.center) + offset
circle.translate(*offset)
assert ocs.to_wcs(circle.dxf.center).isclose(center, abs_tol=1e-9)
def test_circle_non_uniform_scaling():
circle = Circle.new(
dxfattribs={"center": (2, 3, 4), "extrusion": (0, 1, 0), "thickness": 2}
)
# extrusion in WCS y-axis, therefore scale(2, ..., 3) is a non uniform
# scaling in the xy-play of the OCS which is the xz-plane of the WCS
with pytest.raises(NonUniformScalingError):
circle.transform(Matrix44.scale(2, 2, 3))
# source values unchanged after exception
assert circle.dxf.center == (2, 3, 4)
assert circle.dxf.extrusion == (0, 1, 0)
assert circle.dxf.thickness == 2
def test_circle_user_ocs():
center = (2, 3, 4)
extrusion = (0, 1, 0)
circle = Circle.new(
dxfattribs={"center": center, "extrusion": extrusion, "thickness": 2}
)
ocs = OCS(extrusion)
v = ocs.to_wcs(center) # (-2, 4, 3)
v = Vec3(v.x * 2, v.y * 4, v.z * 2)
v += (1, 1, 1)
# and back to OCS, extrusion is unchanged
result = ocs.from_wcs(v)
m = Matrix44.chain(Matrix44.scale(2, 4, 2), Matrix44.translate(1, 1, 1))
circle.transform(m)
assert circle.dxf.center == result
assert circle.dxf.extrusion == (0, 1, 0)
assert circle.dxf.thickness == 8 # in WCS y-axis
@pytest.mark.parametrize(
"radius, sagitta, count",
[
(1, 0.35, 5),
(1, 0.10, 8),
(0, 0.35, 0),
(0, 0.10, 0), # radius 0 works but yields nothing
(-1, 0.35, 5),
(-1, 0.10, 8), # negative radius same as positive radius
],
)
def test_circle_flattening(radius, sagitta, count):
circle = Circle.new(dxfattribs={"radius": radius})
assert len(list(circle.flattening(sagitta))) == count
MALFORMED_CIRCLE = """0
CIRCLE
5
0
62
7
330
0
6
LT_EZDXF
8
LY_EZDXF
100
AcDbCircle
10
1.0
20
2.0
30
3.0
100
AcDbEntity
40
2.0
"""
def test_load_malformed_circle():
circle = Circle.from_text(MALFORMED_CIRCLE)
assert circle.dxf.layer == "LY_EZDXF"
assert circle.dxf.linetype == "LT_EZDXF"
assert circle.dxf.color == 7
assert circle.dxf.center.isclose((1, 2, 3))
assert circle.dxf.radius == 2.0
|