femagtools 1.6.8__py3-none-any.whl → 1.7.1__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.
Files changed (51) hide show
  1. femagtools/__init__.py +2 -2
  2. femagtools/bch.py +1 -1
  3. femagtools/dxfsl/area.py +343 -406
  4. femagtools/dxfsl/areabuilder.py +139 -12
  5. femagtools/dxfsl/conv.py +27 -9
  6. femagtools/dxfsl/converter.py +406 -127
  7. femagtools/dxfsl/corner.py +3 -0
  8. femagtools/dxfsl/femparser.py +1 -1
  9. femagtools/dxfsl/fslrenderer.py +290 -246
  10. femagtools/dxfsl/functions.py +4 -2
  11. femagtools/dxfsl/geom.py +1204 -893
  12. femagtools/dxfsl/journal.py +58 -22
  13. femagtools/dxfsl/machine.py +254 -75
  14. femagtools/dxfsl/plotrenderer.py +38 -3
  15. femagtools/dxfsl/shape.py +380 -103
  16. femagtools/dxfsl/symmetry.py +679 -110
  17. femagtools/femag.py +27 -2
  18. femagtools/forcedens.py +65 -40
  19. femagtools/fsl.py +71 -28
  20. femagtools/losscoeffs.py +46 -0
  21. femagtools/machine/effloss.py +8 -1
  22. femagtools/machine/im.py +3 -1
  23. femagtools/machine/pm.py +11 -7
  24. femagtools/machine/sizing.py +15 -12
  25. femagtools/machine/sm.py +114 -33
  26. femagtools/machine/utils.py +38 -34
  27. femagtools/model.py +12 -2
  28. femagtools/moo/population.py +1 -1
  29. femagtools/parstudy.py +17 -1
  30. femagtools/plot/__init__.py +1 -1
  31. femagtools/plot/char.py +24 -7
  32. femagtools/plot/forcedens.py +56 -29
  33. femagtools/plot/mcv.py +4 -1
  34. femagtools/plot/phasor.py +6 -1
  35. femagtools/poc.py +17 -10
  36. femagtools/templates/cogg_calc.mako +7 -1
  37. femagtools/templates/displ_stator_rotor.mako +33 -0
  38. femagtools/templates/fieldcalc.mako +10 -16
  39. femagtools/templates/pm_sym_f_cur.mako +1 -1
  40. femagtools/tks.py +3 -9
  41. {femagtools-1.6.8.dist-info → femagtools-1.7.1.dist-info}/LICENSE +1 -0
  42. {femagtools-1.6.8.dist-info → femagtools-1.7.1.dist-info}/METADATA +7 -4
  43. {femagtools-1.6.8.dist-info → femagtools-1.7.1.dist-info}/RECORD +51 -50
  44. {femagtools-1.6.8.dist-info → femagtools-1.7.1.dist-info}/WHEEL +1 -1
  45. tests/engines/__init__.py +0 -20
  46. tests/geom/__init__.py +0 -20
  47. tests/moo/__init__.py +0 -20
  48. tests/test_model.py +8 -1
  49. tests/test_sizing.py +2 -2
  50. {femagtools-1.6.8.dist-info → femagtools-1.7.1.dist-info}/entry_points.txt +0 -0
  51. {femagtools-1.6.8.dist-info → femagtools-1.7.1.dist-info}/top_level.txt +0 -0
femagtools/dxfsl/geom.py CHANGED
@@ -13,19 +13,25 @@ from __future__ import print_function
13
13
  import numpy as np
14
14
  import networkx as nx
15
15
  import logging
16
+ import inspect
16
17
  import sys
17
- from .corner import Corner
18
- from .area import Area
18
+ from pathlib import Path
19
+ from femagtools.dxfsl.corner import Corner
20
+ from femagtools.dxfsl.area import Area
21
+ import femagtools.dxfsl.area as AREA
19
22
  from .shape import Element, Shape, Circle, Arc, Line, Point
20
23
  from .shape import is_Circle, is_Arc, is_Line
21
24
  from .machine import Machine
25
+ from femagtools.dxfsl.concat import Concatenation
22
26
  from femagtools.dxfsl.areabuilder import AreaBuilder
27
+ from femagtools.dxfsl.functions import Timer
28
+ from femagtools.dxfsl.journal import Journal, getJournal
23
29
  from .functions import less_equal, less, greater, greater_equal
24
30
  from .functions import distance, alpha_line, alpha_points, alpha_angle
25
31
  from .functions import point, points_are_close, is_point_inside_region
26
32
  from .functions import line_m, line_n, lines_intersect_point
27
33
  from .functions import middle_point_of_line, middle_point_of_arc
28
- from .functions import middle_angle
34
+ from .functions import middle_angle, positive_angle
29
35
  from .functions import normalise_angle, is_same_angle
30
36
  from .functions import part_of_circle, gcd
31
37
  from .functions import point_on_arc, nodes_are_equal
@@ -40,6 +46,11 @@ nxversion = int(nx.__version__.split('.')[0])
40
46
  geom_mindist = 0.0
41
47
 
42
48
 
49
+ def lineno():
50
+ """Returns the current line number in our program."""
51
+ return inspect.currentframe().f_back.f_lineno
52
+
53
+
43
54
  def plot_area(area):
44
55
  """plot area for debug purposes"""
45
56
  import matplotlib.pylab as pl
@@ -73,6 +84,11 @@ def plot_area(area):
73
84
 
74
85
  ndec = 6 # number of decimals to round to
75
86
 
87
+ def create_geometry(new_elements, split=False):
88
+ return Geometry(new_elements,
89
+ center=(0.0, 0.0),
90
+ split=split)
91
+
76
92
 
77
93
  def intersect_and_split(inp_elements, rtol, atol):
78
94
  logger.info("Load input elements ... ")
@@ -117,71 +133,6 @@ def add_or_split(el, x, out_elements, rtol, atol):
117
133
  return []
118
134
 
119
135
 
120
- def add_element(geom, e, rtol, atol):
121
- n = geom.find_nodes(e.start(), e.end())
122
- try:
123
- add_or_join(geom, n[0], n[1], e, rtol, atol)
124
- except Exception as ex:
125
- logger.warn("EXCEPTION in add_element: %s", ex)
126
-
127
-
128
- def add_or_join(geom, n1, n2, entity, rtol, atol):
129
- """ adds a new entity to graph or joins entity with existing
130
- geom: Geometry
131
- n1, n2: nodes
132
- entity
133
- """
134
- if n1 == n2:
135
- logger.debug(
136
- "Tiny element with same node on both sides ignored: %s", n1)
137
- logger.debug(
138
- " -- element: %s", entity)
139
- return
140
-
141
- e = geom.get_edge_element(n1, n2)
142
- if not e: # no duplicates
143
- geom.add_edge(n1, n2, entity)
144
- return
145
-
146
- logger.debug("Duplicate connection: %s <--> %s", n1, n2)
147
- if is_Line(e):
148
- if is_Line(entity):
149
- logger.debug("add_or_join(): Duplicate Lines ignored")
150
- return # its ok
151
-
152
- if is_Arc(e):
153
- if is_Arc(entity):
154
- if points_are_close(e.center, entity.center, rtol=rtol, atol=atol):
155
- if points_are_close(e.p1, entity.p1):
156
- logger.debug("add_or_join(): Duplicate Arcs ignored")
157
- return # its ok
158
-
159
- if is_Circle(entity):
160
- if is_Circle(e):
161
- logger.debug("add_or_join(): Duplicate Circle ignored")
162
- return # its ok
163
-
164
- if is_Circle(entity) or is_Circle(e):
165
- e1, e2 = entity.cut_into_halves()
166
- logger.debug("===== add_or_join(): Element near circle is cut into halves =====")
167
- add_element(geom, e1, rtol, atol)
168
- add_element(geom, e2, rtol, atol)
169
- return # halves installed
170
-
171
- m1 = e.center_of_connection()
172
- m2 = entity.center_of_connection()
173
- logger.debug("midpoints: %s -- %s", m1, m2)
174
- if points_are_close(m1, m2, rtol, 1e-2):
175
- logger.debug("Elements are close together")
176
- return # ok
177
-
178
- e1, e2 = entity.cut_into_halves()
179
- logger.debug("===== add_or_join(): cut into halves =====")
180
- add_element(geom, e1, rtol, atol)
181
- add_element(geom, e2, rtol, atol)
182
- return # halves installed
183
-
184
-
185
136
  def get_nodes_of_paths(g, c):
186
137
  nodes = set()
187
138
  i = 1
@@ -290,11 +241,16 @@ class Geometry(object):
290
241
  def __init__(self,
291
242
  elements=[],
292
243
  center=[],
293
- rtol=1e-03,
244
+ rtol=1e-04,
294
245
  atol=1e-03,
295
246
  is_inner=False,
296
247
  is_outer=False,
297
248
  split=False,
249
+ concatenate=False,
250
+ connect=False,
251
+ delete=False,
252
+ adjust=False,
253
+ main=False,
298
254
  debug=False):
299
255
  self._name = ''
300
256
  self.kind = ''
@@ -307,6 +263,7 @@ class Geometry(object):
307
263
  self.sym_slice_angle = 0.0
308
264
  self.alfa = 0.0
309
265
  self.center = []
266
+ self.with_center_node = False
310
267
  self.min_radius = 0.0
311
268
  self.max_radius = 0.0
312
269
  self.is_inner = is_inner
@@ -315,26 +272,62 @@ class Geometry(object):
315
272
  self.sym_area = None
316
273
  self.airgaps = []
317
274
  self.area_list = []
275
+ self.areagroup_list = []
318
276
  self.g = nx.Graph()
319
277
  self.rtol = rtol
320
278
  self.atol = atol
321
279
  self.debug = debug
322
280
  self.num_edges = 0
323
281
  self.wdg_is_mirrored = False
282
+ self.has_windings = False
283
+ self.has_magnets = False
284
+ self.journal = getJournal()
285
+ self.area_errors = 0
286
+ self.critical_points = []
324
287
  i = 0
325
288
 
289
+ logger.debug("Geometry(split=%s, concat=%s, connect=%s, delete=%s, adjust=%s, main=%s,",
290
+ split, concatenate, connect, delete, adjust, main)
291
+ logger.debug(" rtol=%s, atol=%s)",
292
+ rtol, atol)
293
+
294
+ timer = Timer(start_it=True)
295
+ self.c_concat = 0
296
+ self.c_connect = 0
297
+
326
298
  def get_elements(elements, split):
327
299
  if split:
328
300
  return intersect_and_split(elements, self.rtol, self.atol)
329
- else:
330
- return elements
301
+
302
+ src_elements = [e for e in elements]
303
+ if main:
304
+ self.journal.put_elements(len(src_elements))
305
+
306
+ if not concatenate:
307
+ return src_elements
308
+
309
+ concat = Concatenation(rtol=self.rtol, atol=self.atol)
310
+ c, new_elements = concat.concatenate_matching_elements(src_elements,
311
+ main=main)
312
+ self.c_concat = c
313
+ return new_elements
314
+
315
+ nbr_nodes = []
316
+ if concatenate:
317
+ elements = [e for e in elements]
318
+ geom = Geometry(elements, center=(0.0, 0.0))
319
+ logger.debug("REAL GEOMETRY START ")
320
+ elements = geom.copy_all_elements(alpha=0.0)
321
+ nbr_nodes = geom.get_nodes(num_of_nbrs=[2, 4])
331
322
 
332
323
  for e in get_elements(elements, split):
333
324
  if e:
334
325
  e.id = i
335
326
  n = self.find_nodes(e.start(), e.end())
336
327
  try:
337
- add_or_join(self, n[0], n[1], e, self.rtol, self.atol)
328
+ self.add_or_join_edge(n[0], n[1], e,
329
+ rtol=self.rtol,
330
+ atol=self.atol)
338
331
  except Exception as ex:
339
332
  logger.warn("EXCEPTION %s", ex)
340
333
  if e: # must be a circle
@@ -346,6 +339,29 @@ class Geometry(object):
346
339
  if center:
347
340
  self.set_center(center)
348
341
 
342
+ if connect:
343
+ self.c_connect = self.connect_all_appendices(rtol=1e-04,
344
+ atol=1e-03,
345
+ main=True)
346
+ if delete:
347
+ self.delete_all_appendices()
348
+
349
+ if concatenate and self.c_concat > 0:
350
+ self.c_connect += self.connect_all_nodes(rtol=1e-04,
351
+ atol=1e-03,
352
+ additional_nodes=nbr_nodes,
353
+ main=True)
354
+
355
+ if adjust:
356
+ self.adjust_all_points()
357
+
358
+ if delete and center:
359
+ self.set_minmax_radius()
360
+
361
+ timer.stop("-- Geometry initialised in %0.4f seconds --")
362
+ logger.debug("End Geometry(concatenated=%s, connected=%s)",
363
+ self.c_concat, self.c_connect)
364
+
349
365
  def shaft(self):
350
366
  """returns shaft diameter if any"""
351
367
  radius = []
@@ -379,8 +395,15 @@ class Geometry(object):
379
395
  for n in self.g.nodes()}
380
396
  nx.relabel_nodes(self.g, mapping, copy=False)
381
397
 
398
+ def rotate_nodes(self, alpha, nodes):
399
+ T = np.array(((np.cos(alpha), -np.sin(alpha)),
400
+ (np.sin(alpha), np.cos(alpha))))
401
+ rotnodes = np.dot(T, np.asarray(nodes).T).T.tolist()
402
+ return rotnodes
403
+
382
404
  def rotate(self, alpha):
383
405
  """rotates all objects by angle alpha"""
406
+ logger.debug("rotate geometry(%s)", alpha)
384
407
  T = np.array(((np.cos(alpha), -np.sin(alpha)),
385
408
  (np.sin(alpha), np.cos(alpha))))
386
409
  for e in self.g.edges(data=True):
@@ -391,6 +414,7 @@ class Geometry(object):
391
414
  mapping = {n: (round(r[0], ndec),
392
415
  round(r[1], ndec))
393
416
  for n, r in zip(self.g.nodes(), rotnodes)}
417
+
394
418
  nx.relabel_nodes(self.g, mapping, copy=False)
395
419
 
396
420
  def check_geom(self, what):
@@ -449,12 +473,6 @@ class Geometry(object):
449
473
  nx.relabel_nodes(self.g, mapping, copy=False)
450
474
  self.diameters = tuple([factor*d for d in self.diameters])
451
475
 
452
- def find_nodes0(self, *points):
453
- """return closest nodes to points in arg within pickdist"""
454
- return [tuple([round(int(x/self.atol+0.5)*self.atol, ndec)
455
- for x in p])
456
- for p in points]
457
-
458
476
  def find_nodes(self, *points, **kwargs):
459
477
  """return closest nodes to points in arg within pickdist"""
460
478
  n = []
@@ -475,21 +493,26 @@ class Geometry(object):
475
493
  return [(round(p[0], ndec), round(p[1], ndec)) for p in points]
476
494
  return n
477
495
 
478
- def find_node(self, p, **kwargs):
479
- """return closest nodes to points in arg within pickdist"""
496
+ def find_other_node(self, node, **kwargs):
497
+ """return closest node to node in arg within pickdist"""
480
498
  nodes = list(kwargs.get('g', self.g))
481
499
  if nodes:
482
500
  anodes = np.asarray(nodes)
483
501
  # la.norm on numpy below 1.8 does not accept axis
484
- c = anodes - p
502
+ c = anodes - node
485
503
  dist = np.sqrt(np.einsum('ij, ij->i', c, c))
486
- # dist = la.norm(np.asarray(nodes) - p, axis=1)
487
504
  idx = dist.argmin()
488
- if dist[idx] == 0.0: # myself
489
- dist[idx] = 999.0
490
- idx = dist.argmin()
491
- if dist[idx] < 0.05:
492
- return nodes[idx]
505
+ candidates = [(dist[i], nodes[i]) for i in range(len(dist))
506
+ if dist[i] < 0.01]
507
+ if not candidates:
508
+ return None
509
+ candidates.sort()
510
+ if len(candidates) > 1:
511
+ i = 0
512
+ d, n = candidates[0]
513
+ if d == 0.0:
514
+ d, n = candidates[1]
515
+ return n
493
516
  return None
494
517
 
495
518
  def find_the_node(self, p, **kwargs):
@@ -511,7 +534,7 @@ class Geometry(object):
511
534
  paths = []
512
535
  g = self.g.copy()
513
536
  g.remove_edges_from(self.arcs())
514
- while g.number_of_edges() > 0:
537
+ while self.number_of_edges() > 0:
515
538
  p = single_path(g.edges())
516
539
  g.remove_edges_from(p)
