femagtools 1.6.5__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.
- femagtools/__init__.py +1 -1
- femagtools/dxfsl/area.py +24 -4
- femagtools/dxfsl/areabuilder.py +152 -5
- femagtools/dxfsl/concat.py +7 -7
- femagtools/dxfsl/converter.py +20 -7
- femagtools/dxfsl/dxfparser.py +359 -0
- femagtools/dxfsl/femparser.py +78 -0
- femagtools/dxfsl/geom.py +14 -426
- femagtools/dxfsl/journal.py +15 -23
- femagtools/dxfsl/shape.py +1 -1
- femagtools/dxfsl/svgparser.py +90 -0
- femagtools/dxfsl/symmetry.py +183 -74
- femagtools/isa7.py +6 -5
- femagtools/machine/effloss.py +1 -1
- femagtools/machine/im.py +2 -1
- femagtools/machine/pm.py +71 -12
- femagtools/machine/sm.py +4 -2
- femagtools/plot/nc.py +3 -3
- femagtools/svgfsl/converter.py +74 -0
- {femagtools-1.6.5.dist-info → femagtools-1.6.6.dist-info}/METADATA +5 -1
- {femagtools-1.6.5.dist-info → femagtools-1.6.6.dist-info}/RECORD +26 -21
- {femagtools-1.6.5.dist-info → femagtools-1.6.6.dist-info}/entry_points.txt +1 -0
- tests/test_dxfsl.py +12 -0
- {femagtools-1.6.5.dist-info → femagtools-1.6.6.dist-info}/LICENSE +0 -0
- {femagtools-1.6.5.dist-info → femagtools-1.6.6.dist-info}/WHEEL +0 -0
- {femagtools-1.6.5.dist-info → femagtools-1.6.6.dist-info}/top_level.txt +0 -0
femagtools/dxfsl/geom.py
CHANGED
@@ -19,6 +19,7 @@ from .area import Area
|
|
19
19
|
from .shape import Element, Shape, Circle, Arc, Line, Point
|
20
20
|
from .shape import is_Circle, is_Arc, is_Line
|
21
21
|
from .machine import Machine
|
22
|
+
from femagtools.dxfsl.areabuilder import AreaBuilder
|
22
23
|
from .functions import less_equal, less, greater, greater_equal
|
23
24
|
from .functions import distance, alpha_line, alpha_points, alpha_angle
|
24
25
|
from .functions import point, points_are_close, is_point_inside_region
|
@@ -251,432 +252,6 @@ def intersect(a, b):
|
|
251
252
|
ccw(b.p1, b.p2, a.p1) != ccw(b.p1, b.p2, a.p2)
|
252
253
|
|
253
254
|
|
254
|
-
def polylines(entity, lf, rf, xoff=0.0, yoff=0.0, rotation=0.0):
|
255
|
-
"""returns a collection of bulged vertices
|
256
|
-
http://www.afralisp.net/archive/lisp/Bulges1.htm
|
257
|
-
"""
|
258
|
-
if isinstance(entity.points, list):
|
259
|
-
points = [(p[0], p[1]) for p in entity.points]
|
260
|
-
else:
|
261
|
-
points = [(p[0], p[1]) for p in entity.points()]
|
262
|
-
i = 0
|
263
|
-
if isinstance(entity.vertices, list):
|
264
|
-
vertices = entity.vertices
|
265
|
-
else:
|
266
|
-
vertices = entity.vertices()
|
267
|
-
|
268
|
-
for v in vertices:
|
269
|
-
if hasattr(v, 'bulge'):
|
270
|
-
b = v.bulge
|
271
|
-
else:
|
272
|
-
b = v.get_dxf_attrib('bulge', 0.0)
|
273
|
-
p1 = points[i]
|
274
|
-
try:
|
275
|
-
p2 = points[i+1]
|
276
|
-
except Exception:
|
277
|
-
if not entity.is_closed:
|
278
|
-
break
|
279
|
-
p2 = points[0]
|
280
|
-
if b != 0.0:
|
281
|
-
dx, dy = p2[0] - p1[0], p2[1] - p1[1]
|
282
|
-
c = np.sqrt(dx**2 + dy**2)
|
283
|
-
s = b * c/2
|
284
|
-
r = ((c/2)**2 + s**2)/2/s
|
285
|
-
g = np.arctan2(dx, dy)
|
286
|
-
a = 2*np.arctan(b)
|
287
|
-
pc = (p1[0] + r*np.sin(g - np.pi/2 + a),
|
288
|
-
p1[1] + r*np.cos(g - np.pi/2 + a))
|
289
|
-
if b < 0:
|
290
|
-
sa = np.arctan2(p2[1]-pc[1], p2[0]-pc[0])
|
291
|
-
ea = np.arctan2(p1[1]-pc[1], p1[0]-pc[0])
|
292
|
-
else:
|
293
|
-
sa = np.arctan2(p1[1]-pc[1], p1[0]-pc[0])
|
294
|
-
ea = np.arctan2(p2[1]-pc[1], p2[0]-pc[0])
|
295
|
-
logger.debug("Poly p1 %s p2 %s r %s", p1, p2, r)
|
296
|
-
yield Arc(Element(center=(pc[0], pc[1]),
|
297
|
-
radius=np.abs(r),
|
298
|
-
start_angle=sa/rf,
|
299
|
-
end_angle=ea/rf),
|
300
|
-
lf, rf,
|
301
|
-
xoff=xoff, yoff=yoff,
|
302
|
-
rotation=rotation)
|
303
|
-
else:
|
304
|
-
yield Line(Element(start=p1, end=p2), lf,
|
305
|
-
xoff=xoff, yoff=yoff,
|
306
|
-
rotation=rotation)
|
307
|
-
i += 1
|
308
|
-
|
309
|
-
|
310
|
-
def lw_polyline(entity, lf, xoff=0.0, yoff=0.0, rotation=0.0):
|
311
|
-
"""returns a collection of bulged vertices
|
312
|
-
http://www.afralisp.net/archive/lisp/Bulges1.htm
|
313
|
-
"""
|
314
|
-
if isinstance(entity.points, list):
|
315
|
-
points = [(lf*p[0], lf*p[1]) for p in entity.points]
|
316
|
-
else:
|
317
|
-
points = [(lf*p[0], lf*p[1]) for p in entity.points()]
|
318
|
-
|
319
|
-
if points:
|
320
|
-
p1 = points[0]
|
321
|
-
for p2 in points[1:]:
|
322
|
-
yield Line(Element(start=p1, end=p2), lf,
|
323
|
-
xoff=xoff, yoff=yoff,
|
324
|
-
rotation=rotation)
|
325
|
-
p1 = p2
|
326
|
-
if entity.is_closed:
|
327
|
-
yield Line(Element(start=p1, end=points[0]), lf,
|
328
|
-
xoff=xoff, yoff=yoff,
|
329
|
-
rotation=rotation)
|
330
|
-
|
331
|
-
|
332
|
-
def ellipse(entity, lf, xoff=0.0, yoff=0.0, rotation=0.0):
|
333
|
-
w = np.linalg.norm(entity.major_axis) * 2
|
334
|
-
h = entity.ratio * w
|
335
|
-
theta = np.arctan2(entity.major_axis[1], entity.major_axis[0])
|
336
|
-
start_angle = entity.start_param
|
337
|
-
end_angle = entity.end_param
|
338
|
-
if end_angle < start_angle:
|
339
|
-
end_angle += 2*np.pi
|
340
|
-
alfa = np.linspace(start_angle, end_angle, 20)
|
341
|
-
x = 0.5 * w * np.cos(alfa)
|
342
|
-
y = 0.5 * h * np.sin(alfa)
|
343
|
-
R = np.array([
|
344
|
-
[np.cos(theta), -np.sin(theta)],
|
345
|
-
[np.sin(theta), np.cos(theta)]
|
346
|
-
])
|
347
|
-
x, y = np.dot(R, [x, y])
|
348
|
-
x += entity.center[0]
|
349
|
-
y += entity.center[1]
|
350
|
-
points = np.array((x, y)).T
|
351
|
-
p1 = points[0]
|
352
|
-
for p2 in points[1:]:
|
353
|
-
yield Line(Element(start=p1, end=p2), lf,
|
354
|
-
xoff=xoff, yoff=yoff,
|
355
|
-
rotation=rotation)
|
356
|
-
p1 = p2
|
357
|
-
|
358
|
-
|
359
|
-
def spline(entity, lf, min_dist=0.001, xoff=0.0, yoff=0.0, rotation=0.0):
|
360
|
-
if False:
|
361
|
-
yield Line(Element(start=entity.control_points[0],
|
362
|
-
end=entity.control_points[-1]), lf,
|
363
|
-
xoff=xoff, yoff=yoff,
|
364
|
-
rotation=rotation)
|
365
|
-
return
|
366
|
-
|
367
|
-
if False:
|
368
|
-
p_prev = None
|
369
|
-
for p in entity.control_points:
|
370
|
-
if p_prev:
|
371
|
-
yield Line(Element(start=p_prev, end=p), lf,
|
372
|
-
xoff=xoff, yoff=yoff,
|
373
|
-
rotation=rotation)
|
374
|
-
p_prev = p
|
375
|
-
return
|
376
|
-
|
377
|
-
points_between = entity.control_points[1:-1]
|
378
|
-
p1 = entity.control_points[0]
|
379
|
-
pe = entity.control_points[-1]
|
380
|
-
for p2 in points_between:
|
381
|
-
dist_12 = distance(p1, p2)
|
382
|
-
dist_2e = distance(p2, pe)
|
383
|
-
if dist_2e < min_dist:
|
384
|
-
logger.debug("SPLINE: ignor small end-distance %s", dist_2e)
|
385
|
-
yield Line(Element(start=p1, end=pe), lf,
|
386
|
-
xoff=xoff, yoff=yoff,
|
387
|
-
rotation=rotation)
|
388
|
-
return
|
389
|
-
|
390
|
-
if dist_12 > min_dist:
|
391
|
-
yield Line(Element(start=p1, end=p2), lf,
|
392
|
-
xoff=xoff, yoff=yoff,
|
393
|
-
rotation=rotation)
|
394
|
-
p1 = p2
|
395
|
-
else:
|
396
|
-
logger.debug("SPLINE: ignor small distance %s", dist_12)
|
397
|
-
|
398
|
-
yield Line(Element(start=p1, end=pe), lf,
|
399
|
-
xoff=xoff, yoff=yoff,
|
400
|
-
rotation=rotation)
|
401
|
-
|
402
|
-
|
403
|
-
def face3d(entity, lf):
|
404
|
-
logger.info("FACE3D: Points=%s", entity.points)
|
405
|
-
for i in range(len(entity.points)-1):
|
406
|
-
if not entity.is_edge_invisible(i):
|
407
|
-
ip = i+1 if i < 4 else 0
|
408
|
-
yield Line(Element(start=(entity.points[i][1],
|
409
|
-
entity.points[i][2]),
|
410
|
-
end=(entity.points[ip][1],
|
411
|
-
entity.points[ip][2])))
|
412
|
-
|
413
|
-
|
414
|
-
def insert_block(dwg, insert_entity, lf, rf, block, min_dist=0.001):
|
415
|
-
logger.debug('Insert %s entities from block %s',
|
416
|
-
len(block),
|
417
|
-
insert_entity.name)
|
418
|
-
logger.debug('Insert = %s', insert_entity.insert)
|
419
|
-
logger.debug('Rotation = %s', insert_entity.rotation)
|
420
|
-
logger.debug('Scale = %s', insert_entity.scale)
|
421
|
-
logger.debug('Rows = %s', insert_entity.row_count)
|
422
|
-
logger.debug('Cols = %s', insert_entity.col_count)
|
423
|
-
logger.debug('Row spacing = %s', insert_entity.row_spacing)
|
424
|
-
logger.debug('Col spacing = %s', insert_entity.col_spacing)
|
425
|
-
|
426
|
-
if insert_entity.insert != (0.0, 0.0, 0.0):
|
427
|
-
logger.debug('Different Location in Insert')
|
428
|
-
|
429
|
-
xoff = insert_entity.insert[0]
|
430
|
-
yoff = insert_entity.insert[1]
|
431
|
-
|
432
|
-
scale = (round(insert_entity.scale[0], 8),
|
433
|
-
round(insert_entity.scale[1], 8),
|
434
|
-
round(insert_entity.scale[2], 8))
|
435
|
-
if not (scale == (1.0, 1.0, 1.0) or
|
436
|
-
scale == (1.0, 1.0, 0.0)):
|
437
|
-
logger.error('Block scaling in Insert not supported')
|
438
|
-
logger.error(' scale = {}'.format(scale))
|
439
|
-
return
|
440
|
-
|
441
|
-
if(insert_entity.row_count > 1 or
|
442
|
-
insert_entity.col_count > 1 or
|
443
|
-
insert_entity.row_spacing > 0 or
|
444
|
-
insert_entity.col_spacing > 0):
|
445
|
-
logger.error('Multi Block references in Insert not supported')
|
446
|
-
return
|
447
|
-
|
448
|
-
for e in block:
|
449
|
-
if e.dxftype == 'ARC':
|
450
|
-
logger.debug("Block Arc")
|
451
|
-
yield Arc(e, lf, rf,
|
452
|
-
xoff=xoff, yoff=yoff,
|
453
|
-
rotation=insert_entity.rotation)
|
454
|
-
elif e.dxftype == 'CIRCLE':
|
455
|
-
logger.debug("Block Circle %s, Radius %f", e.center[:2], e.radius)
|
456
|
-
yield Circle(e, lf,
|
457
|
-
xoff=xoff, yoff=yoff,
|
458
|
-
rotation=insert_entity.rotation)
|
459
|
-
elif e.dxftype == 'LINE':
|
460
|
-
logger.debug("Block Line")
|
461
|
-
yield Line(e, lf,
|
462
|
-
xoff=xoff, yoff=yoff,
|
463
|
-
rotation=insert_entity.rotation)
|
464
|
-
elif e.dxftype == 'POLYLINE':
|
465
|
-
logger.debug("Block Polyline")
|
466
|
-
for p in polylines(e, lf, rf,
|
467
|
-
xoff=xoff, yoff=yoff,
|
468
|
-
rotation=insert_entity.rotation):
|
469
|
-
yield p
|
470
|
-
elif e.dxftype == 'LWPOLYLINE':
|
471
|
-
logger.debug("Block lwPolyline")
|
472
|
-
for p in lw_polyline(e, lf,
|
473
|
-
xoff=xoff, yoff=yoff,
|
474
|
-
rotation=insert_entity.rotation):
|
475
|
-
yield p
|
476
|
-
elif e.dxftype == 'SPLINE':
|
477
|
-
logger.debug("Block spline")
|
478
|
-
for l in spline(e, lf,
|
479
|
-
min_dist=min_dist,
|
480
|
-
xoff=xoff, yoff=yoff,
|
481
|
-
rotation=insert_entity.rotation):
|
482
|
-
yield l
|
483
|
-
elif e.dxftype == 'INSERT':
|
484
|
-
logger.debug("Nested Insert of Block %s", e.name)
|
485
|
-
block = dwg.blocks[e.name]
|
486
|
-
for l in insert_block(dwg, e, lf, rf, block, min_dist=min_dist):
|
487
|
-
yield l
|
488
|
-
|
489
|
-
else:
|
490
|
-
logger.warn("unknown type %s in block %s",
|
491
|
-
e.dxftype, insert_entity.name)
|
492
|
-
|
493
|
-
|
494
|
-
def dxfshapes0(dxffile, mindist=0.01, layers=[]):
|
495
|
-
"""returns a collection of dxf entities (ezdxf)"""
|
496
|
-
import ezdxf
|
497
|
-
dwg = ezdxf.readfile(dxffile)
|
498
|
-
id = 0
|
499
|
-
# $ACADVER: AC1006 = R10, AC1009 = R11 and R12, AC1012 = R13,
|
500
|
-
# AC1014 = R14 AC1015 = Release 2000/0i/2
|
501
|
-
# check units:
|
502
|
-
# dwg.header['$ANGDIR'] 1 = Clockwise angles, 0 = Counterclockwise
|
503
|
-
# dwg.header['$AUNITS'] 0 Decimal Degrees, 1 Deg/Min/Sec, 2 Grads, 3 Radians
|
504
|
-
# dwg.header['$INSUNIT'] 1 = Inches; 2 = Feet; 3 = Miles;
|
505
|
-
# 4 = Millimeters; 5 = Centimeters; 6 = Meters
|
506
|
-
# dwg.header['$LUNITS']
|
507
|
-
for e in dwg.modelspace():
|
508
|
-
if e.dxftype() == 'ARC':
|
509
|
-
yield Arc(e.dxf)
|
510
|
-
elif e.dxftype() == 'CIRCLE':
|
511
|
-
logger.debug("Circle %s, Radius %f", e.center[:2], e.radius)
|
512
|
-
yield Circle(e.dxf)
|
513
|
-
elif e.dxftype() == 'LINE':
|
514
|
-
yield Line(e.dxf)
|
515
|
-
elif e.dxftype() == 'POLYLINE':
|
516
|
-
for p in polylines(e):
|
517
|
-
yield p
|
518
|
-
elif e.dxftype() == 'SPLINE':
|
519
|
-
for l in spline(e, 1.0, in_dist=mindist):
|
520
|
-
yield l
|
521
|
-
elif e.dxftype() == 'POINT':
|
522
|
-
logger.debug("Id %d4: type %s ignored", id, e.dxftype)
|
523
|
-
else:
|
524
|
-
logger.warning("Id %d4: unknown type %s", id, e.dxftype)
|
525
|
-
id += 1
|
526
|
-
|
527
|
-
|
528
|
-
def dxfshapes(dxffile, mindist=0.01, layers=[]):
|
529
|
-
"""returns a collection of dxf entities (dxfgrabber)"""
|
530
|
-
import dxfgrabber
|
531
|
-
dwg = dxfgrabber.readfile(dxffile)
|
532
|
-
# print("Layers = {}".format(dwg.layers.names()))
|
533
|
-
id = 0
|
534
|
-
# $ACADVER: AC1006 = R10, AC1009 = R11 and R12, AC1012 = R13,
|
535
|
-
# AC1014 = R14 AC1015 = Release 2000/0i/2
|
536
|
-
# check units:
|
537
|
-
# dwg.header['$ANGDIR'] 1 = Clockwise angles, 0 = Counterclockwise
|
538
|
-
# dwg.header['$AUNITS'] Decimal Degrees, Deg/Min/Sec, Grads, Radians
|
539
|
-
# dwg.header['$INSUNIT'] 1 = Inches; 2 = Feet; 3 = Miles;
|
540
|
-
# 4 = Millimeters; 5 = Centimeters; 6 = Meters
|
541
|
-
# dwg.header['$LUNITS']
|
542
|
-
lf = 1
|
543
|
-
if dwg.header.get('$LUNITS', 0) == 1:
|
544
|
-
# conv = [1, 2.54e-2, 10.12, 633.0, 1e-3, 1e-2, 1]
|
545
|
-
lf = 2.54e3
|
546
|
-
|
547
|
-
rf = np.pi/180
|
548
|
-
if dwg.header.get('$AUNITS', 0) == 4:
|
549
|
-
rf = 1
|
550
|
-
|
551
|
-
for e in dwg.modelspace():
|
552
|
-
if not layers or e.layer in layers:
|
553
|
-
if e.dxftype == 'ARC':
|
554
|
-
yield Arc(e, lf, rf)
|
555
|
-
elif e.dxftype == 'CIRCLE':
|
556
|
-
logger.debug("Circle %s, Radius %f", e.center[:2], e.radius)
|
557
|
-
yield Circle(e, lf)
|
558
|
-
elif e.dxftype == 'LINE':
|
559
|
-
yield Line(e, lf)
|
560
|
-
elif e.dxftype == 'POLYLINE':
|
561
|
-
for p in polylines(e, lf, rf):
|
562
|
-
yield p
|
563
|
-
elif e.dxftype == 'LWPOLYLINE':
|
564
|
-
for p in lw_polyline(e, lf):
|
565
|
-
yield p
|
566
|
-
elif e.dxftype == 'SPLINE':
|
567
|
-
for l in spline(e, lf, min_dist=mindist):
|
568
|
-
yield l
|
569
|
-
elif e.dxftype == 'INSERT':
|
570
|
-
logger.debug("Insert of Block %s", e.name)
|
571
|
-
block = dwg.blocks[e.name]
|
572
|
-
for l in insert_block(dwg, e, lf, rf, block, min_dist=mindist):
|
573
|
-
yield l
|
574
|
-
elif e.dxftype == 'ELLIPSE':
|
575
|
-
for l in ellipse(e, lf):
|
576
|
-
yield l
|
577
|
-
#w = np.linalg.norm(e.major_axis) * 2
|
578
|
-
#h = e.ratio * w
|
579
|
-
#rtheta = np.arctan2(e.major_axis[1], e.major_axis[0])
|
580
|
-
#angle = rtheta*180/np.pi
|
581
|
-
#start_angle = e.start_param*180/np.pi + angle
|
582
|
-
#end_angle = e.end_param*180/np.pi + angle
|
583
|
-
#if end_angle < start_angle:
|
584
|
-
# end_angle += 360
|
585
|
-
#arc = Arc(Element(center=e.center,
|
586
|
-
# radius=w/2,
|
587
|
-
# start_angle=start_angle,
|
588
|
-
# end_angle=end_angle,
|
589
|
-
# width=w,
|
590
|
-
# height=h,
|
591
|
-
# rtheta=rtheta,
|
592
|
-
# start_param=e.start_param,
|
593
|
-
# end_param=e.end_param))
|
594
|
-
#yield arc
|
595
|
-
|
596
|
-
elif e.dxftype == 'POINT':
|
597
|
-
logger.debug("Id %d4: type %s ignored", id, e.dxftype)
|
598
|
-
elif e.dxftype == '3DFACE':
|
599
|
-
logger.warning(
|
600
|
-
"Id %d4: type %s not implemented", id, e.dxftype)
|
601
|
-
# for l in face3d(e, lf):
|
602
|
-
# yield l
|
603
|
-
else:
|
604
|
-
logger.warning("Id %d4: unknown type %s", id, e.dxftype)
|
605
|
-
id += 1
|
606
|
-
|
607
|
-
|
608
|
-
fem_points = []
|
609
|
-
|
610
|
-
|
611
|
-
def read_fem_points(f, num):
|
612
|
-
for x in range(num):
|
613
|
-
p = f.readline().split()
|
614
|
-
fem_points.append([float(p[0]), float(p[1])])
|
615
|
-
|
616
|
-
|
617
|
-
def read_fem_lines(f, num):
|
618
|
-
for x in range(num):
|
619
|
-
p = f.readline().split()
|
620
|
-
i1 = int(p[0])
|
621
|
-
i2 = int(p[1])
|
622
|
-
p1 = fem_points[i1]
|
623
|
-
p2 = fem_points[i2]
|
624
|
-
if points_are_close(p1, p2):
|
625
|
-
logger.warning("FEMM: Line with points close together")
|
626
|
-
logger.warning(" p1 = %s, p2 =%s", p1, p2)
|
627
|
-
yield Line(Element(start=p1, end=p2))
|
628
|
-
|
629
|
-
|
630
|
-
def read_fem_arcs(f, num):
|
631
|
-
for x in range(num):
|
632
|
-
p = f.readline().split()
|
633
|
-
i1 = int(p[0])
|
634
|
-
i2 = int(p[1])
|
635
|
-
alpha = float(p[2])
|
636
|
-
p1 = fem_points[i1]
|
637
|
-
p2 = fem_points[i2]
|
638
|
-
if points_are_close(p1, p2):
|
639
|
-
logger.warning("FEMM: Arc with points close together")
|
640
|
-
logger.warning(" p1 = %s, p2 = %s", p1, p2)
|
641
|
-
for e in get_fem_arc(p1, p2, alpha):
|
642
|
-
yield e
|
643
|
-
|
644
|
-
|
645
|
-
def get_fem_arc(pA, pB, alfa):
|
646
|
-
alpha = alfa/180.0*np.pi/2.0
|
647
|
-
y = distance(pA, pB) / 2.0
|
648
|
-
x = y / np.tan(alpha)
|
649
|
-
r = np.sqrt(x**2 + y**2)
|
650
|
-
|
651
|
-
delta = alpha_line(pA, pB)
|
652
|
-
|
653
|
-
c = [pA[0] + y, pA[1] + x]
|
654
|
-
phi = alpha_line(pA, c) + delta
|
655
|
-
pC = point_on_arc(pA, r, phi)
|
656
|
-
|
657
|
-
startangle = alpha_line(pC, pA)
|
658
|
-
endangle = alpha_line(pC, pB)
|
659
|
-
yield Arc(Element(center=pC,
|
660
|
-
radius=r,
|
661
|
-
start_angle=startangle*180/np.pi,
|
662
|
-
end_angle=endangle*180/np.pi))
|
663
|
-
|
664
|
-
|
665
|
-
def femshapes(femfile):
|
666
|
-
f = open(femfile, 'r')
|
667
|
-
|
668
|
-
for data in f:
|
669
|
-
text = data.split()
|
670
|
-
if text[0] == '[NumPoints]':
|
671
|
-
read_fem_points(f, int(text[2]))
|
672
|
-
elif text[0] == '[NumSegments]':
|
673
|
-
for e in read_fem_lines(f, int(text[2])):
|
674
|
-
yield e
|
675
|
-
elif text[0] == '[NumArcSegments]':
|
676
|
-
for e in read_fem_arcs(f, int(text[2])):
|
677
|
-
yield e
|
678
|
-
|
679
|
-
|
680
255
|
def is_connected(a, b):
|
681
256
|
if a == b:
|
682
257
|
return False
|
@@ -1079,6 +654,14 @@ class Geometry(object):
|
|
1079
654
|
return [n[1]['object'] for n in self.g.nodes(data=True)
|
1080
655
|
if n[1] and isinstance(n[1]['object'], Circle)]
|
1081
656
|
|
657
|
+
def nodes(self):
|
658
|
+
for n in self.g.nodes():
|
659
|
+
yield n
|
660
|
+
|
661
|
+
def get_nodes(self):
|
662
|
+
nodes = [n for n in self.g.nodes()]
|
663
|
+
return nodes
|
664
|
+
|
1082
665
|
def virtual_nodes(self):
|
1083
666
|
nodes = []
|
1084
667
|
for e in self.elements(Shape):
|
@@ -1696,6 +1279,11 @@ class Geometry(object):
|
|
1696
1279
|
# list already available
|
1697
1280
|
return
|
1698
1281
|
|
1282
|
+
areabuilder = AreaBuilder(geom=self)
|
1283
|
+
areabuilder.create_list_of_areas(main=False)
|
1284
|
+
self.area_list = areabuilder.area_list
|
1285
|
+
return
|
1286
|
+
|
1699
1287
|
def append(area_list, a):
|
1700
1288
|
for area in area_list:
|
1701
1289
|
if area.is_identical(a):
|
femagtools/dxfsl/journal.py
CHANGED
@@ -55,7 +55,6 @@ class Journal(object):
|
|
55
55
|
if not self.journal:
|
56
56
|
return
|
57
57
|
self.set_benchmark()
|
58
|
-
|
59
58
|
with open(self.filename, 'w') as f:
|
60
59
|
f.write(json.dumps(self.journal, indent=4))
|
61
60
|
f.close()
|
@@ -69,18 +68,8 @@ class Journal(object):
|
|
69
68
|
|
70
69
|
self.open_journal()
|
71
70
|
self.data = self.journal.get(name, None)
|
72
|
-
|
73
|
-
|
74
|
-
'elements': 0,
|
75
|
-
'nodes': 0,
|
76
|
-
'concat_lines': 0,
|
77
|
-
'concat_arcs': 0,
|
78
|
-
'appendices': 0,
|
79
|
-
'appendices_connected': 0,
|
80
|
-
'appendices_remaining': 0,
|
81
|
-
'areas': 0,
|
82
|
-
'area_errors': 0}
|
83
|
-
self.journal[name] = self.data
|
71
|
+
self.data = {'filename': ""} # initialise
|
72
|
+
self.journal[name] = self.data
|
84
73
|
return self.data
|
85
74
|
|
86
75
|
def set_benchmark(self):
|
@@ -88,19 +77,23 @@ class Journal(object):
|
|
88
77
|
self.put_warning("Problem with areas")
|
89
78
|
if self.data.get('appendices_deleted', 0) > 0:
|
90
79
|
self.put_warning("Problem with appendices")
|
91
|
-
|
80
|
+
|
92
81
|
def put(self, name, val):
|
93
82
|
if self.data:
|
94
83
|
self.data[name] = val
|
95
84
|
|
85
|
+
def add(self, name, val):
|
86
|
+
if self.data:
|
87
|
+
self.data[name] = val + self.data.get(name, 0)
|
88
|
+
|
96
89
|
def put_filename(self, val):
|
97
90
|
self.put('filename', val)
|
98
91
|
|
99
92
|
def put_areas(self, val):
|
100
|
-
self.
|
93
|
+
self.add('areas', val)
|
101
94
|
|
102
95
|
def put_area_errors(self, val):
|
103
|
-
self.
|
96
|
+
self.add('area_errors', val)
|
104
97
|
|
105
98
|
def put_elements(self, val):
|
106
99
|
self.put('elements', val)
|
@@ -109,28 +102,27 @@ class Journal(object):
|
|
109
102
|
self.put('nodes', val)
|
110
103
|
|
111
104
|
def put_concat_lines(self, val):
|
112
|
-
self.
|
105
|
+
self.add('concat_lines', val)
|
113
106
|
|
114
107
|
def put_concat_arcs(self, val):
|
115
|
-
self.
|
108
|
+
self.add('concat_arcs', val)
|
116
109
|
|
117
110
|
def put_appendices(self, val):
|
118
|
-
self.
|
111
|
+
self.add('appendices', val)
|
119
112
|
|
120
113
|
def put_appendices_connected(self, val):
|
121
|
-
self.
|
114
|
+
self.add('appendices_connected', val)
|
122
115
|
|
123
116
|
def put_appendices_remaining(self, val):
|
124
|
-
self.
|
117
|
+
self.add('appendices_remaining', val)
|
125
118
|
|
126
119
|
def put_appendices_deleted(self, val):
|
127
|
-
self.
|
120
|
+
self.add('appendices_deleted', val)
|
128
121
|
|
129
122
|
def put_exception(self, msg):
|
130
123
|
self.put('exception', msg)
|
131
124
|
|
132
125
|
def put_warning(self, msg):
|
133
|
-
print(msg)
|
134
126
|
lst = self.data.get('warning', [])
|
135
127
|
lst.append(msg)
|
136
128
|
self.put('warning', lst)
|
femagtools/dxfsl/shape.py
CHANGED
@@ -1008,7 +1008,7 @@ class Arc(Circle):
|
|
1008
1008
|
for p in points:
|
1009
1009
|
alpha_p = alpha_line(center, p)
|
1010
1010
|
alpha_min = min_angle(alpha_min, alpha_p)
|
1011
|
-
alpha_max =
|
1011
|
+
alpha_max = max_angle(alpha_max, alpha_p)
|
1012
1012
|
|
1013
1013
|
return (alpha_min, alpha_max)
|
1014
1014
|
|
@@ -0,0 +1,90 @@
|
|
1
|
+
"""
|
2
|
+
|
3
|
+
Geometry Parser for SVG files
|
4
|
+
|
5
|
+
"""
|
6
|
+
import logging
|
7
|
+
import re
|
8
|
+
import lxml.etree as ET
|
9
|
+
from .shape import Circle, Arc, Line, Element
|
10
|
+
import numpy as np
|
11
|
+
|
12
|
+
logger = logging.getLogger(__name__)
|
13
|
+
|
14
|
+
def get_center(r, p1, p2, sweep):
|
15
|
+
"""return center point coordinates of arc"""
|
16
|
+
dp = p2-p1
|
17
|
+
s = np.linalg.norm(dp)
|
18
|
+
delta = np.arctan2(dp[1], dp[0])
|
19
|
+
if s < 2*r:
|
20
|
+
if sweep == 0:
|
21
|
+
alfa = delta - np.arctan2(np.sqrt(r**2-s**2/4), s/2)
|
22
|
+
else:
|
23
|
+
alfa = delta + np.arctan2(np.sqrt(r**2-s**2/4), s/2)
|
24
|
+
else:
|
25
|
+
alfa = delta
|
26
|
+
return p1[0] + r*np.cos(alfa), p1[1] + r*np.sin(alfa)
|
27
|
+
|
28
|
+
|
29
|
+
def get_angles(sweep, center, p1, p2):
|
30
|
+
x1, y1 = (p1-center)
|
31
|
+
x2, y2 = (p2-center)
|
32
|
+
if sweep == 0:
|
33
|
+
return np.arctan2(y2, x2), np.arctan2(y1, x1)
|
34
|
+
return np.arctan2(y1, x1), np.arctan2(y2, x2)
|
35
|
+
|
36
|
+
|
37
|
+
def get_shapes(path):
|
38
|
+
"""return list of node elements (A, L)"""
|
39
|
+
state = ''
|
40
|
+
p = []
|
41
|
+
for s in [s for s in re.split('([AML])|,|\\s+',path) if s]:
|
42
|
+
if state == '':
|
43
|
+
state = s[0]
|
44
|
+
elif state == 'M':
|
45
|
+
p.append(float(s))
|
46
|
+
if len(p) == 2:
|
47
|
+
p1 = np.array(p)
|
48
|
+
p = []
|
49
|
+
state = ''
|
50
|
+
elif state == 'L':
|
51
|
+
p.append(float(s))
|
52
|
+
if len(p) == 2:
|
53
|
+
p2 = np.array(p)
|
54
|
+
logger.debug("Line %s -> %s",
|
55
|
+
p1, p2)
|
56
|
+
yield Line(Element(start=p1, end=p2))
|
57
|
+
p1 = p2.copy()
|
58
|
+
p = []
|
59
|
+
state = ''
|
60
|
+
elif state == 'A':
|
61
|
+
p.append(float(s))
|
62
|
+
if len(p) == 7:
|
63
|
+
sweep = int(p[-3])
|
64
|
+
p2 = np.array(p[-2:])
|
65
|
+
r = p[0]
|
66
|
+
center = get_center(r, p1, p2, sweep)
|
67
|
+
start, end = get_angles(sweep, center, p1, p2)
|
68
|
+
logger.debug("Arc center %s r %f %f -> %f",
|
69
|
+
center, r, start, end)
|
70
|
+
yield Arc(Element(center=center,
|
71
|
+
radius=r,
|
72
|
+
start_angle=start*180/np.pi,
|
73
|
+
end_angle=end*180/np.pi))
|
74
|
+
p1 = p2.copy()
|
75
|
+
p = []
|
76
|
+
state = ''
|
77
|
+
else:
|
78
|
+
raise ValueError(f"unsupported path {state}")
|
79
|
+
|
80
|
+
|
81
|
+
def svgshapes(svgfile):
|
82
|
+
svg = ET.parse(svgfile)
|
83
|
+
for p in svg.findall(".//{http://www.w3.org/2000/svg}path"):
|
84
|
+
yield from get_shapes(p.get('d'))
|
85
|
+
for p in svg.findall(".//{http://www.w3.org/2000/svg}line"):
|
86
|
+
yield Line(Element(start=[float(p.get('x1')), float(p.get('y1'))],
|
87
|
+
end=[float(p.get('x2')), float(p.get('y2'))]))
|
88
|
+
for p in svg.findall(".//{http://www.w3.org/2000/svg}circle"):
|
89
|
+
center = float(p.get('cx')), float(p.get('cy'))
|
90
|
+
yield Circle(Element(center=center, radius=float(p.get('r'))))
|