femagtools 1.6.4__py3-none-any.whl → 1.6.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,359 @@
1
+ import logging
2
+ import numpy as np
3
+ from .shape import Circle, Arc, Line, Element
4
+ from .functions import distance
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ def polylines(entity, lf, rf, xoff=0.0, yoff=0.0, rotation=0.0):
9
+ """returns a collection of bulged vertices
10
+ http://www.afralisp.net/archive/lisp/Bulges1.htm
11
+ """
12
+ if isinstance(entity.points, list):
13
+ points = [(p[0], p[1]) for p in entity.points]
14
+ else:
15
+ points = [(p[0], p[1]) for p in entity.points()]
16
+ i = 0
17
+ if isinstance(entity.vertices, list):
18
+ vertices = entity.vertices
19
+ else:
20
+ vertices = entity.vertices()
21
+
22
+ for v in vertices:
23
+ if hasattr(v, 'bulge'):
24
+ b = v.bulge
25
+ else:
26
+ b = v.get_dxf_attrib('bulge', 0.0)
27
+ p1 = points[i]
28
+ try:
29
+ p2 = points[i+1]
30
+ except Exception:
31
+ if not entity.is_closed:
32
+ break
33
+ p2 = points[0]
34
+ if b != 0.0:
35
+ dx, dy = p2[0] - p1[0], p2[1] - p1[1]
36
+ c = np.sqrt(dx**2 + dy**2)
37
+ s = b * c/2
38
+ r = ((c/2)**2 + s**2)/2/s
39
+ g = np.arctan2(dx, dy)
40
+ a = 2*np.arctan(b)
41
+ pc = (p1[0] + r*np.sin(g - np.pi/2 + a),
42
+ p1[1] + r*np.cos(g - np.pi/2 + a))
43
+ if b < 0:
44
+ sa = np.arctan2(p2[1]-pc[1], p2[0]-pc[0])
45
+ ea = np.arctan2(p1[1]-pc[1], p1[0]-pc[0])
46
+ else:
47
+ sa = np.arctan2(p1[1]-pc[1], p1[0]-pc[0])
48
+ ea = np.arctan2(p2[1]-pc[1], p2[0]-pc[0])
49
+ logger.debug("Poly p1 %s p2 %s r %s", p1, p2, r)
50
+ yield Arc(Element(center=(pc[0], pc[1]),
51
+ radius=np.abs(r),
52
+ start_angle=sa/rf,
53
+ end_angle=ea/rf),
54
+ lf, rf,
55
+ xoff=xoff, yoff=yoff,
56
+ rotation=rotation)
57
+ else:
58
+ yield Line(Element(start=p1, end=p2), lf,
59
+ xoff=xoff, yoff=yoff,
60
+ rotation=rotation)
61
+ i += 1
62
+
63
+
64
+ def lw_polyline(entity, lf, xoff=0.0, yoff=0.0, rotation=0.0):
65
+ """returns a collection of bulged vertices
66
+ http://www.afralisp.net/archive/lisp/Bulges1.htm
67
+ """
68
+ if isinstance(entity.points, list):
69
+ points = [(lf*p[0], lf*p[1]) for p in entity.points]
70
+ else:
71
+ points = [(lf*p[0], lf*p[1]) for p in entity.points()]
72
+
73
+ if points:
74
+ p1 = points[0]
75
+ for p2 in points[1:]:
76
+ yield Line(Element(start=p1, end=p2), lf,
77
+ xoff=xoff, yoff=yoff,
78
+ rotation=rotation)
79
+ p1 = p2
80
+ if entity.is_closed:
81
+ yield Line(Element(start=p1, end=points[0]), lf,
82
+ xoff=xoff, yoff=yoff,
83
+ rotation=rotation)
84
+
85
+
86
+ def ellipse(entity, lf, xoff=0.0, yoff=0.0, rotation=0.0):
87
+ w = np.linalg.norm(entity.major_axis) * 2
88
+ h = entity.ratio * w
89
+ theta = np.arctan2(entity.major_axis[1], entity.major_axis[0])
90
+ start_angle = entity.start_param
91
+ end_angle = entity.end_param
92
+ if end_angle < start_angle:
93
+ end_angle += 2*np.pi
94
+ alfa = np.linspace(start_angle, end_angle, 20)
95
+ x = 0.5 * w * np.cos(alfa)
96
+ y = 0.5 * h * np.sin(alfa)
97
+ R = np.array([
98
+ [np.cos(theta), -np.sin(theta)],
99
+ [np.sin(theta), np.cos(theta)]
100
+ ])
101
+ x, y = np.dot(R, [x, y])
102
+ x += entity.center[0]
103
+ y += entity.center[1]
104
+ points = np.array((x, y)).T
105
+ p1 = points[0]
106
+ for p2 in points[1:]:
107
+ yield Line(Element(start=p1, end=p2), lf,
108
+ xoff=xoff, yoff=yoff,
109
+ rotation=rotation)
110
+ p1 = p2
111
+
112
+
113
+ def spline(entity, lf, min_dist=0.001, xoff=0.0, yoff=0.0, rotation=0.0):
114
+ if False:
115
+ yield Line(Element(start=entity.control_points[0],
116
+ end=entity.control_points[-1]), lf,
117
+ xoff=xoff, yoff=yoff,
118
+ rotation=rotation)
119
+ return
120
+
121
+ if False:
122
+ p_prev = None
123
+ for p in entity.control_points:
124
+ if p_prev:
125
+ yield Line(Element(start=p_prev, end=p), lf,
126
+ xoff=xoff, yoff=yoff,
127
+ rotation=rotation)
128
+ p_prev = p
129
+ return
130
+
131
+ points_between = entity.control_points[1:-1]
132
+ p1 = entity.control_points[0]
133
+ pe = entity.control_points[-1]
134
+ for p2 in points_between:
135
+ dist_12 = distance(p1, p2)
136
+ dist_2e = distance(p2, pe)
137
+ if dist_2e < min_dist:
138
+ logger.debug("SPLINE: ignor small end-distance %s", dist_2e)
139
+ yield Line(Element(start=p1, end=pe), lf,
140
+ xoff=xoff, yoff=yoff,
141
+ rotation=rotation)
142
+ return
143
+
144
+ if dist_12 > min_dist:
145
+ yield Line(Element(start=p1, end=p2), lf,
146
+ xoff=xoff, yoff=yoff,
147
+ rotation=rotation)
148
+ p1 = p2
149
+ else:
150
+ logger.debug("SPLINE: ignor small distance %s", dist_12)
151
+
152
+ yield Line(Element(start=p1, end=pe), lf,
153
+ xoff=xoff, yoff=yoff,
154
+ rotation=rotation)
155
+
156
+
157
+ def face3d(entity, lf):
158
+ logger.info("FACE3D: Points=%s", entity.points)
159
+ for i in range(len(entity.points)-1):
160
+ if not entity.is_edge_invisible(i):
161
+ ip = i+1 if i < 4 else 0
162
+ yield Line(Element(start=(entity.points[i][1],
163
+ entity.points[i][2]),
164
+ end=(entity.points[ip][1],
165
+ entity.points[ip][2])))
166
+
167
+
168
+ def insert_block(dwg, insert_entity, lf, rf, block, min_dist=0.001):
169
+ logger.debug('Insert %s entities from block %s',
170
+ len(block),
171
+ insert_entity.name)
172
+ logger.debug('Insert = %s', insert_entity.insert)
173
+ logger.debug('Rotation = %s', insert_entity.rotation)
174
+ logger.debug('Scale = %s', insert_entity.scale)
175
+ logger.debug('Rows = %s', insert_entity.row_count)
176
+ logger.debug('Cols = %s', insert_entity.col_count)
177
+ logger.debug('Row spacing = %s', insert_entity.row_spacing)
178
+ logger.debug('Col spacing = %s', insert_entity.col_spacing)
179
+
180
+ if insert_entity.insert != (0.0, 0.0, 0.0):
181
+ logger.debug('Different Location in Insert')
182
+
183
+ xoff = insert_entity.insert[0]
184
+ yoff = insert_entity.insert[1]
185
+
186
+ scale = (round(insert_entity.scale[0], 8),
187
+ round(insert_entity.scale[1], 8),
188
+ round(insert_entity.scale[2], 8))
189
+ if not (scale == (1.0, 1.0, 1.0) or
190
+ scale == (1.0, 1.0, 0.0)):
191
+ logger.error('Block scaling in Insert not supported')
192
+ logger.error(' scale = {}'.format(scale))
193
+ return
194
+
195
+ if(insert_entity.row_count > 1 or
196
+ insert_entity.col_count > 1 or
197
+ insert_entity.row_spacing > 0 or
198
+ insert_entity.col_spacing > 0):
199
+ logger.error('Multi Block references in Insert not supported')
200
+ return
201
+
202
+ for e in block:
203
+ if e.dxftype == 'ARC':
204
+ logger.debug("Block Arc")
205
+ yield Arc(e, lf, rf,
206
+ xoff=xoff, yoff=yoff,
207
+ rotation=insert_entity.rotation)
208
+ elif e.dxftype == 'CIRCLE':
209
+ logger.debug("Block Circle %s, Radius %f", e.center[:2], e.radius)
210
+ yield Circle(e, lf,
211
+ xoff=xoff, yoff=yoff,
212
+ rotation=insert_entity.rotation)
213
+ elif e.dxftype == 'LINE':
214
+ logger.debug("Block Line")
215
+ yield Line(e, lf,
216
+ xoff=xoff, yoff=yoff,
217
+ rotation=insert_entity.rotation)
218
+ elif e.dxftype == 'POLYLINE':
219
+ logger.debug("Block Polyline")
220
+ for p in polylines(e, lf, rf,
221
+ xoff=xoff, yoff=yoff,
222
+ rotation=insert_entity.rotation):
223
+ yield p
224
+ elif e.dxftype == 'LWPOLYLINE':
225
+ logger.debug("Block lwPolyline")
226
+ for p in lw_polyline(e, lf,
227
+ xoff=xoff, yoff=yoff,
228
+ rotation=insert_entity.rotation):
229
+ yield p
230
+ elif e.dxftype == 'SPLINE':
231
+ logger.debug("Block spline")
232
+ for l in spline(e, lf,
233
+ min_dist=min_dist,
234
+ xoff=xoff, yoff=yoff,
235
+ rotation=insert_entity.rotation):
236
+ yield l
237
+ elif e.dxftype == 'INSERT':
238
+ logger.debug("Nested Insert of Block %s", e.name)
239
+ block = dwg.blocks[e.name]
240
+ for l in insert_block(dwg, e, lf, rf, block, min_dist=min_dist):
241
+ yield l
242
+
243
+ else:
244
+ logger.warn("unknown type %s in block %s",
245
+ e.dxftype, insert_entity.name)
246
+
247
+
248
+ def dxfshapes0(dxffile, mindist=0.01, layers=[]):
249
+ """returns a collection of dxf entities (ezdxf)"""
250
+ import ezdxf
251
+ dwg = ezdxf.readfile(dxffile)
252
+ id = 0
253
+ # $ACADVER: AC1006 = R10, AC1009 = R11 and R12, AC1012 = R13,
254
+ # AC1014 = R14 AC1015 = Release 2000/0i/2
255
+ # check units:
256
+ # dwg.header['$ANGDIR'] 1 = Clockwise angles, 0 = Counterclockwise
257
+ # dwg.header['$AUNITS'] 0 Decimal Degrees, 1 Deg/Min/Sec, 2 Grads, 3 Radians
258
+ # dwg.header['$INSUNIT'] 1 = Inches; 2 = Feet; 3 = Miles;
259
+ # 4 = Millimeters; 5 = Centimeters; 6 = Meters
260
+ # dwg.header['$LUNITS']
261
+ for e in dwg.modelspace():
262
+ if e.dxftype() == 'ARC':
263
+ yield Arc(e.dxf)
264
+ elif e.dxftype() == 'CIRCLE':
265
+ logger.debug("Circle %s, Radius %f", e.center[:2], e.radius)
266
+ yield Circle(e.dxf)
267
+ elif e.dxftype() == 'LINE':
268
+ yield Line(e.dxf)
269
+ elif e.dxftype() == 'POLYLINE':
270
+ for p in polylines(e):
271
+ yield p
272
+ elif e.dxftype() == 'SPLINE':
273
+ for l in spline(e, 1.0, in_dist=mindist):
274
+ yield l
275
+ elif e.dxftype() == 'POINT':
276
+ logger.debug("Id %d4: type %s ignored", id, e.dxftype)
277
+ else:
278
+ logger.warning("Id %d4: unknown type %s", id, e.dxftype)
279
+ id += 1
280
+
281
+
282
+ def dxfshapes(dxffile, mindist=0.01, layers=[]):
283
+ """returns a collection of dxf entities (dxfgrabber)"""
284
+ import dxfgrabber
285
+ dwg = dxfgrabber.readfile(dxffile)
286
+ # print("Layers = {}".format(dwg.layers.names()))
287
+ id = 0
288
+ # $ACADVER: AC1006 = R10, AC1009 = R11 and R12, AC1012 = R13,
289
+ # AC1014 = R14 AC1015 = Release 2000/0i/2
290
+ # check units:
291
+ # dwg.header['$ANGDIR'] 1 = Clockwise angles, 0 = Counterclockwise
292
+ # dwg.header['$AUNITS'] Decimal Degrees, Deg/Min/Sec, Grads, Radians
293
+ # dwg.header['$INSUNIT'] 1 = Inches; 2 = Feet; 3 = Miles;
294
+ # 4 = Millimeters; 5 = Centimeters; 6 = Meters
295
+ # dwg.header['$LUNITS']
296
+ lf = 1
297
+ if dwg.header.get('$LUNITS', 0) == 1:
298
+ # conv = [1, 2.54e-2, 10.12, 633.0, 1e-3, 1e-2, 1]
299
+ lf = 2.54e3
300
+
301
+ rf = np.pi/180
302
+ if dwg.header.get('$AUNITS', 0) == 4:
303
+ rf = 1
304
+
305
+ for e in dwg.modelspace():
306
+ if not layers or e.layer in layers:
307
+ if e.dxftype == 'ARC':
308
+ yield Arc(e, lf, rf)
309
+ elif e.dxftype == 'CIRCLE':
310
+ logger.debug("Circle %s, Radius %f", e.center[:2], e.radius)
311
+ yield Circle(e, lf)
312
+ elif e.dxftype == 'LINE':
313
+ yield Line(e, lf)
314
+ elif e.dxftype == 'POLYLINE':
315
+ for p in polylines(e, lf, rf):
316
+ yield p
317
+ elif e.dxftype == 'LWPOLYLINE':
318
+ for p in lw_polyline(e, lf):
319
+ yield p
320
+ elif e.dxftype == 'SPLINE':
321
+ for l in spline(e, lf, min_dist=mindist):
322
+ yield l
323
+ elif e.dxftype == 'INSERT':
324
+ logger.debug("Insert of Block %s", e.name)
325
+ block = dwg.blocks[e.name]
326
+ for l in insert_block(dwg, e, lf, rf, block, min_dist=mindist):
327
+ yield l
328
+ elif e.dxftype == 'ELLIPSE':
329
+ for l in ellipse(e, lf):
330
+ yield l
331
+ #w = np.linalg.norm(e.major_axis) * 2
332
+ #h = e.ratio * w
333
+ #rtheta = np.arctan2(e.major_axis[1], e.major_axis[0])
334
+ #angle = rtheta*180/np.pi
335
+ #start_angle = e.start_param*180/np.pi + angle
336
+ #end_angle = e.end_param*180/np.pi + angle
337
+ #if end_angle < start_angle:
338
+ # end_angle += 360
339
+ #arc = Arc(Element(center=e.center,
340
+ # radius=w/2,
341
+ # start_angle=start_angle,
342
+ # end_angle=end_angle,
343
+ # width=w,
344
+ # height=h,
345
+ # rtheta=rtheta,
346
+ # start_param=e.start_param,
347
+ # end_param=e.end_param))
348
+ #yield arc
349
+
350
+ elif e.dxftype == 'POINT':
351
+ logger.debug("Id %d4: type %s ignored", id, e.dxftype)
352
+ elif e.dxftype == '3DFACE':
353
+ logger.warning(
354
+ "Id %d4: type %s not implemented", id, e.dxftype)
355
+ # for l in face3d(e, lf):
356
+ # yield l
357
+ else:
358
+ logger.warning("Id %d4: unknown type %s", id, e.dxftype)
359
+ id += 1
@@ -0,0 +1,78 @@
1
+ """
2
+ Geom Parser for femm files
3
+ """
4
+
5
+ import numpy as np
6
+ from .shape import Arc, Line, Element
7
+ from .functions import distance, alpha_line, points_are_close
8
+
9
+ fem_points = []
10
+
11
+
12
+ def read_fem_points(f, num):
13
+ for x in range(num):
14
+ p = f.readline().split()
15
+ fem_points.append([float(p[0]), float(p[1])])
16
+
17
+
18
+ def read_fem_lines(f, num):
19
+ for x in range(num):
20
+ p = f.readline().split()
21
+ i1 = int(p[0])
22
+ i2 = int(p[1])
23
+ p1 = fem_points[i1]
24
+ p2 = fem_points[i2]
25
+ if points_are_close(p1, p2):
26
+ logger.warning("FEMM: Line with points close together")
27
+ logger.warning(" p1 = %s, p2 =%s", p1, p2)
28
+ yield Line(Element(start=p1, end=p2))
29
+
30
+
31
+ def read_fem_arcs(f, num):
32
+ for x in range(num):
33
+ p = f.readline().split()
34
+ i1 = int(p[0])
35
+ i2 = int(p[1])
36
+ alpha = float(p[2])
37
+ p1 = fem_points[i1]
38
+ p2 = fem_points[i2]
39
+ if points_are_close(p1, p2):
40
+ logger.warning("FEMM: Arc with points close together")
41
+ logger.warning(" p1 = %s, p2 = %s", p1, p2)
42
+ for e in get_fem_arc(p1, p2, alpha):
43
+ yield e
44
+
45
+
46
+ def get_fem_arc(pA, pB, alfa):
47
+ alpha = alfa/180.0*np.pi/2.0
48
+ y = distance(pA, pB) / 2.0
49
+ x = y / np.tan(alpha)
50
+ r = np.sqrt(x**2 + y**2)
51
+
52
+ delta = alpha_line(pA, pB)
53
+
54
+ c = [pA[0] + y, pA[1] + x]
55
+ phi = alpha_line(pA, c) + delta
56
+ pC = point_on_arc(pA, r, phi)
57
+
58
+ startangle = alpha_line(pC, pA)
59
+ endangle = alpha_line(pC, pB)
60
+ yield Arc(Element(center=pC,
61
+ radius=r,
62
+ start_angle=startangle*180/np.pi,
63
+ end_angle=endangle*180/np.pi))
64
+
65
+
66
+ def femshapes(femfile):
67
+ f = open(femfile, 'r')
68
+
69
+ for data in f:
70
+ text = data.split()
71
+ if text[0] == '[NumPoints]':
72
+ read_fem_points(f, int(text[2]))
73
+ elif text[0] == '[NumSegments]':
74
+ for e in read_fem_lines(f, int(text[2])):
75
+ yield e
76
+ elif text[0] == '[NumArcSegments]':
77
+ for e in read_fem_arcs(f, int(text[2])):
78
+ yield e