517
540
  # rearrange sequence to make it contiguous:
@@ -545,6 +568,69 @@ class Geometry(object):
545
568
  return n
546
569
  return []
547
570
 
571
+ def add_element(self, e, rtol, atol):
572
+ n = self.find_nodes(e.start(), e.end())
573
+ try:
574
+ self.add_or_join_edge(n[0], n[1], e, rtol=rtol, atol=atol)
575
+ except Exception as ex:
576
+ logger.warn("EXCEPTION in add_element: %s", ex)
577
+
578
+ def add_or_join_edge(self, n1, n2, entity, rtol=1e-03, atol=1e-03):
579
+ """ adds a new entity to graph or joins entity with existing
580
+ geom: Geometry
581
+ n1, n2: nodes
582
+ entity
583
+ """
584
+ if n1 == n2:
585
+ logger.debug(
586
+ "add_or_join_edge: Tiny element with same node on both sides ignored: %s", n1)
587
+ logger.debug(
588
+ "add_or_join_edge: -- element: %s", entity)
589
+ return
590
+
591
+ e = self.get_edge_element(n1, n2)
592
+ if not e: # no duplicates
593
+ self.add_edge(n1, n2, entity)
594
+ return
595
+
596
+ logger.debug("add_or_join_edge: Duplicate connection: %s <--> %s", n1, n2)
597
+ if is_Line(e):
598
+ if is_Line(entity):
599
+ logger.debug("add_or_join_edge: Duplicate Lines ignored")
600
+ return # its ok
601
+
602
+ if is_Arc(e):
603
+ if is_Arc(entity):
604
+ if points_are_close(e.center, entity.center, rtol=rtol, atol=atol):
605
+ if points_are_close(e.p1, entity.p1):
606
+ logger.debug("add_or_join_edge: Duplicate Arcs ignored")
607
+ return # its ok
608
+
609
+ if is_Circle(entity):
610
+ if is_Circle(e):
611
+ logger.debug("add_or_join_edge: Duplicate Circle ignored")
612
+ return # its ok
613
+
614
+ if is_Circle(entity) or is_Circle(e):
615
+ e1, e2 = entity.cut_into_halves()
616
+ logger.debug("add_or_join_edge: Element near circle is cut into halves")
617
+ self.add_element(e1, rtol, atol)
618
+ self.add_element(e2, rtol, atol)
619
+ return # halves installed
620
+
621
+ m1 = e.center_of_connection()
622
+ m2 = entity.center_of_connection()
623
+ logger.debug("add_or_join_edge: midpoints: %s -- %s", m1, m2)
624
+ if points_are_close(m1, m2, rtol, 1e-2):
625
+ logger.debug("add_or_join_edge: Elements are close together")
626
+ return # ok
627
+
628
+ e1, e2 = entity.cut_into_halves()
629
+ logger.debug("add_or_join_edge: cut into halves")
630
+ self.add_element(e1, rtol, atol)
631
+ self.add_element(e2, rtol, atol)
632
+ return # halves installed
633
+
548
634
  def add_edge(self, n1, n2, entity):
549
635
  if points_are_close(n1, n2):
550
636
  logger.debug("WARNING in add_edge(): Points of %s are close together",
@@ -552,10 +638,18 @@ class Geometry(object):
552
638
  logger.debug(" n1 = %s, n2 = %s", n1, n2)
553
639
  logger.debug(" p1 = %s, p2 = %s", entity.p1, entity.p2)
554
640
 
641
+ if self.has_edge(n1, n2):
642
+ logger.warning("FATAL ERROR: Duplicates in add_edge(%s, %s)", n1, n2)
643
+
555
644
  entity.set_nodes(n1, n2)
556
645
  logger.debug("add_edge %s - %s (%s)", n1, n2, entity.classname())
557
646
  self.g.add_edge(n1, n2, object=entity)
558
647
 
648
+ def has_edge(self, n1, n2):
649
+ if self.g.get_edge_data(n1, n2):
650
+ return True
651
+ return False
652
+
559
653
  def get_edge(self, eg):
560
654
  return [[e[0], e[1], e[2]['object']] for e in self.g.edges(data=True)
561
655
  if e[2]['object'] is eg]
@@ -574,6 +668,8 @@ class Geometry(object):
574
668
  def _remove_edge(self, n1, n2):
575
669
  logger.debug("remove_edge %s - %s", n1, n2)
576
670
  self.g.remove_edge(n1, n2)
671
+ self._remove_node(n1)
672
+ self._remove_node(n2)
577
673
 
578
674
  def remove_edge(self, edge):
579
675
  e = self.get_edge(edge)
@@ -587,16 +683,21 @@ class Geometry(object):
587
683
  for e in edges:
588
684
  self.remove_edge(e)
589
685
 
686
+ def _remove_node(self, n):
687
+ for nbr in self.g.neighbors(n):
688
+ return
689
+ try:
690
+ self.g.remove_node(n)
691
+ except nx.NetworkXError:
692
+ logger.warning("WARNING: remove node %s failed", n)
693
+
590
694
  def add_line(self, n1, n2, color=None, linestyle=None):
591
695
  line = Line(Element(start=n1, end=n2),
592
696
  color=color,
593
697
  linestyle=linestyle)
594
- add_or_join(self,
595
- n1,
596
- n2,
597
- line,
598
- self.rtol,
599
- self.atol)
698
+ self.add_element(line,
699
+ rtol=self.rtol,
700
+ atol=self.atol)
600
701
 
601
702
  def add_arc(self, n1, n2, center, radius, color=None, linestyle=None):
602
703
  angle_n1 = alpha_line(center, n1)
@@ -607,18 +708,20 @@ class Geometry(object):
607
708
  end_angle=angle_n2*180/np.pi),
608
709
  color=color,
609
710
  linestyle=linestyle)
610
- add_or_join(self,
611
- n1,
612
- n2,
613
- arc,
614
- self.rtol,
615
- self.atol)
616
-
617
- def elements(self, type):
711
+ self.add_element(arc,
712
+ rtol=self.rtol,
713
+ atol=self.atol)
714
+
715
+ def elements(self, type=Shape):
618
716
  """return lists of objects"""
619
717
  return [e[2]['object'] for e in self.g.edges(data=True)
620
718
  if isinstance(e[2]['object'], type)]
621
719
 
720
+ def elements_and_nodes(self, type=Shape):
721
+ """return lists of objects"""
722
+ return [(e[0], e[1], e[2]['object']) for e in self.g.edges(data=True)
723
+ if isinstance(e[2]['object'], type)]
724
+
622
725
  def arcs(self):
623
726
  """return lists of arcs"""
624
727
  return self.elements(Arc)
@@ -642,12 +745,9 @@ class Geometry(object):
642
745
  for p1, p2 in rem_lines:
643
746
  self._remove_edge(p1, p2)
644
747
  for new_ln in new_lines:
645
- add_or_join(self,
646
- new_ln.node1(ndec),
647
- new_ln.node2(ndec),
648
- new_ln,
649
- self.rtol,
650
- self.atol)
748
+ self.add_element(new_ln,
749
+ rtol=self.rtol,
750
+ atol=self.atol)
651
751
 
652
752
  def circles(self):
653
753
  """return list of circle nodes"""
@@ -658,8 +758,15 @@ class Geometry(object):
658
758
  for n in self.g.nodes():
659
759
  yield n
660
760
 
661
- def get_nodes(self):
662
- nodes = [n for n in self.g.nodes()]
761
+ def get_nodes(self, num_of_nbrs=[]):
762
+ if num_of_nbrs:
763
+ nodes = []
764
+ for n in self.g.nodes():
765
+ nbr_list = [nbr for nbr in self.g.neighbors(n)]
766
+ if len(nbr_list) in num_of_nbrs:
767
+ nodes.append(n)
768
+ else:
769
+ nodes = [n for n in self.g.nodes()]
663
770
  return nodes
664
771
 
665
772
  def virtual_nodes(self):
@@ -668,14 +775,25 @@ class Geometry(object):
668
775
  nodes += e.get_nodes()
669
776
  return nodes
670
777
 
778
+ def get_neighbors(self, n):
779
+ return [nbr for nbr in self.g.neighbors(n)]
780
+
671
781
  def angle_nodes(self, center, angle, rtol, atol):
782
+ if np.isclose(abs(angle), np.pi, rtol, atol):
783
+ angle_func = positive_angle
784
+ else:
785
+ angle_func = normalise_angle
786
+ angle = angle_func(angle)
787
+
672
788
  nodes = []
673
789
  for n in self.g.nodes():
674
790
  if points_are_close(center, n, rtol, atol):
675
791
  # Da gibt es keinen brauchbaren Winkel
676
792
  nodes.append(n)
677
- elif np.isclose(angle, alpha_line(center, n), rtol, atol):
678
- nodes.append(n)
793
+ else:
794
+ angle_line = angle_func(alpha_line(center, n))
795
+ if np.isclose(angle, angle_line, rtol, atol):
796
+ nodes.append(n)
679
797
  return nodes
680
798
 
681
799
  def radius_nodes(self, center, radius, rtol, atol):
@@ -747,7 +865,10 @@ class Geometry(object):
747
865
  else:
748
866
  p = (self.min_radius, 0.0)
749
867
  cp = self.start_corners[0]
750
- if points_are_close(p, cp, atol=0.5):
868
+ if points_are_close(p, cp, rtol=1e-2, atol=1e-1):
869
+ if points_are_close(p, cp, rtol=1e-3, atol=1e-2):
870
+ logger.debug("get_start_airgap_corner: critical")
871
+ logger.debug(" -- soll: %s, ist: %s", p, cp)
751
872
  return cp, True
752
873
  return p, False
753
874
 
@@ -758,7 +879,11 @@ class Geometry(object):
758
879
  else:
759
880
  p = point(self.center, self.min_radius, self.alfa, ndec)
760
881
  cp = self.end_corners[0]
761
- if points_are_close(p, cp, atol=0.5):
882
+ logger.debug("End Airgap Corner: %s is %s", p, cp)
883
+ if points_are_close(p, cp, rtol=1e-2, atol=1e-1):
884
+ if points_are_close(p, cp, rtol=1e-3, atol=1e-2):
885
+ logger.debug("get_end_airgap_corner: critical")
886
+ logger.debug(" -- soll: %s, ist: %s", p, cp)
762
887
  return cp, True
763
888
  return p, False
764
889
 
@@ -798,6 +923,7 @@ class Geometry(object):
798
923
  atol = 1e-3
799
924
 
800
925
  logger.debug("begin repair_hull_line(center=%s, angle=%s)", center, angle)
926
+ [logger.debug(" --> Corner %s", c) for c in corners]
801
927
 
802
928
  if len(corners) < 2:
803
929
  # no hull without more than 1 corners
@@ -840,8 +966,12 @@ class Geometry(object):
840
966
  radius=el.radius,
841
967
  start_angle=alpha_mid*180/np.pi,
842
968
  end_angle=alpha_end*180/np.pi))
843
- self.add_edge(p1, a1.node2(ndec), a1)
844
- self.add_edge(a2.node1(ndec), p2, a2)
969
+ self.add_element(a1,
970
+ rtol=self.rtol,
971
+ atol=self.atol)
972
+ self.add_element(a2,
973
+ rtol=self.rtol,
974
+ atol=self.atol)
845
975
  else:
846
976
  clist = []
847
977
  if clist_p1:
@@ -850,18 +980,12 @@ class Geometry(object):
850
980
  clist = [c for c in clist_p2]
851
981
  [corner.set_keep_node() for corner in clist]
852
982
 
853
- try:
854
- [self.g.remove_node(c.point())
855
- for c in corners if not c.keep_node()]
856
- except Exception as e:
857
- logger.warn("Warning: %s", e)
858
-
859
983
  # Rebuild Corner-list after correction
860
984
  center_added, corners = self.get_corner_list(center, angle, rtol, atol)
861
985
  for c in corners:
862
986
  logger.debug("Correct Corner: %s", c)
863
987
 
864
- if with_center:
988
+ if with_center or self.with_center_node:
865
989
  c_corner = Corner(center, tuple(center))
866
990
  if c_corner not in corners:
867
991
  corners.append(c_corner)
@@ -871,7 +995,9 @@ class Geometry(object):
871
995
  p1 = corners[0].point()
872
996
  for c in corners[1:]:
873
997
  p2 = c.point()
874
- self.add_edge(p1, p2, Line(Element(start=p1, end=p2)))
998
+ self.add_element(Line(Element(start=p1, end=p2)),
999
+ rtol=self.rtol,
1000
+ atol=self.atol)
875
1001
  p1 = p2
876
1002
 
877
1003
  self.set_minmax_radius()
@@ -906,14 +1032,18 @@ class Geometry(object):
906
1032
  c_min.is_new_point = True
907
1033
  p1 = c_min.point()
908
1034
  p2 = c_first.point()
909
- self.add_edge(p1, p2, Line(Element(start=p1, end=p2)))
1035
+ self.add_element(Line(Element(start=p1, end=p2)),
1036
+ rtol=self.rtol,
1037
+ atol=self.atol)
910
1038
 
911
1039
  c_last = corners[len(corners)-1]
912
1040
  if not c_max.is_same_corner(c_last):
913
1041
  c_max.is_new_point = True
914
1042
  p2 = c_max.point()
915
1043
  p1 = c_last.point()
916
- self.add_edge(p1, p2, Line(Element(start=p1, end=p2)))
1044
+ self.add_element(Line(Element(start=p1, end=p2)),
1045
+ rtol=self.rtol,
1046
+ atol=self.atol)
917
1047
  logger.debug("end complete_hull_line")
918
1048
  return (c_min, c_max)
919
1049
 
@@ -928,10 +1058,12 @@ class Geometry(object):
928
1058
  nodes_sorted.sort()
929
1059
  p = nodes_sorted[0][1]
930
1060
  angle_p = alpha_line(self.center, p)
931
- self.add_edge(start_p, p, Arc(
932
- Element(center=self.center, radius=radius,
933
- start_angle=startangle*180/np.pi,
934
- end_angle=angle_p*180/np.pi)))
1061
+ arc = Arc(Element(center=self.center, radius=radius,
1062
+ start_angle=startangle*180/np.pi,
1063
+ end_angle=angle_p*180/np.pi))
1064
+ self.add_element(arc,
1065
+ rtol=self.rtol,
1066
+ atol=self.atol)
935
1067
 
936
1068
  if endcorner.is_new_point:
937
1069
  end_p = endcorner.point()
@@ -940,10 +1072,12 @@ class Geometry(object):
940
1072
  inx = len(nodes_sorted)-1
941
1073
  p = nodes_sorted[inx][1]
942
1074
  angle_p = alpha_line(self.center, p)
943
- self.add_edge(p, end_p, Arc(
944
- Element(center=self.center, radius=radius,
945
- start_angle=angle_p*180/np.pi,
946
- end_angle=endangle*180/np.pi)))
1075
+ arc = Arc(Element(center=self.center, radius=radius,
1076
+ start_angle=angle_p*180/np.pi,
1077
+ end_angle=endangle*180/np.pi))
1078
+ self.add_element(p, end_p, arc,
1079
+ rtol=self.rtol,
1080
+ atol=self.atol)
947
1081
 
948
1082
  def get_corner_nodes(self, center, angle):
949
1083
  rtol = 1e-4
@@ -954,313 +1088,17 @@ class Geometry(object):
954
1088
  return () # not enough corners
955
1089
  return (corners[0].point(), corners[len(corners)-1].point())
956
1090
 
1091
+ def set_start_corners(self, center, angle):
1092
+ self.start_corners = self.get_corner_nodes(center, angle)
1093
+
1094
+ def set_end_corners(self, center, angle):
1095
+ self.end_corners = self.get_corner_nodes(center, angle)
1096
+
957
1097
  def get_angle(self, alpha1, alpha2):
958
1098
  if np.isclose(alpha1, alpha2, 0.001, 0.001):
959
1099
  return 0.0
960
1100
  return alpha_angle(alpha1, alpha2)
961
1101
 
962
- def get_edge_neighbors_list(self, alpha, info):
963
- n1 = info['n1']
964
- n2 = info['n2']
965
-
966
- nbrs = [n for n in self.g.neighbors(n2)
967
- if not (points_are_close(n, n1) or points_are_close(n, n2))]
968
- if len(nbrs) == 0:
969
- logger.debug(" FATAL: no neighbors of %s available ???", n2)
970
- return []
971
-
972
- angles = []
973
- for c, n in enumerate(nbrs):
974
- info_next = self.get_edge_info(n2, n)
975
- angle = self.get_angle(alpha, info_next['alpha_start'])
976
- angles.append((angle, c, info_next))
977
-
978
- info_rev = self.get_reverse_edge_info(info)
979
- angle = self.get_angle(alpha, info_rev['alpha_start'])
980
- angles.append((angle, c+1, info_rev))
981
- angles.sort(reverse=True)
982
- return angles
983
-
984
- def is_lefthand_edge(self, alpha, info1, info2):
985
- logger.debug(" begin of is_lefthand_edge()")
986
- angle1 = self.get_angle(alpha, info1['alpha_start'])
987
- angle2 = self.get_angle(alpha, info2['alpha_start'])
988
- if not np.isclose(angle1, angle2, 0.005, 0.005):
989
- logger.debug(" UNEXPECTED DIFFERENT ANGLES")
990
- return angle1 > angle2
991
-
992
- alpha_start = info1['alpha_start']
993
-
994
- if self.is_edge_arc(info1):
995
- if self.is_edge_arc(info2):
996
- logger.debug(" ARC - ARC")
997
-
998
- i1_dist = distance(info1['n1'], info1['n2'])
999
- i2_dist = distance(info2['n1'], info2['n2'])
1000
- min_dist = min(i1_dist, i2_dist) / 1.5
1001
-
1002
- circ = Circle(Element(center=info1['n1'],
1003
- radius=min_dist))
1004
- pt = info1['element'].intersect_circle(circ)
1005
- if len(pt) != 1:
1006
- logger.debug("WARNING: intersect problem at %s",
1007
- info1['n1'])
1008
- i1_alpha = info1['alpha_n2']
1009
- else:
1010
- i1_alpha = alpha_line(info1['n1'], pt[0])
1011
- i1_angle = self.get_angle(alpha_start, i1_alpha)
1012
-
1013
- circ = Circle(Element(center=info2['n1'],
1014
- radius=min_dist))
1015
- pt = info2['element'].intersect_circle(circ)
1016
- if len(pt) != 1:
1017
- logger.debug("WARNING: intersect problem at %s",
1018
- info2['n1'])
1019
- i2_alpha = info2['alpha_n2']
1020
- else:
1021
- i2_alpha = alpha_line(info2['n1'], pt[0])
1022
- i2_angle = self.get_angle(alpha_start, i2_alpha)
1023
-
1024
- rslt = normalise_angle(i1_angle) > normalise_angle(i2_angle)
1025
- logger.debug(" end of is_lefthand_edge() = %s",
1026
- rslt)
1027
- return rslt
1028
-
1029
- logger.debug(" ARC - LINE")
1030
-
1031
- e1 = info1['element']
1032
- d2 = distance(e1.center, info2['n2'])
1033
- if not np.isclose(e1.radius, d2, 0.005, 0.005):
1034
- angle1 = self.get_angle(alpha, info1['alpha_n2'])
1035
- angle = alpha_angle(angle1, angle2)
1036
- logger.debug(" NOT close together")
1037
- rslt = greater(angle, np.pi)
1038
- logger.debug(" end of is_lefthand_edge() = %s", rslt)
1039
- return rslt
1040
-
1041
- next_info2 = self.next_edge_lefthand_side(info2)
1042
- if not next_info2:
1043
- logger.debug("FATAL ERROR")
1044
- raise ValueError("FATAL ERROR: no edge found")
1045
-
1046
- return self.is_lefthand_edge(alpha, info1, next_info2)
1047
-
1048
- if not self.is_edge_arc(info2):
1049
- # two overlapping lines
1050
- logger.debug(" end of is_lefthand_edge(): overlap")
1051
- return True
1052
-
1053
- logger.debug(" LINE - ARC")
1054
-
1055
- rslt = not self.is_lefthand_edge(alpha, info2, info1)
1056
- logger.debug(" end of is_lefthand_edge() = %s", rslt)
1057
- return rslt
1058
-
1059
- def next_edge_lefthand_side(self, info_curr): # current
1060
- alpha = normalise_angle(info_curr['alpha_n2'] + np.pi)
1061
- logger.debug(" next_edge_lefthand_side( alpha=%s )", alpha)
1062
-
1063
- nbrs = self.get_edge_neighbors_list(alpha, info_curr)
1064
- if len(nbrs) == 0:
1065
- logger.debug(" no neighbors available ???")
1066
- return None # unexpected end
1067
-
1068
- if len(nbrs) < 3:
1069
- for a, c, info_next in nbrs:
1070
- if not info_next['reverse']:
1071
- return info_next
1072
- raise ValueError("FATAL ERROR in next_edge_lefthand_side() !!")
1073
-
1074
- logger.debug(" POINT WITH %s NEIGHBORS", len(nbrs)-1)
1075
-
1076
- f_angle, f_c, f_info_next = nbrs[0]
1077
- f_info_next['angle'] = f_angle
1078
-
1079
- for n_angle, n_c, n_info_next in nbrs[1:]:
1080
- n_info_next['angle'] = n_angle
1081
- if np.isclose(f_angle, n_angle, 0.01, 0.01):
1082
- logger.debug(" SAME DIRECTION")
1083
- # ACHTUNG
1084
- if self.is_lefthand_edge(alpha, f_info_next, n_info_next):
1085
- logger.debug(" == first is on the left side")
1086
- angle = self.get_angle(alpha,
1087
- n_info_next['alpha_start'] - 0.01)
1088
- n_info_next['angle'] = angle
1089
- else:
1090
- logger.debug(" == next is on the left side")
1091
- angle = self.get_angle(alpha,
1092
- f_info_next['alpha_start'] - 0.01)
1093
- f_info_next['angle'] = angle
1094
-
1095
- f_angle = n_angle
1096
- f_info_next = n_info_next
1097
-
1098
- nbrs2 = [(e['angle'], c, e) for a, c, e in nbrs
1099
- if not e['reverse']]
1100
- nbrs2.sort(reverse=True)
1101
- return nbrs2[0][2]
1102
-
1103
- def get_edge_info(self, n1, n2):
1104
- e_dict = self.g.get_edge_data(n1, n2)
1105
- if not e_dict:
1106
- raise ValueError("Fatal: no edge-data found from {} to {}"
1107
- .format(n1, n2))
1108
-
1109
- e = e_dict.get('object', None)
1110
- if not e:
1111
- raise ValueError("Fatal: no object found from {} to {}"
1112
- .format(n1, n2))
1113
-
1114
- x = e.get_node_number(n1)
1115
- alpha_n1 = e.get_alpha(n1)
1116
-
1117
- info = {'n1': n1,
1118
- 'n2': n2,
1119
- 'data': e_dict,
1120
- 'element': e,
1121
- 'x': x,
1122
- 'alpha_n1': alpha_n1,
1123
- 'alpha_n2': e.get_alpha(n2),
1124
- 'alpha_start': normalise_angle(alpha_n1 + np.pi),
1125
- 'tracked': e_dict.get(x, False),
1126
- 'reverse': False}
1127
- return info
1128
-
1129
- def get_reverse_edge_info(self, info):
1130
- alpha_n1 = info['alpha_n2']
1131
- rev_info = {'n1': info['n2'],
1132
- 'n2': info['n1'],
1133
- 'data': info['data'],
1134
- 'element': info['element'],
1135
- 'x': 0,
1136
- 'alpha_n1': alpha_n1,
1137
- 'alpha_n2': info['alpha_n1'],
1138
- 'alpha_start': normalise_angle(alpha_n1 + np.pi),
1139
- 'tracked': False,
1140
- 'reverse': True}
1141
- return rev_info
1142
-
1143
- def is_edge_arc(self, info):
1144
- return isinstance(info['element'], Arc)
1145
-
1146
- def log_edge_info(self, info):
1147
- logger.debug(' node1 = %s', info['n1'])
1148
- logger.debug(' node2 = %s', info['n2'])
1149
- logger.debug(' x = %s', info['x'])
1150
- logger.debug(' lock = (%s, %s, %s)',
1151
- info['data'].get(0, False),
1152
- info['data'].get(1, False),
1153
- info['data'].get(2, False))
1154
-
1155
- def set_edge_tracked(self, info):
1156
- x = info['x']
1157
- info['data'][x] = True # footprint
1158
-
1159
- def get_new_area(self, start_n1, start_n2, solo):
1160
- info_curr = self.get_edge_info(start_n1, start_n2)
1161
-
1162
- area = []
1163
- result = {'area': area,
1164
- 'elements': 1,
1165
- 'msg': "<undefined>",
1166
- 'reverse': False,
1167
- 'ok': False}
1168
- area.append(info_curr['element'])
1169
-
1170
- if info_curr['tracked']:
1171
- result['msg'] = ("<== area already tracked (%s) ***",
1172
- info_curr['x'])
1173
- result['area'] = None
1174
- return result
1175
-
1176
- logger.debug('==> start of get_new_area()')
1177
- self.log_edge_info(info_curr)
1178
- self.set_edge_tracked(info_curr)
1179
-
1180
- e = info_curr['element']
1181
- if (isinstance(e, Circle) and not isinstance(e, Arc)):
1182
- result['msg'] = "area is a circle !!"
1183
- logger.debug("<== %s", result['msg'])
1184
- e_dict = info_curr['data']
1185
- e_dict[1] = True # footprint
1186
- e_dict[2] = True # footprint
1187
- result['ok'] = True
1188
- return result
1189
-
1190
- logger.debug("***** EDGE %s *****", 1)
1191
- info_next = self.next_edge_lefthand_side(info_curr)
1192
- if not info_next:
1193
- result['msg'] = ("dead end ({}, {})"
1194
- .format(info_curr['n1'], info_curr['n2']))
1195
- logger.debug("<== %s", result['msg'])
1196
- return result
1197
- self.log_edge_info(info_next)
1198
-
1199
- prev_n1 = info_curr['n1']
1200
- next_n1 = info_next['n1']
1201
- next_n2 = info_next['n2']
1202
-
1203
- alpha = normalise_angle(alpha_points(prev_n1,
1204
- next_n1,
1205
- next_n2))
1206
-
1207
- c = 1
1208
- while not (nodes_are_equal(next_n1, start_n1) and
1209
- nodes_are_equal(next_n2, start_n2)):
1210
- c += 1
1211
- if c > self.num_edges * 2:
1212
- logger.error("FATAL: *** over %s elements in area ? ***",
1213
- self.num_edges)
1214
- plot_area(area)
1215
- sys.exit(1)
1216
-
1217
- area.append(info_next['element'])
1218
-
1219
- if info_next['tracked']:
1220
- result['msg'] = ("FATAL: area already tracked ({}) ***"
1221
- .format(info_next['x']))
1222
- logger.debug("<== %s", result['msg'])
1223
- result['elements'] = c
1224
- return result
1225
-
1226
- self.set_edge_tracked(info_next)
1227
-
1228
- info_curr = info_next
1229
- logger.debug("***** EDGE %s *****", c)
1230
- info_next = self.next_edge_lefthand_side(info_curr)
1231
- if not info_next:
1232
- result['msg'] = ("<== dead end ({},{})"
1233
- .format(info_curr['n1'], info_curr['n2']))
1234
- logger.debug("<== %s", result['msg'])
1235
- result['elements'] = c
1236
- return result
1237
- self.log_edge_info(info_next)
1238
-
1239
- prev_n1 = info_curr['n1']
1240
- next_n1 = info_next['n1']
1241
- next_n2 = info_next['n2']
1242
-
1243
- a = normalise_angle(alpha_points(prev_n1,
1244
- next_n1,
1245
- next_n2))
1246
- alpha += a
1247
-
1248
- logger.debug(" END OF get_new_area")
1249
-
1250
- if alpha < 0.0:
1251
- result['msg'] = ("turn left expected, but it turned right ({})"
1252
- .format(alpha))
1253
- logger.debug("<== %s", result['msg'])
1254
- result['elements'] = c
1255
- result['reverse'] = True
1256
- return result
1257
-
1258
- result['msg'] = "area found !!"
1259
- logger.debug("<== %s", result['msg'])
1260
- result['elements'] = c
1261
- result['ok'] = True
1262
- return result
1263
-
1264
1102
  def set_edge_attributes(self):
1265
1103
  if nxversion == 1:
1266
1104
  nx.set_edge_attributes(self.g, 0, True)
@@ -1271,7 +1109,7 @@ class Geometry(object):
1271
1109
  nx.set_edge_attributes(self.g, False, 1)
1272
1110
  nx.set_edge_attributes(self.g, False, 2)
1273
1111
 
1274
- def create_list_of_areas(self, crunch=False):
1112
+ def create_list_of_areas(self, main=False):
1275
1113
  """ return list of areas for each node and their neighbors
1276
1114
  """
1277
1115
  if len(self.area_list) > 0:
@@ -1280,47 +1118,9 @@ class Geometry(object):
1280
1118
  return
1281
1119
 
1282
1120
  areabuilder = AreaBuilder(geom=self)
1283
- areabuilder.create_list_of_areas(main=False)
1121
+ areabuilder.create_list_of_areas(main=main)
1284
1122
  self.area_list = areabuilder.area_list
1285
- return
1286
-
1287
- def append(area_list, a):
1288
- for area in area_list:
1289
- if area.is_identical(a):
1290
- return
1291
- area_list.append(a)
1292
-
1293
- logger.debug("create new area list")
1294
- self.set_edge_attributes()
1295
-
1296
- crunched = 0
1297
- for n in self.g.nodes():
1298
- if self.debug:
1299
- print('.', end='', flush=True)
1300
-
1301
- finished = False
1302
- while not finished:
1303
- finished = True
1304
- nbrs = [nbr for nbr in self.g.neighbors(n)]
1305
- for next_n in nbrs:
1306
- result = self.get_new_area(n, next_n, len(nbrs) < 3)
1307
- if result['ok']:
1308
- area = result['area']
1309
- a = Area(area, self.center, 0.0)
1310
- logger.debug("Area %s found", a.identifier())
1311
- if crunch:
1312
- c = a.crunch_area(self)
1313
- else:
1314
- c = 0
1315
- append(self.area_list, a)
1316
- crunched += c
1317
- if c > 0:
1318
- # take care! may be there are new neighbors for n
1319
- finished = False
1320
- break
1321
-
1322
- logger.debug("%s areas found and %s elements concatenated",
1323
- len(self.area_list), crunched)
1123
+ logger.debug("area list created")
1324
1124
 
1325
1125
  def list_of_areas(self):
1326
1126
  self.create_list_of_areas()
@@ -1497,8 +1297,12 @@ class Geometry(object):
1497
1297
  end_angle=alpha_end*180/np.pi))
1498
1298
  if points_are_close(a.p1, a.p2, rtol=1e-02, atol=1e-02):
1499
1299
  logger.debug("ATTENTION: creation of a tiny arc")
1300
+ logger.debug("-- %s", a)
1500
1301
  a.set_attribute("tiny")
1501
- new_elements.append(a)
1302
+ if points_are_close(a.p1, a.p2, rtol=1e-06, atol=1e-06):
1303
+ logger.debug("-- points are equal")
1304
+ else:
1305
+ new_elements.append(a)
1502
1306
  alpha_start = alpha_end
1503
1307
  p1 = p2
1504
1308
  return new_elements
@@ -1594,7 +1398,8 @@ class Geometry(object):
1594
1398
  append_inner=False,
1595
1399
  append_outer=False,
1596
1400
  delete_appendices=False,
1597
- concatenate_tiny_el=False):
1401
+ concatenate=True,
1402
+ connect=True):
1598
1403
  """ Die Funktion kopiert die Teile von Shape-Objekten, welche sich in
1599
1404
  der durch die Parameter definierten Teilkreisfläche befinden.
1600
1405
  """
@@ -1608,6 +1413,8 @@ class Geometry(object):
1608
1413
  atol = 1e-4
1609
1414
  logger.debug(' -> rtol=%s, atol=%s', rtol, atol)
1610
1415
 
1416
+ self.with_center_node = self.find_the_node(self.center) is not None
1417
+
1611
1418
  if is_same_angle(startangle, endangle):
1612
1419
  start_line = Line(
1613
1420
  Element(start=self.center,
@@ -1695,40 +1502,28 @@ class Geometry(object):
1695
1502
  new_elements.append(arc)
1696
1503
  p1 = p2
1697
1504
 
1698
- if concatenate_tiny_el:
1699
- ok, new_elements = self.concatenate_tiny_elements(new_elements)
1700
- if ok:
1701
- split = True
1702
-
1703
- if delete_appendices:
1704
- center = []
1705
- else:
1706
- center = self.center
1505
+ center = self.center
1707
1506
 
1708
1507
  if split:
1709
1508
  logger.debug('new Geometry with split')
1710
- geom = Geometry(new_elements,
1711
- center=center,
1712
- rtol=self.rtol,
1713
- atol=self.atol,
1714
- is_inner=self.is_inner,
1715
- is_outer=self.is_outer,
1716
- split=split)
1717
- else:
1718
- geom = Geometry(new_elements,
1719
- center=center,
1720
- rtol=self.rtol,
1721
- atol=self.atol,
1722
- is_inner=self.is_inner,
1723
- is_outer=self.is_outer)
1724
-
1725
- if delete_appendices:
1726
- geom.delete_all_appendices()
1727
- geom.set_center(self.center)
1509
+
1510
+ geom = Geometry(new_elements,
1511
+ center=center,
1512
+ rtol=self.rtol,
1513
+ atol=self.atol,
1514
+ is_inner=self.is_inner,
1515
+ is_outer=self.is_outer,
1516
+ concatenate=concatenate,
1517
+ connect=connect,
1518
+ delete=delete_appendices,
1519
+ split=split)
1520
+ geom.with_center_node = self.with_center_node
1521
+
1728
1522
  logger.debug('end copy_shape')
1729
1523
  return geom
1730
1524
 
1731
1525
  def copy_all_elements(self, alpha):
1526
+ logger.debug("begin copy_all_elements(alpha=%s)", alpha)
1732
1527
  if alpha == 0.0:
1733
1528
  T = None
1734
1529
  else:
@@ -1764,19 +1559,25 @@ class Geometry(object):
1764
1559
  el.transform(T, alpha, ndec)
1765
1560
  all_el.append(el)
1766
1561
 
1767
- logger.debug("copy_all_elements: %s lines, %s arcs, %s circles",
1562
+ logger.debug("end copy_all_elements: %s lines, %s arcs, %s circles",
1768
1563
  lines, arcs, circles)
1769
-
1770
1564
  return all_el
1771
1565
 
1772
- def new_clone(self, new_elements, split=False):
1566
+ def new_clone(self, new_elements,
1567
+ split=False,
1568
+ concatenate=False,
1569
+ connect=False,
1570
+ adjust=False):
1773
1571
  return Geometry(new_elements,
1774
1572
  center=self.center,
1775
1573
  rtol=self.rtol,
1776
1574
  atol=self.atol,
1777
1575
  is_inner=self.is_inner,
1778
1576
  is_outer=self.is_outer,
1779
- split=split)
1577
+ split=split,
1578
+ concatenate=concatenate,
1579
+ connect=connect,
1580
+ adjust=adjust)
1780
1581
 
1781
1582
  def is_new_angle(self, alpha_list, alpha):
1782
1583
  for a in alpha_list:
@@ -1784,78 +1585,6 @@ class Geometry(object):
1784
1585
  return False
1785
1586
  return True
1786
1587
 
1787
- def concatenate_arc_elements(self, el, elements):
1788
- if not is_Arc(el):
1789
- return False
1790
-
1791
- def match(e1, e2):
1792
- if e2.has_attribute("del"):
1793
- return False
1794
- if e2.has_attribute("tiny"):
1795
- return False
1796
- if not points_are_close(e1.center, e2.center):
1797
- return False
1798
- return np.isclose(e1.radius, e2.radius)
1799
-
1800
- elmts = [(e.p1, e) for e in elements if is_Arc(e) and match(el, e)]
1801
- elmts.sort()
1802
-
1803
- ok = False
1804
- for p, e in elmts:
1805
- el_new = el.concatenate(None, None, e)
1806
- if el_new:
1807
- el.set_attribute("del")
1808
- e.set_attribute("del")
1809
- elements.append(el_new)
1810
- el = el_new
1811
- ok = True
1812
- return ok
1813
-
1814
- def concatenate_line_elements(self, el, elements):
1815
- if not is_Line(el):
1816
- return False
1817
-
1818
- def match(e1, e2):
1819
- if e2.has_attribute("del"):
1820
- return False
1821
- if e2.has_attribute("tiny"):
1822
- return False
1823
- return np.isclose(e1.m(999999.0), e2.m(999999.0))
1824
-
1825
- elmts = [(e.p1, e) for e in elements if is_Line(e) and match(el, e)]
1826
- elmts.sort()
1827
-
1828
- ok = False
1829
- for p, e in elmts:
1830
- el_new = el.concatenate(None, None, e)
1831
- if el_new:
1832
- el.set_attribute("del")
1833
- e.set_attribute("del")
1834
- elements.append(el_new)
1835
- el = el_new
1836
- ok = True
1837
- return ok
1838
-
1839
- def concatenate_tiny_elements(self, new_elements):
1840
- logger.debug("begin concatenate_tiny_elements")
1841
- tiny_elements = [e for e in new_elements if e.has_attribute("tiny")]
1842
- if not tiny_elements:
1843
- logger.debug("end concatenate_tiny_elements: (%s elements)", 0)
1844
- return False, new_elements
1845
-
1846
- count = 0
1847
- for e_tiny in tiny_elements:
1848
- if is_Line(e_tiny):
1849
- if self.concatenate_line_elements(e_tiny, new_elements):
1850
- count += 1
1851
- elif is_Arc(e_tiny):
1852
- if self.concatenate_arc_elements(e_tiny, new_elements):
1853
- count += 1
1854
-
1855
- new_list = [e for e in new_elements if not e.has_attribute("del")]
1856
- logger.debug("end concatenate_tiny_elements: (%s elements)", count)
1857
- return count>0, new_list
1858
-
1859
1588
  def find_symmetry(self, radius,
1860
1589
  startangle, endangle, sym_tolerance):
1861
1590
  arealist = self.list_of_areas()
@@ -2082,6 +1811,29 @@ class Geometry(object):
2082
1811
  return [h for (k, h) in legend.items()]
2083
1812
  return []
2084
1813
 
1814
+ def render_areagroups(self, renderer):
1815
+ if not self.areagroup_list:
1816
+ return
1817
+ for area in self.areagroup_list:
1818
+ area.render(renderer,
1819
+ color="yellow",
1820
+ fill=False)
1821
+ return
1822
+
1823
+ def render_magnet_phi(self, renderer):
1824
+ magnets = [a for a in self.list_of_areas()]
1825
+ if not magnets:
1826
+ return
1827
+ arrow_len = [a.magnet_arrow_length() for a in magnets]
1828
+ length = max(arrow_len)
1829
+
1830
+ for area in magnets:
1831
+ area.render_magnet_phi(renderer, length)
1832
+
1833
+ def render_critical(self, renderer):
1834
+ for e in self.critical_points:
1835
+ e.render(renderer, 'darkred')
1836
+
2085
1837
  def get_points_in_iron(self):
2086
1838
  points = []
2087
1839
  for area in self.list_of_areas():
@@ -2114,6 +1866,10 @@ class Geometry(object):
2114
1866
  atol = 3.0
2115
1867
 
2116
1868
  logger.debug("*** Begin of get_machine() ***")
1869
+
1870
+ logger.debug(">> minmax: %s", mm)
1871
+ logger.debug(">> w=%s, h=%s", width, height)
1872
+
2117
1873
  if np.isclose(height, width, self.rtol, self.atol):
2118
1874
  radius = width/2
2119
1875
  self.set_center([mm[1]-radius, mm[3]-radius])
@@ -2128,6 +1884,8 @@ class Geometry(object):
2128
1884
  logger.info("check for quarter machine")
2129
1885
  radius = width
2130
1886
  self.set_center([mm[0], mm[2]])
1887
+ logger.debug("-- center = %s, radius min/max = %s/%s",
1888
+ self.center, self.min_radius, self.max_radius)
2131
1889
  if self.check_hull(radius, mm[0], mm[2], self.rtol, atol):
2132
1890
  logger.info(" - it is a quarter")
2133
1891
  return Machine(self,
@@ -2303,7 +2061,7 @@ class Geometry(object):
2303
2061
  m_min = min(m_min, m)
2304
2062
 
2305
2063
  y = line_n([p[0]-center[0], p[1]], m_min)
2306
- center[1] = y
2064
+ center = (center[0], y)
2307
2065
  angle = alpha_line(center, p)
2308
2066
 
2309
2067
  self.set_center([round(center[0], 8), round(center[1], 8)])
@@ -2406,8 +2164,20 @@ class Geometry(object):
2406
2164
  return None
2407
2165
 
2408
2166
  def get_center_arcs(self):
2167
+ logger.debug("begin of get_center_arcs")
2409
2168
  center_list = []
2410
- for e in self.elements(Arc):
2169
+ circles = [e for e in self.elements() if is_Circle(e)]
2170
+ logger.debug(" -- %s Circles", len(circles))
2171
+
2172
+ for e in circles:
2173
+ center = (round(e.center[0], 3), round(e.center[1], 3))
2174
+ radius = round(e.radius, 1)
2175
+ center_list.append(([1], center, [radius]))
2176
+
2177
+ arcs = [e for e in self.elements() if is_Arc(e)]
2178
+ logger.debug(" -- %s Arcs", len(arcs))
2179
+
2180
+ for e in arcs:
2411
2181
  center = (round(e.center[0], 3), round(e.center[1], 3))
2412
2182
  radius = round(e.radius, 1)
2413
2183
  c = self.get_same_center(center_list, center, self.rtol, self.atol)
@@ -2429,6 +2199,8 @@ class Geometry(object):
2429
2199
  c2 = arc_list[1]
2430
2200
  if not c1[0] > c2[0]:
2431
2201
  center = None
2202
+
2203
+ logger.debug("end of get_center_arcs: -> %s", center)
2432
2204
  return center
2433
2205
 
2434
2206
  def get_center_dim(self, mm):
@@ -2487,6 +2259,63 @@ class Geometry(object):
2487
2259
  borders += 1
2488
2260
  return (ok, borders)
2489
2261
 
2262
+ def check_airgap(self, startangle, endangle):
2263
+ logger.debug("begin check_airgap")
2264
+ area_id_list = [a.id for a in self.list_of_areas()]
2265
+
2266
+ def delete_id(id):
2267
+ try:
2268
+ i = area_id_list.index(id)
2269
+ except ValueError:
2270
+ return
2271
+ area_id_list[i] = 0
2272
+ # ---
2273
+ def append_area(alist, a):
2274
+ for my_a in alist:
2275
+ if my_a.is_in_touch_with_area(self, a):
2276
+ alist.append(a)
2277
+ delete_id(a.id)
2278
+ return True
2279
+ return False
2280
+ # ---
2281
+ for area in self.area_list:
2282
+ if not area.id in area_id_list:
2283
+ continue
2284
+
2285
+ for a in self.area_list:
2286
+ if area.id == a.id:
2287
+ continue
2288
+ if not a.id in area_id_list:
2289
+ continue
2290
+
2291
+ if area.the_area_is_inside_area(a):
2292
+ delete_id(a.id)
2293
+
2294
+ # collect remaining areas
2295
+ area_list = [a for a in self.area_list if a.id in area_id_list]
2296
+ group_list = {}
2297
+ for area in area_list:
2298
+ if not area.id in area_id_list:
2299
+ continue
2300
+ group_list[area.id] = [area]
2301
+ delete_id(area.id)
2302
+ for a in self.area_list:
2303
+ if area.id == a.id:
2304
+ continue
2305
+ if not a.id in area_id_list:
2306
+ continue
2307
+ if append_area(group_list[area.id], a):
2308
+ continue
2309
+
2310
+ area_list = [a for a in self.area_list if a.id in area_id_list]
2311
+ for area in area_list:
2312
+ group_list[area.id] = [area]
2313
+
2314
+ area_id_list = [int(x) for x in group_list.keys()]
2315
+
2316
+ logger.debug("end check_airgap: return %s", len(area_id_list) > 1)
2317
+ return len(area_id_list) > 1 # bad
2318
+
2490
2319
  def is_border_line(self, center, startangle, endangle, e, atol):
2491
2320
  if isinstance(e, Line):
2492
2321
  if np.isclose(startangle, endangle):
@@ -2635,6 +2464,49 @@ class Geometry(object):
2635
2464
  # logger.info(" ++ %s", id)
2636
2465
  logger.debug("end set_areas_inside_for_all_areas")
2637
2466
 
2467
+ def set_groups_inside_for_all_areas(self):
2468
+ logger.debug("begin set_groups_inside_for_all_areas")
2469
+
2470
+ groups_inside = {}
2471
+ groups = {}
2472
+ areas_outside = []
2473
+ for area in self.list_of_areas():
2474
+ grouplist = [a for a in self.areagroup_list
2475
+ if area.is_inside(a, self)]
2476
+ if not grouplist:
2477
+ continue
2478
+ groups_inside = {g.id: g for g in grouplist}
2479
+ area.areas_inside = groups_inside
2480
+ areas_outside.append(area)
2481
+ for g in grouplist:
2482
+ alist = groups.get(g.id, [])
2483
+ alist.append(area)
2484
+ groups[g.id] = alist
2485
+
2486
+ outside_id = [a.id for a in areas_outside]
2487
+ logger.debug("Areas outside: %s", outside_id)
2488
+
2489
+ for id in groups.keys():
2490
+ if len(groups[id]) > 1:
2491
+ logger.warning("Attention: nested groups of areas")
2492
+ self.journal.put("warning", "nested groups of areas")
2493
+ areas = groups[id]
2494
+ main_area = areas[0]
2495
+ main_size = main_area.area_size()
2496
+ for a in areas[1:]:
2497
+ sz = a.area_size()
2498
+ if sz < main_size:
2499
+ main_area = a
2500
+ main_size = sz
2501
+ assert(main_area is not None)
2502
+ main_area.is_child = True
2503
+ for area in areas:
2504
+ if area.id != main_area.id:
2505
+ del area.areas_inside[id]
2506
+
2507
+ logger.debug("end set_areas_inside_for_all_areas")
2508
+ return areas_outside
2509
+
2638
2510
  def get_minmax_magnet(self):
2639
2511
  logger.debug("get_minmax_magnet")
2640
2512
  maglist = [a for a in self.list_of_areas() if a.is_magnet()]
@@ -2647,15 +2519,29 @@ class Geometry(object):
2647
2519
 
2648
2520
  def create_auxiliary_lines(self, rightangle, leftangle):
2649
2521
  logger.debug("begin of create_auxiliary_lines")
2650
- self.set_areas_inside_for_all_areas()
2651
-
2652
- logger.debug("-> start create_auxiliary_lines")
2653
-
2522
+ timer = Timer(start_it=True)
2654
2523
  done = False
2655
- for area in self.list_of_areas():
2656
- if self.create_aux_lines(area, rightangle, leftangle):
2657
- done = True
2658
2524
 
2525
+ if True: # new style
2526
+ logger.debug("-> start create_auxiliary_lines")
2527
+ area_list = self.list_of_areas()
2528
+ builder = AreaBuilder(geom=self)
2529
+ builder.create_area_groups(area_list)
2530
+ self.areagroup_list = builder.area_list
2531
+ area_list = self.set_groups_inside_for_all_areas()
2532
+ for area in area_list:
2533
+ if self.create_aux_lines(area, rightangle, leftangle):
2534
+ done = True
2535
+ else:
2536
+ logger.debug("-> start create_auxiliary_lines")
2537
+ self.set_areas_inside_for_all_areas()
2538
+ done = False
2539
+ for area in self.list_of_areas():
2540
+ if self.create_aux_lines(area, rightangle, leftangle):
2541
+ done = True
2542
+
2543
+ t = timer.stop("-- auxiliary lines in %0.4f seconds --")
2544
+ self.journal.put('time_auxiliary_lines', t)
2659
2545
  logger.debug("end of create_auxiliary_lines")
2660
2546
  return done
2661
2547
 
@@ -2664,7 +2550,7 @@ class Geometry(object):
2664
2550
 
2665
2551
  areas_inside = area.areas_inside.values()
2666
2552
  if not areas_inside:
2667
- logger.debug("end create_aux_lines() for %s (no areas inside)",
2553
+ logger.debug("end of create_aux_lines() for %s (no areas inside)",
2668
2554
  area.get_id())
2669
2555
  return False
2670
2556
 
@@ -2672,6 +2558,10 @@ class Geometry(object):
2672
2558
 
2673
2559
  aux_color = 'red'
2674
2560
  aux_linestyle = 'dotted'
2561
+ if area.is_child:
2562
+ logger.debug("Area %s is a child of another nested area", area.id)
2563
+ rightangle = None
2564
+ leftangle = None
2675
2565
 
2676
2566
  areas_border = {a.get_id(): a for a in areas_inside
2677
2567
  if area.has_connection(self, a, ndec)}
@@ -2861,21 +2751,22 @@ class Geometry(object):
2861
2751
  line = aux_line['line']
2862
2752
  n1 = self.find_the_node(aux_line['p1'])
2863
2753
  n2 = self.find_the_node(aux_line['p2'])
2864
- if not (n1 and n2):
2865
- pts = self.split_and_get_intersect_points(line)
2866
- if len(pts) != 2:
2867
- logger.error("ERROR in create_aux_lines()")
2868
- logger.debug("Points: %s", pts)
2869
-
2870
- n1 = self.find_the_node(line.node1(ndec))
2871
- n2 = self.find_the_node(line.node2(ndec))
2754
+ logger.debug("Line: n1=%s, n2=%s", n1, n2)
2755
+
2756
+ pts = self.split_and_get_intersect_points(line)
2757
+ if len(pts) != 2:
2758
+ logger.error("ERROR in create_aux_lines()")
2759
+ logger.debug("Points: %s", pts)
2760
+ logger.debug("Line: %s", line)
2761
+
2762
+ n1 = self.find_the_node(line.node1(ndec))
2763
+ n2 = self.find_the_node(line.node2(ndec))
2764
+ logger.debug("Line: n1=%s, n2=%s", n1, n2)
2872
2765
  if n1 and n2:
2873
- add_or_join(self,
2874
- n1,
2875
- n2,
2876
- aux_line['line'],
2877
- self.rtol,
2878
- self.atol)
2766
+ logger.debug("Create Line %s", aux_line['pattern'])
2767
+ self.add_element(line,
2768
+ rtol=self.rtol,
2769
+ atol=self.atol)
2879
2770
  logger.debug("=== Create auxiliary line: %s", aux_line)
2880
2771
  if aux_line['connect'] == 'child':
2881
2772
  for a in areas_inside:
@@ -2889,7 +2780,7 @@ class Geometry(object):
2889
2780
  logger.debug("end create_aux_lines() for %s (no iron)",
2890
2781
  area.get_id())
2891
2782
  return done
2892
-
2783
+ return done
2893
2784
  # -----------------
2894
2785
  def id_of_inside_area(p):
2895
2786
  for a in areas_inside:
@@ -2925,7 +2816,10 @@ class Geometry(object):
2925
2816
  # ----------
2926
2817
 
2927
2818
  # Arcs as additional auxiliary connections thru iron
2819
+ logger.debug("Additional Lines in %s", area.identifier())
2928
2820
  for a in area_to_parent_list:
2821
+ logger.debug("Area %s in Parent List", a.identifier())
2822
+
2929
2823
  mid_dist = (a.min_dist + a.max_dist) / 2
2930
2824
  mid_angle = (a.min_angle + a.max_angle) / 2
2931
2825
  arc = Arc(Element(center=self.center,
@@ -2949,12 +2843,14 @@ class Geometry(object):
2949
2843
  radius=mid_dist,
2950
2844
  start_angle=start_angle*180/np.pi,
2951
2845
  end_angle=end_angle*180/np.pi),
2952
- color=aux_color,
2846
+ color='black', #aux_color,
2953
2847
  linestyle=aux_linestyle)
2954
2848
  arc.set_attribute('iron_sep')
2955
2849
  self.split_and_get_intersect_points(arc)
2956
2850
  n = self.find_nodes(pts[0], pts[1])
2957
- self.add_edge(n[0], n[1], arc)
2851
+ self.add_or_join_edge(n[0], n[1], arc,
2852
+ rtol=self.rtol,
2853
+ atol=self.atol)
2958
2854
 
2959
2855
  logger.debug("end create_aux_lines() for %s",
2960
2856
  area.get_id())
@@ -3000,53 +2896,99 @@ class Geometry(object):
3000
2896
  dict12['deleted'] = True
3001
2897
  dict01['deleted'] = True
3002
2898
  line = Line(Element(start=n0, end=n2))
3003
- self.add_edge(n0, n2, line)
2899
+ self.add_element(line,
2900
+ rtol=self.rtol,
2901
+ atol=self.atol)
3004
2902
  return True
3005
2903
 
3006
- def delete_tiny_elements(self, mindist):
2904
+ def search_tiny_elements(self, mindist):
2905
+ logger.debug("begin of search_tiny_elements(%s)", mindist)
3007
2906
  if mindist == 0.0:
3008
- return
2907
+ return []
3009
2908
 
3010
2909
  edges = [edge for edge in self.g.edges(data=True)
3011
2910
  if distance(edge[0], edge[1]) < mindist]
3012
- if len(edges) > 0:
3013
- logger.info("mindist=%s: %s tiny elements found",
3014
- mindist, len(edges))
2911
+
2912
+ logger.debug("end of search_tiny_elements: %s tiny elements found",
2913
+ len(edges))
2914
+ return edges
2915
+
2916
+ def delete_tiny_elements(self, mindist):
2917
+ logger.debug("begin of delete_tiny_elements(%s)", mindist)
2918
+ edges = self.search_tiny_elements(mindist)
2919
+ if not edges:
2920
+ logger.debug("-- no tiny elements found")
2921
+ return 0
2922
+
3015
2923
  deleted = 0
3016
2924
  for edge in edges:
3017
- if edge[2].get('deleted', False):
2925
+ n1 = edge[0]
2926
+ n2 = edge[1]
2927
+ el = edge[2]['object']
2928
+ logger.debug("-- %s: %s <-> %s", el.classname(), n1, n2)
2929
+ logger.debug("Edge: %s", el.classname())
2930
+
2931
+ if n1 is n2:
2932
+ logger.debug("-- delete edge with equal nodes")
2933
+ self._remove_edge(n1, n2)
2934
+ deleted += 1
3018
2935
  continue
3019
2936
 
3020
- nbrs_n1 = [nbr for nbr in self.g.neighbors(edge[0])
3021
- if nbr is not edge[1]]
3022
- nbrs_n2 = [nbr for nbr in self.g.neighbors(edge[1])
3023
- if nbr is not edge[0]]
2937
+ nbrs_n1 = [nbr for nbr in self.g.neighbors(n1)
2938
+ if not nodes_are_equal(nbr, n2)]
2939
+ nbrs_n2 = [nbr for nbr in self.g.neighbors(n2)
2940
+ if not nodes_are_equal(nbr, n1)]
2941
+
2942
+ if len(nbrs_n1) == 0 and len(nbrs_n2) == 0:
2943
+ # lonesome edge
2944
+ logger.debug("-- delete lonesome edge")
2945
+ self._remove_edge(n1, n2)
2946
+ deleted += 1
2947
+ continue
3024
2948
 
3025
2949
  if len(nbrs_n1) == 1:
3026
- if self._delete_a_tiny_element(edge[1], edge[0],
3027
- edge[2], nbrs_n1[0]):
2950
+ if self._delete_a_tiny_element(n2, n1, edge[2], nbrs_n1[0]):
3028
2951
  deleted += 1
3029
2952
  continue
3030
2953
 
3031
2954
  if len(nbrs_n2) == 1:
3032
- if self._delete_a_tiny_element(edge[0], edge[1],
3033
- edge[2], nbrs_n2[0]):
2955
+ if self._delete_a_tiny_element(n1, n2, edge[2], nbrs_n2[0]):
3034
2956
  deleted += 1
3035
2957
  continue
3036
2958
 
3037
2959
  if deleted:
3038
- logger.info("%s tiny elements deleted", deleted)
3039
- return
2960
+ logger.debug("%s tiny elements deleted", deleted)
2961
+ self.journal.put("tiny_elements_deleted", deleted)
2962
+ logger.debug("end of delete_tiny_elements")
2963
+ return deleted
2964
+
2965
+ def search_critical_elements(self, mindist):
2966
+ for n in self.g.nodes():
2967
+ nbrs = self.get_neighbors(n)
2968
+ if len(nbrs) < 3:
2969
+ continue
2970
+ critical_point = False
2971
+ critical_dist = 9999
2972
+ for nbr in nbrs:
2973
+ e = self.get_edge_element(n, nbr)
2974
+ if e.is_tiny(mindist):
2975
+ critical_point = True
2976
+ critical_dist = min(critical_dist, e.length())
2977
+ if critical_point:
2978
+ logger.debug("Warning: maybe critical point %s", n)
2979
+ self.journal.put("maybe_critical_points", (n, critical_dist))
2980
+ c = Circle(Element(center=n, radius=1))
2981
+ self.critical_points.append(c)
3040
2982
 
3041
2983
  def check_shaft_area(self, shaft):
3042
2984
  for a in self.list_of_areas():
3043
2985
  if not shaft.is_identical(a):
3044
2986
  if shaft.is_inside(a, self):
3045
- shaft.type = 6 # iron shaft (Zahn)
2987
+ shaft.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3046
2988
  return
3047
2989
  if shaft.is_touching(a):
3048
2990
  if not a.is_iron():
3049
- shaft.type = 6 # iron shaft (Zahn)
2991
+ shaft.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3050
2992
  return
3051
2993
 
3052
2994
  def mark_connecting_edges(self, windings):
@@ -3060,18 +3002,19 @@ class Geometry(object):
3060
3002
  for e in elist:
3061
3003
  e.init_attributes('lightblue', 'no_fsl')
3062
3004
 
3063
- def search_subregions(self):
3005
+ def search_subregions(self, startangle, endangle, single=False):
3064
3006
  if self.is_stator():
3065
- self.search_stator_subregions()
3007
+ self.search_stator_subregions(startangle, endangle, single=single)
3066
3008
  elif self.is_rotor():
3067
- self.search_rotor_subregions()
3009
+ self.search_rotor_subregions(startangle, endangle, single=single)
3068
3010
  else:
3069
3011
  logger.warning("no stator or rotor assigned")
3070
3012
  self.search_unknown_subregions()
3071
3013
  self.looking_for_corners()
3072
3014
 
3073
3015
  def get_windings(self, type):
3074
- windings = [a for a in self.list_of_areas() if a.type == type]
3016
+ windings = [a for a in self.list_of_areas()
3017
+ if a.is_type(type)]
3075
3018
  for w in windings:
3076
3019
  inside = []
3077
3020
  for a in self.list_of_areas():
@@ -3079,13 +3022,14 @@ class Geometry(object):
3079
3022
  if w.is_inside(a, self):
3080
3023
  inside.append(a)
3081
3024
  if inside:
3082
- w.set_type(0) # air
3083
- return [a for a in self.list_of_areas() if a.type == type]
3025
+ w.set_type(AREA.TYPE_AIR) # air
3026
+ return [a for a in self.list_of_areas()
3027
+ if a.is_type(type)]
3084
3028
 
3085
3029
  def collect_windings(self):
3086
3030
  logger.debug("begin of collect_windings")
3087
- good_windings = self.get_windings(2)
3088
- ugly_windings = self.get_windings(12)
3031
+ good_windings = self.get_windings(AREA.TYPE_WINDINGS)
3032
+ ugly_windings = self.get_windings(AREA.TYPE_WINDINGS_OR_AIR)
3089
3033
 
3090
3034
  logger.debug("-- %s good and %s ugly windings",
3091
3035
  len(good_windings),
@@ -3097,8 +3041,8 @@ class Geometry(object):
3097
3041
 
3098
3042
  if not good_windings:
3099
3043
  logger.debug("#2 end of collect_windings: %s windings", len(ugly_windings))
3100
- [w.set_type(2) for w in ugly_windings]
3101
- return [a for a in self.list_of_areas() if a.type == 2]
3044
+ [w.set_type(AREA.TYPE_WINDINGS) for w in ugly_windings]
3045
+ return [a for a in self.list_of_areas() if a.is_type(AREA.TYPE_WINDINGS)]
3102
3046
 
3103
3047
  # ggod and ugly windings available
3104
3048
  found = True
@@ -3106,27 +3050,28 @@ class Geometry(object):
3106
3050
  found = False
3107
3051
  for a in ugly_windings:
3108
3052
  if a.is_touching_areas(good_windings):
3109
- a.set_type(2)
3053
+ a.set_type(AREA.TYPE_WINDINGS)
3110
3054
  found = True
3111
3055
 
3112
- good_windings = [a for a in self.list_of_areas() if a.type == 2]
3113
- ugly_windings = [a for a in self.list_of_areas() if a.type == 12]
3056
+ good_windings = [a for a in self.list_of_areas()
3057
+ if a.is_type(AREA.TYPE_WINDINGS)]
3058
+ ugly_windings = [a for a in self.list_of_areas()
3059
+ if a.is_type(AREA.TYPE_WINDINGS_OR_AIR)]
3114
3060
 
3115
- [w.set_type(0) for w in ugly_windings]
3116
- good_windings = [a for a in self.list_of_areas() if a.type == 2]
3061
+ [w.set_type(AREA.TYPE_AIR) for w in ugly_windings]
3062
+ good_windings = [a for a in self.list_of_areas()
3063
+ if a.is_type(AREA.TYPE_WINDINGS)]
3117
3064
 
3118
- logger.debug("return %s bad windings as good windings", len(good_windings))
3065
+ logger.debug("return bad and ugly windings as %s good windings", len(good_windings))
3119
3066
  logger.debug("end of collect_windings")
3120
3067
  return good_windings
3121
3068
 
3122
- def search_stator_subregions(self, place=''):
3069
+ def search_stator_subregions(self,
3070
+ startangle,
3071
+ endangle,
3072
+ single=False):
3123
3073
  logger.debug("Begin of search_stator_subregions")
3124
3074
 
3125
- if place == 'in':
3126
- self.is_inner = True
3127
- elif place == 'out':
3128
- self.is_inner = False
3129
-
3130
3075
  if self.alfa == 0.0:
3131
3076
  self.alfa = np.pi * 2.0
3132
3077
 
@@ -3141,18 +3086,20 @@ class Geometry(object):
3141
3086
  self.max_radius)
3142
3087
 
3143
3088
  windings = self.collect_windings()
3144
- [a.set_type(0) for a in self.list_of_areas() if a.type == 12]
3089
+ [a.set_type(AREA.TYPE_AIR) for a in self.list_of_areas()
3090
+ if a.is_type(AREA.TYPE_WINDINGS_OR_AIR)]
3145
3091
  windings_found = len(windings)
3146
3092
  logger.debug("%d windings found", windings_found)
3093
+ self.has_windings = windings_found > 0
3147
3094
 
3148
3095
  if windings_found > 1:
3149
3096
  windings_surface = [[w.surface, w] for w in windings]
3150
3097
  windings_surface.sort(reverse=True)
3151
- max_size = windings_surface[0][0]
3152
- for sz, w in windings_surface:
3098
+ max_size, max_w = windings_surface[0]
3099
+ for sz, w in windings_surface[1:]:
3153
3100
  logger.debug("winding size = %s", sz)
3154
- if sz / max_size < 0.95:
3155
- w.set_type(0)
3101
+ if sz / max_size < 0.80:
3102
+ w.set_type(AREA.TYPE_AIR)
3156
3103
  if sz / max_size < 0.2:
3157
3104
  windings_found -= 1
3158
3105
  windings = [a for a in self.list_of_areas()
@@ -3160,8 +3107,9 @@ class Geometry(object):
3160
3107
  if windings_found > 2 and len(windings) == 1:
3161
3108
  logger.info("no windings remaining")
3162
3109
  # no windings
3163
- [w.set_type(0) for w in windings]
3164
- [a.set_type(1) for a in self.list_of_areas() if a.is_iron()]
3110
+ [w.set_type(AREA.TYPE_AIR) for w in windings]
3111
+ [a.set_type(AREA.TYPE_IRON) for a in self.list_of_areas()
3112
+ if a.is_iron()]
3165
3113
  windings = []
3166
3114
  elif len(windings) < windings_found:
3167
3115
  logger.info("%d windings remaining", len(windings))
@@ -3197,7 +3145,8 @@ class Geometry(object):
3197
3145
  self.wdg_is_mirrored = False
3198
3146
 
3199
3147
  # air or iron near windings and near airgap ?
3200
- air_areas = [a for a in self.list_of_areas() if a.type == 9]
3148
+ air_areas = [a for a in self.list_of_areas()
3149
+ if a.is_type(AREA.TYPE_AIR_OR_IRON)]
3201
3150
  for a in air_areas:
3202
3151
  if a.around_windings(windings, self):
3203
3152
  logger.debug("Area %s", a.identifier())
@@ -3211,7 +3160,7 @@ class Geometry(object):
3211
3160
  if a.close_to_startangle:
3212
3161
  if not wdg_close_to_startangle:
3213
3162
  logger.debug("#0.1 ===> close to startangle")
3214
- a.type = 6 # iron shaft (Zahn)
3163
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3215
3164
  continue
3216
3165
 
3217
3166
  if a.close_to_endangle:
@@ -3219,10 +3168,10 @@ class Geometry(object):
3219
3168
  logger.debug("#0.2 ===> close to endangle")
3220
3169
  if(a.min_angle < wdg_min_angle and
3221
3170
  a.close_to_ag):
3222
- a.type = 0 # air
3171
+ a.set_type(AREA.TYPE_AIR) # air
3223
3172
  continue
3224
3173
 
3225
- a.type = 6 # iron shaft (Zahn)
3174
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3226
3175
  continue
3227
3176
 
3228
3177
  if greater_equal(a.min_air_angle, wdg_min_angle):
@@ -3232,53 +3181,54 @@ class Geometry(object):
3232
3181
 
3233
3182
  if a.close_to_endangle and self.is_mirrored():
3234
3183
  logger.debug("#1 ===> endangle and mirrored <===")
3235
- a.type = 0 # air
3184
+ a.set_type(AREA.TYPE_AIR) # air
3236
3185
  elif less_equal(a.max_air_angle, wdg_max_angle):
3237
3186
  logger.debug("#2 ===> %s <= %s <===",
3238
3187
  a.max_air_angle,
3239
3188
  wdg_max_angle)
3240
- a.type = 0 # air
3189
+ a.set_type(AREA.TYPE_AIR) # air
3241
3190
  else:
3242
3191
  logger.debug("#3 ===> %s > %s <===",
3243
3192
  a.max_air_angle,
3244
3193
  wdg_max_angle)
3245
- a.type = 6 # iron shaft (Zahn)
3194
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3246
3195
  else:
3247
3196
  logger.debug("#4 ===> %s < %s <===",
3248
3197
  a.min_air_angle,
3249
3198
  wdg_min_angle)
3250
- a.type = 6 # iron shaft (Zahn)
3199
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3251
3200
  else:
3252
3201
  logger.debug("#5 not around windings")
3253
- a.type = 6 # iron shaft (Zahn)
3202
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3254
3203
 
3255
3204
  # yoke or shaft ?
3256
- iron_areas = [a for a in self.list_of_areas() if a.type == 5]
3205
+ iron_areas = [a for a in self.list_of_areas()
3206
+ if a.is_type(AREA.TYPE_YOKE)]
3257
3207
  for a in iron_areas:
3258
3208
  if a.around_windings(windings, self):
3259
3209
  if less(a.min_dist, wdg_max_dist):
3260
3210
  if less_equal(a.max_dist, wdg_max_dist):
3261
- a.type = 6 # iron shaft (Zahn)
3211
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3262
3212
  else:
3263
3213
  dist_low = wdg_max_dist - a.min_dist
3264
3214
  dist_up = a.max_dist - wdg_max_dist
3265
3215
  if dist_low > dist_up:
3266
- a.type = 6 # iron shaft (Zahn)
3216
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3267
3217
 
3268
- shaft_areas = [a for a in self.list_of_areas() if a.type == 10]
3218
+ shaft_areas = [a for a in self.list_of_areas()
3219
+ if a.is_type(AREA.TYPE_SHAFT)]
3269
3220
  if shaft_areas:
3270
3221
  if len(shaft_areas) > 1:
3271
- logger.warn("More than two shafts ?!?")
3222
+ logger.debug("More than one shaft in stator ?!?")
3272
3223
  return
3273
3224
  self.check_shaft_area(shaft_areas[0])
3225
+ logger.debug("End of search_stator_subregions")
3274
3226
 
3275
- def search_rotor_subregions(self, place=''):
3276
- logger.info("Begin of search_rotor_subregions")
3277
-
3278
- if place == 'in':
3279
- self.is_inner = True
3280
- elif place == 'out':
3281
- self.is_inner = False
3227
+ def search_rotor_subregions(self,
3228
+ startangle,
3229
+ endangle,
3230
+ single=False):
3231
+ logger.debug("Begin of search_rotor_subregions")
3282
3232
 
3283
3233
  if self.alfa == 0.0:
3284
3234
  self.alfa = np.pi * 2.0
@@ -3290,20 +3240,65 @@ class Geometry(object):
3290
3240
  self.alfa,
3291
3241
  self.center,
3292
3242
  self.min_radius,
3293
- self.max_radius)
3243
+ self.max_radius,
3244
+ startangle,
3245
+ endangle)
3294
3246
  if t in types:
3295
3247
  types[t] += 1
3296
3248
  else:
3297
3249
  types[t] = 1
3298
3250
 
3299
- if 10 in types:
3251
+ if AREA.TYPE_SHAFT in types:
3300
3252
  logger.debug("Shaft is available")
3301
3253
 
3302
- if 4 in types: # magnet rectangle
3303
- if types[4] > 1:
3304
- logger.debug("%s embedded magnets in rotor", types[4])
3254
+ if AREA.TYPE_MAGNET_RECT_NEAR_AIRGAP in types: # magnet rectangle near ag
3255
+ if AREA.TYPE_MAGNET_RECT in types: # magnet rectangle
3256
+ mag_rectangles = [a for a in self.list_of_areas()
3257
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3258
+ for a in mag_rectangles:
3259
+ if self.is_inner:
3260
+ dist_1 = a.max_dist + 0.5
3261
+ dist_2 = self.max_radius + 5
3262
+ else:
3263
+ dist_1 = a_min_dist - 0.5
3264
+ dist_2 = self.min_radius - 5
3265
+
3266
+ mid_angle = a.get_mid_angle(self.center)
3267
+ p1 = point(self.center, dist_1, mid_angle)
3268
+ p2 = point(self.center, dist_2, mid_angle)
3269
+ line = Line(Element(start=p1, end=p2))
3270
+ logger.debug("magnet intersect line: %s to %s", p1, p2)
3271
+ pts = self.split_and_get_intersect_points(line,
3272
+ aktion=False,
3273
+ include_end=False)
3274
+ logger.debug("magnet intersect points: %s", pts)
3275
+ if not pts:
3276
+ a.set_type(AREA.TYPE_MAGNET_UNDEFINED)
3277
+ mag_rectangles = [a for a in self.list_of_areas()
3278
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3279
+ if mag_rectangles: # undo
3280
+ logger.debug("--- undo ---")
3281
+ [a.set_type(AREA.TYPE_MAGNET_RECT) for a in self.list_of_areas()
3282
+ if a.is_type(AREA.TYPE_MAGNET_UNDEFINED)]
3283
+ else:
3284
+ logger.debug("--- set type 3 ---")
3285
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in self.list_of_areas()
3286
+ if a.is_type(AREA.TYPE_MAGNET_RECT_NEAR_AIRGAP)]
3287
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in self.list_of_areas()
3288
+ if a.is_type(AREA.TYPE_MAGNET_UNDEFINED)]
3289
+ types.pop(AREA.TYPE_MAGNET_RECT)
3290
+ else:
3291
+ # set magnet
3292
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in self.list_of_areas()
3293
+ if a.is_type(AREA.TYPE_MAGNET_RECT_NEAR_AIRGAP)]
3294
+ types[AREA.TYPE_MAGNET_RECT_NEAR_AIRGAP] = 0
3295
+
3296
+ if AREA.TYPE_MAGNET_RECT in types: # magnet rectangle
3297
+ if types[AREA.TYPE_MAGNET_RECT] > 1:
3298
+ logger.debug("%s embedded magnets in rotor",
3299
+ types[AREA.TYPE_MAGNET_RECT])
3305
3300
  emb_mag_areas = [a for a in self.list_of_areas()
3306
- if a.type == 4]
3301
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3307
3302
  [a.set_surface(self.is_mirrored()) for a in emb_mag_areas]
3308
3303
  max_surface = 0.0
3309
3304
  max_phi = 0.0
@@ -3315,30 +3310,34 @@ class Geometry(object):
3315
3310
  for a in emb_mag_areas:
3316
3311
  if a.surface < max_surface * 0.20: # too small
3317
3312
  logger.debug(
3318
- "embedded magnet too small: convert to air")
3313
+ "embedded magnet %s too small: convert to air",
3314
+ a.identifier())
3319
3315
  logger.debug("max surface : %s", max_surface)
3320
3316
  logger.debug("area surface: %s", a.surface)
3321
3317
  logger.debug("max phi : %s", max_phi)
3322
3318
  logger.debug("area phi : %s", a.phi)
3323
3319
  if not np.isclose(a.phi, max_phi):
3324
- a.set_type(0) # air
3320
+ a.set_type(AREA.TYPE_AIR) # air
3325
3321
 
3326
3322
  # set iron
3327
- [a.set_type(1) for a in self.list_of_areas() if a.type == 3]
3323
+ [a.set_type(AREA.TYPE_IRON) for a in self.list_of_areas()
3324
+ if a.is_type(AREA.TYPE_MAGNET_AIRGAP)]
3328
3325
 
3329
- iron_mag_areas = [a for a in self.list_of_areas() if a.type == 9]
3330
- air_mag_areas = [a for a in self.list_of_areas() if a.type == 8]
3326
+ iron_mag_areas = [a for a in self.list_of_areas()
3327
+ if a.is_type(AREA.TYPE_MAGNET_OR_IRON)]
3328
+ air_mag_areas = [a for a in self.list_of_areas()
3329
+ if a.is_type(AREA.TYPE_MAGNET_OR_AIR)]
3331
3330
  ag_areas = [a for a in self.list_of_areas() if a.close_to_ag]
3332
3331
  if len(ag_areas) == 1:
3333
3332
  if len(iron_mag_areas) == 1:
3334
- [a.set_type(3) for a in iron_mag_areas]
3333
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in iron_mag_areas]
3335
3334
  iron_mag_areas = []
3336
3335
  if len(air_mag_areas) == 1:
3337
- [a.set_type(3) for a in air_mag_areas]
3336
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in air_mag_areas]
3338
3337
  air_mag_areas = []
3339
3338
 
3340
- [a.set_type(1) for a in iron_mag_areas]
3341
- [a.set_type(0) for a in air_mag_areas]
3339
+ [a.set_type(AREA.TYPE_IRON) for a in iron_mag_areas]
3340
+ [a.set_type(AREA.TYPE_AIR) for a in air_mag_areas]
3342
3341
 
3343
3342
  if self.is_mirrored():
3344
3343
  mid_alfa = round(self.alfa, 3)
@@ -3348,44 +3347,64 @@ class Geometry(object):
3348
3347
  mag_areas = [[abs(round(a.phi, 3) - mid_alfa),
3349
3348
  a.id,
3350
3349
  a] for a in self.list_of_areas()
3351
- if a.type == 4]
3352
- if len(mag_areas) > 2:
3353
- mag_areas.sort()
3354
- mag_phi = {}
3355
- phi_prev = mag_areas[0][0]
3356
- phi_curr = phi_prev
3357
-
3358
- for phi, id, a in mag_areas:
3359
- # group around mid_alfa
3360
- if phi > phi_prev + 0.33:
3361
- phi_curr = phi
3362
-
3363
- phi_prev = phi
3364
- x = mag_phi.get(phi_curr, [0, []])
3365
- x[0] += 1
3366
- x[1].append(a)
3367
- mag_phi[phi_curr] = x
3368
-
3369
- phi_list = [[l[0], p, l[1]] for p, l in mag_phi.items()]
3370
- phi_list.sort(reverse=True)
3371
- if len(phi_list) > 1:
3372
- c0 = phi_list[0][0]
3373
- c1 = phi_list[1][0]
3374
- first = 1
3375
- if c0 == c1:
3376
- first = 2
3377
-
3378
- for c, phi, a_lst in phi_list[first:]:
3379
- [a.set_type(0) for a in a_lst]
3380
-
3381
- shaft_areas = [a for a in self.list_of_areas() if a.type == 10]
3350
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3351
+
3352
+ shaft_areas = [a for a in self.list_of_areas()
3353
+ if a.is_type(AREA.TYPE_SHAFT)]
3382
3354
  if shaft_areas:
3383
3355
  if len(shaft_areas) > 1:
3384
- logger.warn("More than two shafts ?!?")
3356
+ logger.debug("More than one shaft in rotor ?!?")
3385
3357
  return
3386
3358
  self.check_shaft_area(shaft_areas[0])
3387
3359
 
3388
- logger.info("end of search_rotor_subregions")
3360
+ magnets = [a for a in self.list_of_areas()
3361
+ if a.is_magnet()]
3362
+ self.has_magnets = len(magnets) > 0
3363
+ for m in magnets:
3364
+ m.phi = m.get_magnet_orientation()
3365
+ logger.debug("%s magnets found in rotor", len(magnets))
3366
+
3367
+ if not single:
3368
+ if not magnets:
3369
+ [a.set_type(AREA.TYPE_AIR) for a in self.list_of_areas()]
3370
+ self.search_stator_subregions(startangle, endangle, single=single)
3371
+ return
3372
+
3373
+ logger.debug("end of search_rotor_subregions")
3374
+
3375
+ def recalculate_magnet_orientation(self):
3376
+ logger.debug("begin of recalculate_magnet_orientation")
3377
+ magnet_areas = [a for a in self.list_of_areas()
3378
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3379
+ self.recalculate_magnet_group(magnet_areas)
3380
+
3381
+ magnet_areas = [a for a in self.list_of_areas()
3382
+ if a.is_type(AREA.TYPE_MAGNET_AIRGAP)]
3383
+ for a in magnet_areas:
3384
+ a.phi = a.get_magnet_orientation()
3385
+ logger.debug("end of recalculate_magnet_orientation")
3386
+
3387
+ def recalculate_magnet_group(self, areas):
3388
+ if not areas:
3389
+ return
3390
+ elements = []
3391
+ for a in areas:
3392
+ elements += a.elements()
3393
+ geom = Geometry(elements, center=self.center)
3394
+ builder = AreaBuilder(geom=geom)
3395
+ if builder.create_area_groups(areas):
3396
+ return # bad
3397
+ group_list = builder.area_list
3398
+ # for debugging
3399
+ # self.areagroup_list = group_list
3400
+ for group in group_list:
3401
+ if not group.is_magnet_rectangle():
3402
+ logger.debug("Warning: group is not a rectangle")
3403
+ group.set_type(AREA.TYPE_MAGNET_RECT)
3404
+ phi = group.get_magnet_orientation()
3405
+ for a in group.areas_of_group:
3406
+ logger.debug("Replace phi %s by %s", a.phi, phi)
3407
+ a.phi = phi
3389
3408
 
3390
3409
  def search_unknown_subregions(self):
3391
3410
  logger.debug("begin of search_unknown_subregions")
@@ -3401,22 +3420,31 @@ class Geometry(object):
3401
3420
  else:
3402
3421
  types[t] = 1
3403
3422
 
3404
- if 4 in types: # magnet rectangle
3405
- if types[4] > 1:
3406
- logger.debug("%s embedded magnets in rotor", types[4])
3407
- emb_mag_areas = [a for a in self.list_of_areas()
3408
- if a.type == 4]
3409
- [a.set_surface(self.is_mirrored()) for a in emb_mag_areas]
3410
- max_surface = 0.0
3411
- for a in emb_mag_areas:
3412
- max_surface = max(max_surface, a.surface)
3423
+ if types.get(AREA.TYPE_MAGNET_RECT, 0) > 1:
3424
+ logger.debug("%s embedded magnets in rotor",
3425
+ types[AREA.TYPE_MAGNET_RECT])
3426
+ emb_mag_areas = [a for a in self.list_of_areas()
3427
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3428
+ [a.set_surface(self.is_mirrored()) for a in emb_mag_areas]
3429
+ max_surface = 0.0
3430
+ for a in emb_mag_areas:
3431
+ max_surface = max(max_surface, a.surface)
3413
3432
 
3414
- for a in emb_mag_areas:
3415
- if a.surface < max_surface * 0.20: # too small
3416
- a.set_type(0) # air
3433
+ for a in emb_mag_areas:
3434
+ if a.surface < max_surface * 0.20: # too small
3435
+ a.set_type(AREA.TYPE_AIR) # air
3417
3436
 
3418
3437
  logger.debug("end of search_unknown_subregions")
3419
3438
 
3439
+ def magnets_in_the_middle(self, midangle):
3440
+ mag_areas = [a for a in self.list_of_areas()
3441
+ if a.is_magnet()]
3442
+ logger.debug("%s magnets in geom", len(mag_areas))
3443
+ for a in mag_areas:
3444
+ if a.max_angle > midangle and a.min_angle < midangle:
3445
+ return True
3446
+ return False
3447
+
3420
3448
  def looking_for_corners(self):
3421
3449
  if self.is_inner:
3422
3450
  logger.debug("looking_for_corners: inner")
@@ -3434,14 +3462,14 @@ class Geometry(object):
3434
3462
 
3435
3463
  def num_areas_of_type(self, type):
3436
3464
  return len([area for area in self.list_of_areas()
3437
- if area.type == type])
3465
+ if area.is_type(type)])
3438
3466
 
3439
3467
  def num_of_windings(self):
3440
- return self.num_areas_of_type(2)
3468
+ return self.num_areas_of_type(AREA.TYPE_WINDINGS)
3441
3469
 
3442
3470
  def area_close_to_endangle(self, type):
3443
3471
  return len([area for area in self.list_of_areas()
3444
- if area.type == type and area.close_to_endangle])
3472
+ if area.is_type(type) and area.close_to_endangle])
3445
3473
 
3446
3474
  def corners_dont_match(self):
3447
3475
  if self.is_mirrored():
@@ -3460,7 +3488,7 @@ class Geometry(object):
3460
3488
  return True
3461
3489
  return False
3462
3490
 
3463
- def search_appendices(self):
3491
+ def get_appendices(self):
3464
3492
  c = 0
3465
3493
  end_nodes = []
3466
3494
  for n in self.g.nodes():
@@ -3473,154 +3501,202 @@ class Geometry(object):
3473
3501
 
3474
3502
  if not is_Circle(el):
3475
3503
  end_nodes.append((n, nbrs[0], el))
3504
+ return end_nodes
3505
+
3506
+ def connect_all_nodes(self,
3507
+ additional_nodes=[],
3508
+ rtol=1e-04, atol=1e-04,
3509
+ main=False):
3510
+ logger.debug("begin of connect_all_nodes")
3511
+ timer = Timer(start_it=True)
3512
+ nodes_list = self.get_nodes()
3513
+ c1 = 0
3514
+ c2 = 0
3515
+ additional_nodes_list = []
3516
+ for n in additional_nodes:
3517
+ if not n in nodes_list:
3518
+ additional_nodes_list.append(n)
3519
+ c1 += 1
3520
+ else:
3521
+ c2 += 1
3522
+ logger.debug("connect_all_nodes: %s added, %s already available", c1, c2)
3523
+
3524
+ corr = self.connect_nodes(nodes_list,
3525
+ rtol=rtol, atol=atol)
3526
+ if additional_nodes_list:
3527
+ corr += self.connect_nodes(additional_nodes_list,
3528
+ omit_single_element=True,
3529
+ rtol=rtol, atol=atol)
3530
+ t = timer.stop("-- {} connections in %0.4f seconds --".format(corr))
3531
+ if main:
3532
+ self.journal.put_nodes_connected(corr)
3533
+ self.journal.put('time_node_connections', t)
3534
+ logger.debug("==> %s nodes connected", corr)
3535
+ logger.debug("end of connect_all_nodes")
3536
+ return corr
3537
+
3538
+ def connect_nodes(self, nodes_list,
3539
+ rtol=1e-03, atol=1e-03,
3540
+ omit_single_element=False,
3541
+ ignore_end=False):
3542
+ logger.debug("begin of connect_nodes(rtol=%s, atol=%s)", rtol, atol)
3543
+ logger.debug("-- %s nodes exist", len(nodes_list))
3476
3544
 
3477
- for n0, n1, el in end_nodes:
3478
- logger.debug("Critical Node at %s", n0)
3479
- if self.node_connected(n0):
3480
- c += 1
3545
+ count = 0
3546
+ for n in nodes_list:
3547
+ if self.node_connected(n,
3548
+ rtol=rtol, atol=atol,
3549
+ omit_single_element=omit_single_element,
3550
+ ignore_end=ignore_end):
3551
+ count += 1
3552
+
3553
+ logger.debug("end of connect_nodes => %s", count)
3554
+ return count
3555
+
3556
+ def connect_all_appendices(self, rtol=1e-04, atol=1e-04, main=False):
3557
+ logger.debug("begin of connect_all_appendices")
3558
+ timer = Timer(start_it=True)
3559
+ appendix_list = self.get_appendices()
3560
+ before = len(appendix_list)
3561
+ if main:
3562
+ self.journal.put_appendices(len(appendix_list))
3563
+ corr = self.connect_appendices(appendix_list, rtol=rtol, atol=atol)
3564
+ corr_total = corr
3565
+
3566
+ if corr < before:
3567
+ appendix_list = self.get_appendices()
3568
+ before = len(appendix_list)
3569
+ corr = self.connect_appendices(appendix_list, rtol=rtol, atol=atol)
3570
+ corr_total += corr
3571
+ t = timer.stop("-- {} connections in %0.4f seconds --".format(corr))
3572
+ if main:
3573
+ self.journal.put_appendices_connected(corr_total)
3574
+ self.journal.put('time_app_connections', t)
3575
+
3576
+ logger.debug("==> %s appendices connected", corr_total)
3577
+ logger.debug("end of connect_all_appendices")
3578
+ return corr_total
3579
+
3580
+ def connect_appendices(self, appendix_list, rtol=1e-03, atol=1e-03, ignore_end=False):
3581
+ logger.debug("begin of connect_appendices(rtol=%s, atol=%s)", rtol, atol)
3582
+ logger.debug("-- %s appendices exist", len(appendix_list))
3583
+ self.fixed_appendices = []
3584
+
3585
+ count = 0
3586
+ for n0, n1, el in appendix_list:
3587
+ logger.debug("Appendix Node at %s", n0)
3588
+ if n0 in self.fixed_appendices:
3589
+ logger.debug(" - Node already fixed")
3481
3590
  else:
3482
- nn = self.find_node(n0)
3483
- if nn:
3484
- logger.debug("Node %s is near %s", n0, nn)
3485
- try:
3486
- self._remove_edge(n0, n1)
3487
- self.add_edge(nn, n1, el)
3488
- except Exception:
3489
- logger.debug("delete of %s - %s failed", n0, n)
3490
- logger.debug("Element %s", el)
3491
- return c
3591
+ count += self.connect_appendix(n0, n1, el,
3592
+ rtol=rtol, atol=atol,
3593
+ ignore_end=ignore_end)
3492
3594
 
3493
- def delete_appendices(self):
3494
- c = 0
3495
- end_nodes = []
3496
- for n in self.g.nodes():
3497
- nbrs = [nbr for nbr in self.g.neighbors(n)]
3498
- if len(nbrs) == 1:
3499
- end_nodes.append((n, nbrs[0]))
3595
+ self.fixed_appendices = []
3500
3596
 
3501
- for n0, n1 in end_nodes:
3502
- logger.debug("Deadend Node at %s", n0)
3503
- c += self.remove_appendix(n0, n1)
3504
- return c
3597
+ logger.debug("end of connect_appendices => %s", count)
3598
+ return count
3505
3599
 
3506
- def search_all_overlapping_elements(self):
3507
- logger.debug("begin of search_all_overlapping_elements")
3508
- c = 1
3509
- corr = 0
3510
- while c > 0:
3511
- c = self.search_overlapping_elements()
3512
- corr += c
3513
- logger.debug("==> %s corrections performed", corr)
3514
- logger.debug("end of search_all_overlapping_elements")
3515
-
3516
- def search_all_appendices(self):
3517
- logger.debug("begin of search_all_appendices")
3518
- corr = self.search_appendices()
3519
- logger.debug("==> %s appendices connected", corr)
3520
- logger.debug("end of search_all_appendices")
3600
+ def connect_appendix(self, n0, n1, el, rtol=1e-03, atol=1e-03, ignore_end=False):
3601
+ logger.debug("begin of connect_appendix(%s, rtol=%s, atol=%s)", n0, rtol, atol)
3521
3602
 
3522
- def delete_all_appendices(self):
3523
- logger.debug("begin of delete_all_appendices")
3524
- corr = self.delete_appendices()
3525
- logger.debug("==> %s appendices removed", corr)
3526
- logger.debug("end of delete_all_appendices")
3603
+ if points_are_close(n0, n1, rtol=1e-04, atol=1e-04):
3604
+ # a very tiny appendix
3605
+ d = distance(n0, n1)
3606
+ if less(d, 0.001):
3607
+ logger.debug("-- WARNING: a very tiny appendix of length %s", d)
3608
+ nbr_list = [nbr for nbr in self.g.neighbors(n1)
3609
+ if not nodes_are_equal(nbr, n0)]
3527
3610
 
3528
- def search_overlapping_elements(self):
3529
- logger.debug("begin of search_overlapping_elements")
3530
- count = 0
3611
+ if len(nbr_list) == 0:
3612
+ logger.debug("end of connect_appendix: => lonesome appendix -> no action")
3613
+ return 0
3531
3614
 
3532
- for n in self.g.nodes():
3533
- nbrs = [nbr for nbr in self.g.neighbors(n)]
3534
- if len(nbrs) < 3:
3535
- continue
3536
- logger.debug(" Node %s has %s neighbors", n, len(nbrs))
3537
- edges = []
3538
- for nbr in nbrs:
3539
- e_dict = self.g.get_edge_data(n, nbr)
3540
- if not e_dict:
3541
- break
3542
- e = e_dict.get('object', None)
3543
- if not e:
3544
- break
3545
- edges.append([nbr, e])
3615
+ logger.debug(" remove it")
3616
+ self._remove_edge(n0, n1)
3617
+ return 1
3546
3618
 
3547
- if not edges:
3548
- continue
3619
+ if self.node_connected(n0, rtol=rtol, atol=atol, ignore_end=ignore_end):
3620
+ logger.debug("end of connect_appendix: %s CONNECTED", n0)
3621
+ return 1
3549
3622
 
3550
- for i in range(len(edges)):
3551
- e1 = edges[i][1]
3552
- if e1 is None:
3553
- continue
3554
- n1 = edges[i][0]
3555
- over_edges = [[e1.length(), n1]]
3556
- # list entry [<length of edge>, <end node of edge>]
3557
- for j in range(i+1, len(edges)):
3558
- e2 = edges[j][1]
3559
- if e2 is None:
3560
- continue
3561
- n2 = edges[j][0]
3562
- if e1.overlapping_shapes(n, e2):
3563
- over_edges.append([e2.length(), n2])
3564
- edges[j][1] = None
3565
-
3566
- if len(over_edges) > 1:
3567
- if self.correct_overlapping(n, e1, over_edges):
3568
- count += 1
3569
- logger.debug("end of search_overlapping_elements(correct=%s)", count)
3570
- return count
3623
+ nn = self.find_other_node(n0)
3624
+ if not nn:
3625
+ logger.debug("end of connect_appendix: => No node found nearby")
3626
+ return 0
3571
3627
 
3572
- def correct_overlapping(self, n, e, edges):
3573
- if len(edges) < 2:
3574
- return False # no correction
3575
- edges.sort()
3576
- if isinstance(e, Line):
3577
- self.correct_overlapping_lines(n, edges)
3578
- return True
3579
- return False
3628
+ logger.debug("Node %s is near %s", n0, nn)
3629
+ logger.debug(" -- appendix %s from %s to %s", el.classname(), n0, n1)
3630
+ try:
3631
+ logger.debug("remove edge of %s from %s to %s",
3632
+ el.classname(), el.p1, el.p2)
3633
+ self._remove_edge(n0, n1)
3634
+ except Exception:
3635
+ f = Path(__file__)
3636
+ msg = "{} #{}: delete of {} - {} failed".format(
3637
+ f.name, lineno(),
3638
+ n0, n1)
3639
+ self.journal.put_warning(msg)
3640
+ logger.warning("WARNING: %s", msg)
3641
+ logger.debug("-- Element %s", el)
3642
+
3643
+ self.add_or_join_edge(nn, n1, el,
3644
+ rtol=rtol,
3645
+ atol=atol)
3646
+ self.fixed_appendices.append(nn)
3647
+ logger.debug("end of connect_appendix: connected")
3648
+ return 1
3580
3649
 
3581
- def correct_overlapping_lines(self, n, edges):
3582
- logger.debug("begin of correct_overlapping_lines")
3583
- logger.debug(" -- n=%s", n)
3584
- assert(len(edges) > 1)
3650
+ def delete_appendices(self, appendix_list):
3651
+ c = 0
3652
+ for n0, n1, e in appendix_list:
3653
+ logger.debug("Deadend Node at %s", n0)
3654
+ c += self.remove_appendix(n0, n1)
3655
+ return c
3585
3656
 
3586
- n1 = edges[0][1]
3587
- for edge in edges[1:]:
3588
- n2 = edge[1]
3589
- self._remove_edge(n, n2)
3590
- line = Line(Element(start=n1, end=n2))
3591
- self.add_edge(n1, n2, line)
3592
- n1 = n2
3657
+ def delete_all_appendices(self):
3658
+ logger.debug("begin of delete_all_appendices")
3659
+ appendix_list = self.get_appendices()
3660
+ app = len(appendix_list)
3661
+ if not app:
3662
+ logger.debug("end of delete_all_appendices: no appendices")
3663
+ return
3593
3664
 
3594
- logger.debug(" -- corrected")
3595
- logger.debug("end of correct_overlapping_lines")
3665
+ corr = self.delete_appendices(appendix_list)
3666
+ self.journal.put_appendices_deleted(corr)
3667
+
3668
+ logger.debug("==> %s appendices removed", corr)
3669
+ logger.debug("end of delete_all_appendices")
3596
3670
 
3597
- def connect_arc_or_line(self, n, el, n1, n2, tol=1e-05):
3598
- elements = el.split([n], rtol=tol, atol=tol)
3671
+ def connect_arc_or_line(self, n, el, n1, n2, rtol=1e-03, atol=1e-03, mdec=0):
3672
+ elements = el.split([n], rtol=rtol, atol=atol, mdec=mdec)
3599
3673
  if len(elements) != 2:
3600
- logger.info("Not 2 Elements")
3601
- logger.info("Node {} in Element {}".format(n, el))
3674
+ logger.warning("Not 2 Elements")
3675
+ logger.warning("split(rtol=%s, atol=%s, mdec=%s)", rtol, atol, mdec)
3676
+ logger.warning("Node {} in Element {}".format(n, el))
3602
3677
  for e in elements:
3603
3678
  logger.info(e)
3604
3679
  assert(len(elements) == 2)
3605
3680
 
3606
3681
  logger.debug("HIT! Node %s is in %s", n, el)
3607
- logger.debug(" => remove from %s to %s", n1, n2)
3682
+ logger.debug(" => remove %s", el)
3683
+ self.fixed_appendices.append(n1)
3684
+ self.fixed_appendices.append(n2)
3608
3685
  self._remove_edge(n1, n2)
3609
3686
 
3610
3687
  for element in elements:
3611
3688
  logger.debug("Split: %s", element)
3612
3689
 
3613
- rtol = tol
3614
- atol = tol
3615
-
3616
3690
  for element in elements:
3617
3691
  n1_inside = element.is_point_inside(n1,
3618
3692
  rtol=rtol,
3619
3693
  atol=atol,
3694
+ mdec=mdec,
3620
3695
  include_end=True)
3621
3696
  n2_inside = element.is_point_inside(n2,
3622
3697
  rtol=rtol,
3623
3698
  atol=atol,
3699
+ mdec=mdec,
3624
3700
  include_end=True)
3625
3701
  if n1_inside and n2_inside:
3626
3702
  logger.error("FATAL: both inside %s", element)
@@ -3629,37 +3705,63 @@ class Geometry(object):
3629
3705
  else:
3630
3706
  if n1_inside:
3631
3707
  logger.debug(" <= #1 add from %s to %s", n1, n)
3632
- self.add_edge(n1, n, element)
3708
+ self.add_element(element,
3709
+ rtol=self.rtol,
3710
+ atol=self.atol)
3633
3711
  else:
3634
3712
  logger.debug(" <= #2 add from %s to %s", n2, n)
3635
- self.add_edge(n2, n, element)
3713
+ self.add_element(element,
3714
+ rtol=self.rtol,
3715
+ atol=self.atol)
3636
3716
 
3637
- def connect_circle(self, n, el, n1, n2, tol=0.01):
3638
- elements = el.split([n], rtol=tol, atol=tol)
3717
+ def connect_circle(self, n, el, n1, n2, rtol=1e-03, atol=1e-03):
3718
+ elements = el.split([n], rtol=rtol, atol=atol)
3639
3719
  assert(len(elements) == 3)
3640
3720
 
3641
- logger.debug("Node %s is in %s", n, el)
3642
- logger.debug(" => remove from %s to %s", n1, n2)
3721
+ logger.debug("connect_circle: Node %s is in %s", n, el)
3722
+ logger.debug(" => remove %s from %s to %s", el.classname(), n1, n2)
3723
+ e = self.get_edge_element(n1, n2)
3724
+ if not e:
3725
+ logger.error("Element from %s to %s not found", n1, n2)
3726
+ else:
3727
+ logger.debug("Element to Remove: %s", e)
3643
3728
  self._remove_edge(n1, n2)
3729
+
3644
3730
  for element in elements:
3645
- nodes = self.find_nodes(element.start(), element.end())
3646
- self.add_edge(nodes[0], nodes[1], element)
3731
+ self.add_element(element,
3732
+ rtol=self.rtol,
3733
+ atol=self.atol)
3734
+
3735
+ def node_connected(self, n,
3736
+ rtol=1e-03, atol=1e-03,
3737
+ omit_single_element=False,
3738
+ ignore_end=False):
3739
+ mdec = 2
3740
+ count = 0
3741
+ el_list = []
3742
+ for n1, n2, el in self.elements_and_nodes(Shape):
3743
+ if not el.is_near(n):
3744
+ #logger.debug("Node %s is NOT near this edge", n)
3745
+ continue
3746
+ elif el.is_point_inside(n,
3747
+ rtol=rtol,
3748
+ atol=atol,
3749
+ mdec=mdec,
3750
+ include_end=False,
3751
+ ignore_end=ignore_end):
3752
+ logger.debug("Node %s is inside of an edge", n)
3753
+ el_list.append((n1, n2, el))
3647
3754
 
3648
- def node_connected(self, n):
3649
- tol = 0.0001
3650
- for e in self.g.edges(data=True):
3651
- el = e[2].get('object', None)
3652
- if el:
3653
- if el.is_point_inside(n,
3654
- rtol=tol,
3655
- atol=tol,
3656
- include_end=False):
3657
- if is_Circle(el):
3658
- self.connect_circle(n, el, e[0], e[1], tol=tol)
3659
- else:
3660
- self.connect_arc_or_line(n, el, e[0], e[1], tol=tol)
3661
- return True
3662
- return False
3755
+ if omit_single_element and len(el_list) < 2:
3756
+ return 0
3757
+
3758
+ for n1, n2, el in el_list:
3759
+ if is_Circle(el):
3760
+ self.connect_circle(n, el, n1, n2, rtol=rtol, atol=atol)
3761
+ else:
3762
+ self.connect_arc_or_line(n, el, n1, n2, rtol=rtol, atol=atol, mdec=mdec)
3763
+ count += 1
3764
+ return count
3663
3765
 
3664
3766
  def remove_appendix(self, n1, n2, incr_text=''):
3665
3767
  e_dict = self.g.get_edge_data(n1, n2)
@@ -3677,12 +3779,21 @@ class Geometry(object):
3677
3779
  logger.debug("%s remove_appendix(%s, %s)", incr_text, n1, n2)
3678
3780
  self._remove_edge(n1, n2)
3679
3781
  c = 1
3680
- nbrs = [nbr for nbr in self.g.neighbors(n2)]
3782
+ try:
3783
+ nbrs = [nbr for nbr in self.g.neighbors(n2)]
3784
+ except nx.NetworkXError:
3785
+ logger.debug("Node %s already deleted", n2)
3786
+ nbrs = []
3787
+
3681
3788
  if len(nbrs) == 1:
3682
3789
  c += self.remove_appendix(n2, nbrs[0], incr_text + '.')
3683
3790
  return c
3684
3791
 
3685
- def split_and_get_intersect_points(self, el, aktion=True):
3792
+ def adjust_all_points(self):
3793
+ for e in self.elements():
3794
+ e.adjust_points()
3795
+
3796
+ def split_and_get_intersect_points(self, el, aktion=True, include_end=True):
3686
3797
  logger.debug("begin of split_and_get_intersect_points")
3687
3798
  rtol = 1e-03
3688
3799
  atol = 1e-03
@@ -3691,12 +3802,15 @@ class Geometry(object):
3691
3802
  pts = e.intersect_shape(el,
3692
3803
  rtol=rtol,
3693
3804
  atol=atol,
3694
- include_end=True)
3805
+ include_end=include_end)
3695
3806
  if pts:
3807
+ logger.debug("Split %s", e)
3808
+ [logger.debug("-- intersect point %s", p) for p in pts]
3696
3809
  pts_inside = []
3697
3810
  pts_real = []
3698
3811
  for p in pts:
3699
- if not e.is_point_inside(p, rtol, atol, False):
3812
+ incl_end = is_Circle(e)
3813
+ if not e.is_point_inside(p, rtol, atol, include_end=incl_end):
3700
3814
  # get the real point
3701
3815
  n = self.find_the_node(p)
3702
3816
  if n:
@@ -3723,7 +3837,9 @@ class Geometry(object):
3723
3837
  logger.debug(
3724
3838
  "=== OMIT ELEMENT WITH SAME NODES ===")
3725
3839
  else:
3726
- self.add_edge(n[0], n[1], e)
3840
+ self.add_or_join_edge(n[0], n[1], e,
3841
+ rtol=rtol,
3842
+ atol=atol)
3727
3843
  points += pts_real
3728
3844
 
3729
3845
  logger.debug("end of split_and_get_intersect_points")
@@ -3737,6 +3853,30 @@ class Geometry(object):
3737
3853
  return True
3738
3854
  return False
3739
3855
 
3856
+ def _line_inside_magnets(self, p1, p2):
3857
+ for area in self.list_of_areas():
3858
+ if area.is_magnet():
3859
+ if area.is_point_inside(p1):
3860
+ if area.is_point_inside(p2):
3861
+ return True
3862
+ return False
3863
+
3864
+ def _line_inside_air(self, p1, p2):
3865
+ for area in self.list_of_areas():
3866
+ if area.is_air():
3867
+ if area.is_point_inside(p1):
3868
+ if area.is_point_inside(p2):
3869
+ return True
3870
+ return False
3871
+
3872
+ def _line_inside_not_iron(self, p1, p2):
3873
+ for area in self.list_of_areas():
3874
+ if area.is_shaft() or area.is_air() or area.is_magnet():
3875
+ if area.is_point_inside(p1):
3876
+ if area.is_point_inside(p2):
3877
+ return True
3878
+ return False
3879
+
3740
3880
  def inside_area_list(self, p):
3741
3881
  for area in self.list_of_areas():
3742
3882
  if area.is_point_inside(p):
@@ -3749,7 +3889,7 @@ class Geometry(object):
3749
3889
  d = distance(self.center, p)
3750
3890
  logger.debug("-- p = %s, dist = %s", p, d)
3751
3891
  for a in self.inside_area_list(p):
3752
- logger.debug("-- Area type = %s", a.type)
3892
+ logger.debug("-- Area type = %s", a.legend())
3753
3893
  logger.debug(" min=%s, max= %s", a.min_dist, a.max_dist)
3754
3894
  logger.debug(" close to start = %s", a.close_to_startangle)
3755
3895
  logger.debug(" close to end = %s", a.close_to_endangle)
@@ -3775,17 +3915,47 @@ class Geometry(object):
3775
3915
  p1 = p2
3776
3916
  continue
3777
3917
 
3778
- n = self.find_nodes(p1, p2)
3779
3918
  line = Line(Element(start=p1, end=p2),
3780
3919
  color='darkred',
3781
3920
  linestyle='dotted')
3782
- self.add_edge(n[0], n[1], line)
3783
- logger.debug("add line(%s, %s)", n[0], n[1])
3921
+ self.add_element(line,
3922
+ rtol=self.rtol,
3923
+ atol=self.atol)
3924
+ logger.debug("add line(%s)", line)
3784
3925
  created = True
3785
3926
  p1 = p2
3786
3927
 
3787
3928
  return created
3788
3929
 
3930
+ def create_lines_outside_magnets(self, points):
3931
+ logger.debug("begin of create_lines_outside_magnets")
3932
+ if not points:
3933
+ return False
3934
+ created = False
3935
+
3936
+ p1 = points[0]
3937
+ for p2 in points[1:]:
3938
+ logger.debug("try from %s to %s", p1, p2)
3939
+ if not points_are_close(p1, p2):
3940
+ logger.debug("Line from %s to %s", p1, p2)
3941
+ if self._line_inside_not_iron(p1, p2):
3942
+ logger.debug("- not in iron (%s, %s)", p1, p2)
3943
+ p1 = p2
3944
+ continue
3945
+
3946
+ line = Line(Element(start=p1, end=p2),
3947
+ color='darkred',
3948
+ linestyle='dotted')
3949
+ line.set_attribute('iron_sep')
3950
+ self.add_element(line,
3951
+ rtol=self.rtol,
3952
+ atol=self.atol)
3953
+ logger.debug("add line(%s)", line)
3954
+ created = True
3955
+ p1 = p2
3956
+ logger.debug("end of create_lines_outside_magnets")
3957
+ return created
3958
+
3789
3959
  def has_areas_touching_both_sides(self):
3790
3960
  for a in self.area_list:
3791
3961
  if a.is_touching_both_sides():
@@ -3842,9 +4012,146 @@ class Geometry(object):
3842
4012
  logger.debug("end of get_inner_airgap_line #%s", len(nodes))
3843
4013
  return nodes, elements
3844
4014
 
3845
- def create_corner_areas(self):
4015
+ def create_inner_corner_areas(self, startangle, endangle):
3846
4016
  self.set_edge_attributes()
3847
- self.create_inner_corner_auxiliary_areas()
4017
+
4018
+ builder = AreaBuilder(geom=self)
4019
+ builder.create_inner_corner_auxiliary_areas(startangle, endangle)
4020
+
4021
+ def repair_border_line(self, nodes):
4022
+ logger.debug("begin repair_border_line")
4023
+ for d, n, ok in nodes:
4024
+ logger.debug(" node=%s, ok=%s", n, ok)
4025
+
4026
+ d1, n1, ok1 = nodes[0]
4027
+ if not ok1: # fatal => ignore
4028
+ logger.debug("end repair_border_line: missing point %s", n1)
4029
+ return False
4030
+ d1, n1, ok1 = nodes[-1]
4031
+ if not ok1: # fatal => ignore
4032
+ logger.debug("end repair_border_line: missing point %s", n1)
4033
+ return False
4034
+
4035
+ remove_n1 = None
4036
+ for d2, n2, ok2 in nodes[1:]:
4037
+ if ok1 and not ok2:
4038
+ remove_n1 = n1
4039
+ if ok2 and remove_n1:
4040
+ try:
4041
+ self._remove_edge(remove_n1, n2)
4042
+ logger.debug("Remove Line %s -- %s", remove_n1, n2)
4043
+ except nx.NetworkXError:
4044
+ logger.debug("Warning: Remove Line %s -- %s failed", remove_n1, n2)
4045
+ logger.debug("end repair_border_line: failed")
4046
+ return False
4047
+ remove_n1 = None
4048
+ n1 = n2
4049
+ ok1 = ok2
4050
+
4051
+ d1, n1, ok1 = nodes[0]
4052
+ for d2, n2, ok2 in nodes[1:]:
4053
+ if not ok2: # new node
4054
+ self.add_line(n1, n2)
4055
+ logger.debug("Add Line %s -- %s", n1, n2)
4056
+ elif not ok1:
4057
+ self.add_line(n1, n2)
4058
+ logger.debug("Add Line %s -- %s", n1, n2)
4059
+ n1 = n2
4060
+ ok1 = ok2
4061
+ logger.debug("end repair_border_line")
4062
+ return True
4063
+
4064
+ def create_boundery_nodes(self,
4065
+ center,
4066
+ startangle,
4067
+ endangle,
4068
+ rtol=None, atol=None):
4069
+ if not rtol:
4070
+ rtol = 1e-4
4071
+ if not atol:
4072
+ atol = 1e-3
4073
+
4074
+ start_nodes = [n for n in self.angle_nodes(center, startangle, rtol, atol)]
4075
+ end_nodes = [n for n in self.angle_nodes(center, endangle, rtol, atol)]
4076
+ alpha = alpha_angle(startangle, endangle)
4077
+
4078
+ logger.debug("begin of create_boundery_nodes")
4079
+ start_rot_nodes = self.rotate_nodes(alpha, start_nodes)
4080
+ end_rot_nodes = self.rotate_nodes(-alpha, end_nodes)
4081
+
4082
+ def miss_nodelist(src_nodelist, dest_nodelist):
4083
+ nlist = []
4084
+ for src_n in src_nodelist:
4085
+ ok = False
4086
+ for dest_n in dest_nodelist:
4087
+ if points_are_close(src_n, dest_n, rtol=rtol, atol=atol):
4088
+ ok = True
4089
+ break
4090
+ if not ok:
4091
+ nlist.append(src_n)
4092
+ return nlist
4093
+
4094
+ logger.debug("Begin with Nodes Start=%s, End=%s", len(start_nodes), len(end_nodes))
4095
+
4096
+ missing_end_nodes = miss_nodelist(start_rot_nodes, end_nodes)
4097
+ missing_start_nodes = miss_nodelist(end_rot_nodes, start_nodes)
4098
+
4099
+ if missing_start_nodes:
4100
+ logger.debug("%s missing start nodes", len(missing_start_nodes))
4101
+ start_nodes = [(distance(center, n), n, True) for n in start_nodes]
4102
+ for n in missing_start_nodes:
4103
+ start_nodes.append((distance(center, n), n, False))
4104
+ start_nodes.sort()
4105
+ if not self.repair_border_line(start_nodes):
4106
+ logger.debug("end of create_boundery_nodes (failed)")
4107
+ return
4108
+ else:
4109
+ start_nodes = [(distance(center, n), n, True) for n in start_nodes]
4110
+ start_nodes.sort()
4111
+
4112
+ if missing_end_nodes:
4113
+ logger.debug("%s missing end nodes", len(missing_end_nodes))
4114
+ end_nodes = [(distance(center, n), n, True) for n in end_nodes]
4115
+ for n in missing_end_nodes:
4116
+ end_nodes.append((distance(center, n), n, False))
4117
+ end_nodes.sort()
4118
+ if not self.repair_border_line(end_nodes):
4119
+ logger.debug("end of create_boundery_nodes (failed)")
4120
+ return
4121
+ else:
4122
+ end_nodes = [(distance(center, n), n, True) for n in end_nodes]
4123
+ end_nodes.sort()
4124
+
4125
+ start_nodes = [(distance(center, n), n)
4126
+ for n in self.angle_nodes(center, startangle, rtol, atol)]
4127
+ start_nodes.sort()
4128
+ end_nodes = [(distance(center, n), n)
4129
+ for n in self.angle_nodes(center, endangle, rtol, atol)]
4130
+ end_nodes.sort()
4131
+
4132
+ logger.debug("End with Nodes Start=%s, End=%s", len(start_nodes), len(end_nodes))
4133
+
4134
+ nodes = [n for d, n in start_nodes]
4135
+ start_rot_nodes = self.rotate_nodes(alpha, nodes)
4136
+
4137
+ for d, node in start_nodes:
4138
+ self.set_point_of_node(node, node)
4139
+ i = 0
4140
+ if len(end_nodes) == len(start_rot_nodes):
4141
+ for d, node in end_nodes:
4142
+ self.set_point_of_node(node, start_rot_nodes[i])
4143
+ i += 1
4144
+
4145
+ logger.debug("end of create_boundery_nodes")
4146
+ return
4147
+
4148
+ def set_point_of_node(self, node, p):
4149
+ if isinstance(node, list):
4150
+ node = (node[0], node[1])
4151
+ nbrs = self.get_neighbors(node)
4152
+ for nbr in nbrs:
4153
+ e = self.get_edge_element(node, nbr)
4154
+ e.replace_point(node, p)
3848
4155
 
3849
4156
  def create_and_append_area(self, n1, n2):
3850
4157
  rslt = self.get_new_area(n1, n2, False)
@@ -3852,7 +4159,7 @@ class Geometry(object):
3852
4159
  if rslt.get('ok', False):
3853
4160
  area = rslt['area']
3854
4161
  a = Area(area, self.center, 0.0)
3855
- a.type = 0 # air
4162
+ a.set_type(AREA.TYPE_AIR) # air
3856
4163
  self.area_list.append(a)
3857
4164
  return True
3858
4165
  logger.error("No area for air near airgap!!")
@@ -3904,7 +4211,9 @@ class Geometry(object):
3904
4211
  self.add_line(start_cp, n,
3905
4212
  color='red',
3906
4213
  linestyle='dotted')
3907
- self.add_edge(cp, start_cp, start_line)
4214
+ self.add_element(start_line,
4215
+ rtol=self.rtol,
4216
+ atol=self.atol)
3908
4217
  self.create_and_append_area(start_cp, n)
3909
4218
  self.start_corners = self.get_corner_nodes(self.center,
3910
4219
  0.0)
@@ -3931,7 +4240,9 @@ class Geometry(object):
3931
4240
  self.add_line(end_cp, n,
3932
4241
  color='red',
3933
4242
  linestyle='dotted')
3934
- self.add_edge(cp, end_cp, end_line)
4243
+ self.add_element(end_line,
4244
+ rtol=self.rtol,
4245
+ atol=self.atol)
3935
4246
  self.create_and_append_area(n, end_cp)
3936
4247
  self.end_corners = self.get_corner_nodes(self.center,
3937
4248
  self.alfa)