femagtools 1.6.7__py3-none-any.whl → 1.7.0__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 (50) hide show
  1. femagtools/__init__.py +2 -2
  2. femagtools/bch.py +1 -1
  3. femagtools/dxfsl/area.py +334 -332
  4. femagtools/dxfsl/areabuilder.py +131 -10
  5. femagtools/dxfsl/conv.py +27 -9
  6. femagtools/dxfsl/converter.py +390 -125
  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 +1120 -886
  12. femagtools/dxfsl/journal.py +53 -22
  13. femagtools/dxfsl/machine.py +250 -74
  14. femagtools/dxfsl/plotrenderer.py +34 -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 +12 -11
  24. femagtools/machine/sizing.py +14 -11
  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.7.dist-info → femagtools-1.7.0.dist-info}/LICENSE +1 -0
  42. {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/METADATA +7 -4
  43. {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/RECORD +50 -49
  44. tests/engines/__init__.py +0 -20
  45. tests/geom/__init__.py +0 -20
  46. tests/moo/__init__.py +0 -20
  47. tests/test_model.py +8 -1
  48. {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/WHEEL +0 -0
  49. {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/entry_points.txt +0 -0
  50. {femagtools-1.6.7.dist-info → femagtools-1.7.0.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,61 @@ 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
324
286
  i = 0
325
287
 
288
+ logger.debug("Geometry(split=%s, concat=%s, connect=%s, delete=%s, adjust=%s, main=%s,",
289
+ split, concatenate, connect, delete, adjust, main)
290
+ logger.debug(" rtol=%s, atol=%s)",
291
+ rtol, atol)
292
+
293
+ timer = Timer(start_it=True)
294
+ self.c_concat = 0
295
+ self.c_connect = 0
296
+
326
297
  def get_elements(elements, split):
327
298
  if split:
328
299
  return intersect_and_split(elements, self.rtol, self.atol)
329
- else:
330
- return elements
300
+
301
+ src_elements = [e for e in elements]
302
+ if main:
303
+ self.journal.put_elements(len(src_elements))
304
+
305
+ if not concatenate:
306
+ return src_elements
307
+
308
+ concat = Concatenation(rtol=self.rtol, atol=self.atol)
309
+ c, new_elements = concat.concatenate_matching_elements(src_elements,
310
+ main=main)
311
+ self.c_concat = c
312
+ return new_elements
313
+
314
+ nbr_nodes = []
315
+ if concatenate:
316
+ elements = [e for e in elements]
317
+ geom = Geometry(elements, center=(0.0, 0.0))
318
+ logger.debug("REAL GEOMETRY START ")
319
+ elements = geom.copy_all_elements(alpha=0.0)
320
+ nbr_nodes = geom.get_nodes(num_of_nbrs=[2, 4])
331
321
 
332
322
  for e in get_elements(elements, split):
333
323
  if e:
334
324
  e.id = i
335
325
  n = self.find_nodes(e.start(), e.end())
336
326
  try:
337
- add_or_join(self, n[0], n[1], e, self.rtol, self.atol)
327
+ self.add_or_join_edge(n[0], n[1], e,
328
+ rtol=self.rtol,
329
+ atol=self.atol)
338
330
  except Exception as ex:
339
331
  logger.warn("EXCEPTION %s", ex)
340
332
  if e: # must be a circle
@@ -346,6 +338,29 @@ class Geometry(object):
346
338
  if center:
347
339
  self.set_center(center)
348
340
 
341
+ if connect:
342
+ self.c_connect = self.connect_all_appendices(rtol=1e-04,
343
+ atol=1e-03,
344
+ main=True)
345
+ if delete:
346
+ self.delete_all_appendices()
347
+
348
+ if concatenate and self.c_concat > 0:
349
+ self.c_connect += self.connect_all_nodes(rtol=1e-04,
350
+ atol=1e-03,
351
+ additional_nodes=nbr_nodes,
352
+ main=True)
353
+
354
+ if adjust:
355
+ self.adjust_all_points()
356
+
357
+ if delete and center:
358
+ self.set_minmax_radius()
359
+
360
+ timer.stop("-- Geometry initialised in %0.4f seconds --")
361
+ logger.debug("End Geometry(concatenated=%s, connected=%s)",
362
+ self.c_concat, self.c_connect)
363
+
349
364
  def shaft(self):
350
365
  """returns shaft diameter if any"""
351
366
  radius = []
@@ -379,8 +394,15 @@ class Geometry(object):
379
394
  for n in self.g.nodes()}
380
395
  nx.relabel_nodes(self.g, mapping, copy=False)
381
396
 
397
+ def rotate_nodes(self, alpha, nodes):
398
+ T = np.array(((np.cos(alpha), -np.sin(alpha)),
399
+ (np.sin(alpha), np.cos(alpha))))
400
+ rotnodes = np.dot(T, np.asarray(nodes).T).T.tolist()
401
+ return rotnodes
402
+
382
403
  def rotate(self, alpha):
383
404
  """rotates all objects by angle alpha"""
405
+ logger.debug("rotate geometry(%s)", alpha)
384
406
  T = np.array(((np.cos(alpha), -np.sin(alpha)),
385
407
  (np.sin(alpha), np.cos(alpha))))
386
408
  for e in self.g.edges(data=True):
@@ -391,6 +413,7 @@ class Geometry(object):
391
413
  mapping = {n: (round(r[0], ndec),
392
414
  round(r[1], ndec))
393
415
  for n, r in zip(self.g.nodes(), rotnodes)}
416
+
394
417
  nx.relabel_nodes(self.g, mapping, copy=False)
395
418
 
396
419
  def check_geom(self, what):
@@ -449,12 +472,6 @@ class Geometry(object):
449
472
  nx.relabel_nodes(self.g, mapping, copy=False)
450
473
  self.diameters = tuple([factor*d for d in self.diameters])
451
474
 
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
475
  def find_nodes(self, *points, **kwargs):
459
476
  """return closest nodes to points in arg within pickdist"""
460
477
  n = []
@@ -475,21 +492,26 @@ class Geometry(object):
475
492
  return [(round(p[0], ndec), round(p[1], ndec)) for p in points]
476
493
  return n
477
494
 
478
- def find_node(self, p, **kwargs):
479
- """return closest nodes to points in arg within pickdist"""
495
+ def find_other_node(self, node, **kwargs):
496
+ """return closest node to node in arg within pickdist"""
480
497
  nodes = list(kwargs.get('g', self.g))
481
498
  if nodes:
482
499
  anodes = np.asarray(nodes)
483
500
  # la.norm on numpy below 1.8 does not accept axis
484
- c = anodes - p
501
+ c = anodes - node
485
502
  dist = np.sqrt(np.einsum('ij, ij->i', c, c))
486
- # dist = la.norm(np.asarray(nodes) - p, axis=1)
487
503
  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]
504
+ candidates = [(dist[i], nodes[i]) for i in range(len(dist))
505
+ if dist[i] < 0.01]
506
+ if not candidates:
507
+ return None
508
+ candidates.sort()
509
+ if len(candidates) > 1:
510
+ i = 0
511
+ d, n = candidates[0]
512
+ if d == 0.0:
513
+ d, n = candidates[1]
514
+ return n
493
515
  return None
494
516
 
495
517
  def find_the_node(self, p, **kwargs):
@@ -511,7 +533,7 @@ class Geometry(object):
511
533
  paths = []
512
534
  g = self.g.copy()
513
535
  g.remove_edges_from(self.arcs())
514
- while g.number_of_edges() > 0:
536
+ while self.number_of_edges() > 0:
515
537
  p = single_path(g.edges())
516
538
  g.remove_edges_from(p)
517
539
  # rearrange sequence to make it contiguous:
@@ -545,6 +567,69 @@ class Geometry(object):
545
567
  return n
546
568
  return []
547
569
 
570
+ def add_element(self, e, rtol, atol):
571
+ n = self.find_nodes(e.start(), e.end())
572
+ try:
573
+ self.add_or_join_edge(n[0], n[1], e, rtol=rtol, atol=atol)
574
+ except Exception as ex:
575
+ logger.warn("EXCEPTION in add_element: %s", ex)
576
+
577
+ def add_or_join_edge(self, n1, n2, entity, rtol=1e-03, atol=1e-03):
578
+ """ adds a new entity to graph or joins entity with existing
579
+ geom: Geometry
580
+ n1, n2: nodes
581
+ entity
582
+ """
583
+ if n1 == n2:
584
+ logger.debug(
585
+ "add_or_join_edge: Tiny element with same node on both sides ignored: %s", n1)
586
+ logger.debug(
587
+ "add_or_join_edge: -- element: %s", entity)
588
+ return
589
+
590
+ e = self.get_edge_element(n1, n2)
591
+ if not e: # no duplicates
592
+ self.add_edge(n1, n2, entity)
593
+ return
594
+
595
+ logger.debug("add_or_join_edge: Duplicate connection: %s <--> %s", n1, n2)
596
+ if is_Line(e):
597
+ if is_Line(entity):
598
+ logger.debug("add_or_join_edge: Duplicate Lines ignored")
599
+ return # its ok
600
+
601
+ if is_Arc(e):
602
+ if is_Arc(entity):
603
+ if points_are_close(e.center, entity.center, rtol=rtol, atol=atol):
604
+ if points_are_close(e.p1, entity.p1):
605
+ logger.debug("add_or_join_edge: Duplicate Arcs ignored")
606
+ return # its ok
607
+
608
+ if is_Circle(entity):
609
+ if is_Circle(e):
610
+ logger.debug("add_or_join_edge: Duplicate Circle ignored")
611
+ return # its ok
612
+
613
+ if is_Circle(entity) or is_Circle(e):
614
+ e1, e2 = entity.cut_into_halves()
615
+ logger.debug("add_or_join_edge: Element near circle is cut into halves")
616
+ self.add_element(e1, rtol, atol)
617
+ self.add_element(e2, rtol, atol)
618
+ return # halves installed
619
+
620
+ m1 = e.center_of_connection()
621
+ m2 = entity.center_of_connection()
622
+ logger.debug("add_or_join_edge: midpoints: %s -- %s", m1, m2)
623
+ if points_are_close(m1, m2, rtol, 1e-2):
624
+ logger.debug("add_or_join_edge: Elements are close together")
625
+ return # ok
626
+
627
+ e1, e2 = entity.cut_into_halves()
628
+ logger.debug("add_or_join_edge: cut into halves")
629
+ self.add_element(e1, rtol, atol)
630
+ self.add_element(e2, rtol, atol)
631
+ return # halves installed
632
+
548
633
  def add_edge(self, n1, n2, entity):
549
634
  if points_are_close(n1, n2):
550
635
  logger.debug("WARNING in add_edge(): Points of %s are close together",
@@ -552,10 +637,18 @@ class Geometry(object):
552
637
  logger.debug(" n1 = %s, n2 = %s", n1, n2)
553
638
  logger.debug(" p1 = %s, p2 = %s", entity.p1, entity.p2)
554
639
 
640
+ if self.has_edge(n1, n2):
641
+ logger.warning("FATAL ERROR: Duplicates in add_edge(%s, %s)", n1, n2)
642
+
555
643
  entity.set_nodes(n1, n2)
556
644
  logger.debug("add_edge %s - %s (%s)", n1, n2, entity.classname())
557
645
  self.g.add_edge(n1, n2, object=entity)
558
646
 
647
+ def has_edge(self, n1, n2):
648
+ if self.g.get_edge_data(n1, n2):
649
+ return True
650
+ return False
651
+
559
652
  def get_edge(self, eg):
560
653
  return [[e[0], e[1], e[2]['object']] for e in self.g.edges(data=True)
561
654
  if e[2]['object'] is eg]
@@ -574,6 +667,8 @@ class Geometry(object):
574
667
  def _remove_edge(self, n1, n2):
575
668
  logger.debug("remove_edge %s - %s", n1, n2)
576
669
  self.g.remove_edge(n1, n2)
670
+ self._remove_node(n1)
671
+ self._remove_node(n2)
577
672
 
578
673
  def remove_edge(self, edge):
579
674
  e = self.get_edge(edge)
@@ -587,16 +682,21 @@ class Geometry(object):
587
682
  for e in edges:
588
683
  self.remove_edge(e)
589
684
 
685
+ def _remove_node(self, n):
686
+ for nbr in self.g.neighbors(n):
687
+ return
688
+ try:
689
+ self.g.remove_node(n)
690
+ except nx.NetworkXError:
691
+ logger.warning("WARNING: remove node %s failed", n)
692
+
590
693
  def add_line(self, n1, n2, color=None, linestyle=None):
591
694
  line = Line(Element(start=n1, end=n2),
592
695
  color=color,
593
696
  linestyle=linestyle)
594
- add_or_join(self,
595
- n1,
596
- n2,
597
- line,
598
- self.rtol,
599
- self.atol)
697
+ self.add_element(line,
698
+ rtol=self.rtol,
699
+ atol=self.atol)
600
700
 
601
701
  def add_arc(self, n1, n2, center, radius, color=None, linestyle=None):
602
702
  angle_n1 = alpha_line(center, n1)
@@ -607,18 +707,20 @@ class Geometry(object):
607
707
  end_angle=angle_n2*180/np.pi),
608
708
  color=color,
609
709
  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):
710
+ self.add_element(arc,
711
+ rtol=self.rtol,
712
+ atol=self.atol)
713
+
714
+ def elements(self, type=Shape):
618
715
  """return lists of objects"""
619
716
  return [e[2]['object'] for e in self.g.edges(data=True)
620
717
  if isinstance(e[2]['object'], type)]
621
718
 
719
+ def elements_and_nodes(self, type=Shape):
720
+ """return lists of objects"""
721
+ return [(e[0], e[1], e[2]['object']) for e in self.g.edges(data=True)
722
+ if isinstance(e[2]['object'], type)]
723
+
622
724
  def arcs(self):
623
725
  """return lists of arcs"""
624
726
  return self.elements(Arc)
@@ -642,12 +744,9 @@ class Geometry(object):
642
744
  for p1, p2 in rem_lines:
643
745
  self._remove_edge(p1, p2)
644
746
  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)
747
+ self.add_element(new_ln,
748
+ rtol=self.rtol,
749
+ atol=self.atol)
651
750
 
652
751
  def circles(self):
653
752
  """return list of circle nodes"""
@@ -658,8 +757,15 @@ class Geometry(object):
658
757
  for n in self.g.nodes():
659
758
  yield n
660
759
 
661
- def get_nodes(self):
662
- nodes = [n for n in self.g.nodes()]
760
+ def get_nodes(self, num_of_nbrs=[]):
761
+ if num_of_nbrs:
762
+ nodes = []
763
+ for n in self.g.nodes():
764
+ nbr_list = [nbr for nbr in self.g.neighbors(n)]
765
+ if len(nbr_list) in num_of_nbrs:
766
+ nodes.append(n)
767
+ else:
768
+ nodes = [n for n in self.g.nodes()]
663
769
  return nodes
664
770
 
665
771
  def virtual_nodes(self):
@@ -668,14 +774,25 @@ class Geometry(object):
668
774
  nodes += e.get_nodes()
669
775
  return nodes
670
776
 
777
+ def get_neighbors(self, n):
778
+ return [nbr for nbr in self.g.neighbors(n)]
779
+
671
780
  def angle_nodes(self, center, angle, rtol, atol):
781
+ if np.isclose(abs(angle), np.pi, rtol, atol):
782
+ angle_func = positive_angle
783
+ else:
784
+ angle_func = normalise_angle
785
+ angle = angle_func(angle)
786
+
672
787
  nodes = []
673
788
  for n in self.g.nodes():
674
789
  if points_are_close(center, n, rtol, atol):
675
790
  # Da gibt es keinen brauchbaren Winkel
676
791
  nodes.append(n)
677
- elif np.isclose(angle, alpha_line(center, n), rtol, atol):
678
- nodes.append(n)
792
+ else:
793
+ angle_line = angle_func(alpha_line(center, n))
794
+ if np.isclose(angle, angle_line, rtol, atol):
795
+ nodes.append(n)
679
796
  return nodes
680
797
 
681
798
  def radius_nodes(self, center, radius, rtol, atol):
@@ -747,7 +864,10 @@ class Geometry(object):
747
864
  else:
748
865
  p = (self.min_radius, 0.0)
749
866
  cp = self.start_corners[0]
750
- if points_are_close(p, cp, atol=0.5):
867
+ if points_are_close(p, cp, rtol=1e-2, atol=1e-1):
868
+ if points_are_close(p, cp, rtol=1e-3, atol=1e-2):
869
+ logger.debug("get_start_airgap_corner: critical")
870
+ logger.debug(" -- soll: %s, ist: %s", p, cp)
751
871
  return cp, True
752
872
  return p, False
753
873
 
@@ -758,7 +878,11 @@ class Geometry(object):
758
878
  else:
759
879
  p = point(self.center, self.min_radius, self.alfa, ndec)
760
880
  cp = self.end_corners[0]
761
- if points_are_close(p, cp, atol=0.5):
881
+ logger.debug("End Airgap Corner: %s is %s", p, cp)
882
+ if points_are_close(p, cp, rtol=1e-2, atol=1e-1):
883
+ if points_are_close(p, cp, rtol=1e-3, atol=1e-2):
884
+ logger.debug("get_end_airgap_corner: critical")
885
+ logger.debug(" -- soll: %s, ist: %s", p, cp)
762
886
  return cp, True
763
887
  return p, False
764
888
 
@@ -798,6 +922,7 @@ class Geometry(object):
798
922
  atol = 1e-3
799
923
 
800
924
  logger.debug("begin repair_hull_line(center=%s, angle=%s)", center, angle)
925
+ [logger.debug(" --> Corner %s", c) for c in corners]
801
926
 
802
927
  if len(corners) < 2:
803
928
  # no hull without more than 1 corners
@@ -840,8 +965,12 @@ class Geometry(object):
840
965
  radius=el.radius,
841
966
  start_angle=alpha_mid*180/np.pi,
842
967
  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)
968
+ self.add_element(a1,
969
+ rtol=self.rtol,
970
+ atol=self.atol)
971
+ self.add_element(a2,
972
+ rtol=self.rtol,
973
+ atol=self.atol)
845
974
  else:
846
975
  clist = []
847
976
  if clist_p1:
@@ -850,18 +979,12 @@ class Geometry(object):
850
979
  clist = [c for c in clist_p2]
851
980
  [corner.set_keep_node() for corner in clist]
852
981
 
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
982
  # Rebuild Corner-list after correction
860
983
  center_added, corners = self.get_corner_list(center, angle, rtol, atol)
861
984
  for c in corners:
862
985
  logger.debug("Correct Corner: %s", c)
863
986
 
864
- if with_center:
987
+ if with_center or self.with_center_node:
865
988
  c_corner = Corner(center, tuple(center))
866
989
  if c_corner not in corners:
867
990
  corners.append(c_corner)
@@ -871,7 +994,9 @@ class Geometry(object):
871
994
  p1 = corners[0].point()
872
995
  for c in corners[1:]:
873
996
  p2 = c.point()
874
- self.add_edge(p1, p2, Line(Element(start=p1, end=p2)))
997
+ self.add_element(Line(Element(start=p1, end=p2)),
998
+ rtol=self.rtol,
999
+ atol=self.atol)
875
1000
  p1 = p2
876
1001
 
877
1002
  self.set_minmax_radius()
@@ -906,14 +1031,18 @@ class Geometry(object):
906
1031
  c_min.is_new_point = True
907
1032
  p1 = c_min.point()
908
1033
  p2 = c_first.point()
909
- self.add_edge(p1, p2, Line(Element(start=p1, end=p2)))
1034
+ self.add_element(Line(Element(start=p1, end=p2)),
1035
+ rtol=self.rtol,
1036
+ atol=self.atol)
910
1037
 
911
1038
  c_last = corners[len(corners)-1]
912
1039
  if not c_max.is_same_corner(c_last):
913
1040
  c_max.is_new_point = True
914
1041
  p2 = c_max.point()
915
1042
  p1 = c_last.point()
916
- self.add_edge(p1, p2, Line(Element(start=p1, end=p2)))
1043
+ self.add_element(Line(Element(start=p1, end=p2)),
1044
+ rtol=self.rtol,
1045
+ atol=self.atol)
917
1046
  logger.debug("end complete_hull_line")
918
1047
  return (c_min, c_max)
919
1048
 
@@ -928,10 +1057,12 @@ class Geometry(object):
928
1057
  nodes_sorted.sort()
929
1058
  p = nodes_sorted[0][1]
930
1059
  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)))
1060
+ arc = Arc(Element(center=self.center, radius=radius,
1061
+ start_angle=startangle*180/np.pi,
1062
+ end_angle=angle_p*180/np.pi))
1063
+ self.add_element(arc,
1064
+ rtol=self.rtol,
1065
+ atol=self.atol)
935
1066
 
936
1067
  if endcorner.is_new_point:
937
1068
  end_p = endcorner.point()
@@ -940,10 +1071,12 @@ class Geometry(object):
940
1071
  inx = len(nodes_sorted)-1
941
1072
  p = nodes_sorted[inx][1]
942
1073
  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)))
1074
+ arc = Arc(Element(center=self.center, radius=radius,
1075
+ start_angle=angle_p*180/np.pi,
1076
+ end_angle=endangle*180/np.pi))
1077
+ self.add_element(p, end_p, arc,
1078
+ rtol=self.rtol,
1079
+ atol=self.atol)
947
1080
 
948
1081
  def get_corner_nodes(self, center, angle):
949
1082
  rtol = 1e-4
@@ -954,313 +1087,17 @@ class Geometry(object):
954
1087
  return () # not enough corners
955
1088
  return (corners[0].point(), corners[len(corners)-1].point())
956
1089
 
1090
+ def set_start_corners(self, center, angle):
1091
+ self.start_corners = self.get_corner_nodes(center, angle)
1092
+
1093
+ def set_end_corners(self, center, angle):
1094
+ self.end_corners = self.get_corner_nodes(center, angle)
1095
+
957
1096
  def get_angle(self, alpha1, alpha2):
958
1097
  if np.isclose(alpha1, alpha2, 0.001, 0.001):
959
1098
  return 0.0
960
1099
  return alpha_angle(alpha1, alpha2)
961
1100
 
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
1101
  def set_edge_attributes(self):
1265
1102
  if nxversion == 1:
1266
1103
  nx.set_edge_attributes(self.g, 0, True)
@@ -1271,7 +1108,7 @@ class Geometry(object):
1271
1108
  nx.set_edge_attributes(self.g, False, 1)
1272
1109
  nx.set_edge_attributes(self.g, False, 2)
1273
1110
 
1274
- def create_list_of_areas(self, crunch=False):
1111
+ def create_list_of_areas(self, main=False):
1275
1112
  """ return list of areas for each node and their neighbors
1276
1113
  """
1277
1114
  if len(self.area_list) > 0:
@@ -1280,47 +1117,9 @@ class Geometry(object):
1280
1117
  return
1281
1118
 
1282
1119
  areabuilder = AreaBuilder(geom=self)
1283
- areabuilder.create_list_of_areas(main=False)
1120
+ areabuilder.create_list_of_areas(main=main)
1284
1121
  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)
1122
+ logger.debug("area list created")
1324
1123
 
1325
1124
  def list_of_areas(self):
1326
1125
  self.create_list_of_areas()
@@ -1497,8 +1296,12 @@ class Geometry(object):
1497
1296
  end_angle=alpha_end*180/np.pi))
1498
1297
  if points_are_close(a.p1, a.p2, rtol=1e-02, atol=1e-02):
1499
1298
  logger.debug("ATTENTION: creation of a tiny arc")
1299
+ logger.debug("-- %s", a)
1500
1300
  a.set_attribute("tiny")
1501
- new_elements.append(a)
1301
+ if points_are_close(a.p1, a.p2, rtol=1e-06, atol=1e-06):
1302
+ logger.debug("-- points are equal")
1303
+ else:
1304
+ new_elements.append(a)
1502
1305
  alpha_start = alpha_end
1503
1306
  p1 = p2
1504
1307
  return new_elements
@@ -1594,7 +1397,8 @@ class Geometry(object):
1594
1397
  append_inner=False,
1595
1398
  append_outer=False,
1596
1399
  delete_appendices=False,
1597
- concatenate_tiny_el=False):
1400
+ concatenate=True,
1401
+ connect=True):
1598
1402
  """ Die Funktion kopiert die Teile von Shape-Objekten, welche sich in
1599
1403
  der durch die Parameter definierten Teilkreisfläche befinden.
1600
1404
  """
@@ -1608,6 +1412,8 @@ class Geometry(object):
1608
1412
  atol = 1e-4
1609
1413
  logger.debug(' -> rtol=%s, atol=%s', rtol, atol)
1610
1414
 
1415
+ self.with_center_node = self.find_the_node(self.center) is not None
1416
+
1611
1417
  if is_same_angle(startangle, endangle):
1612
1418
  start_line = Line(
1613
1419
  Element(start=self.center,
@@ -1695,40 +1501,28 @@ class Geometry(object):
1695
1501
  new_elements.append(arc)
1696
1502
  p1 = p2
1697
1503
 
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
1504
+ center = self.center
1707
1505
 
1708
1506
  if split:
1709
1507
  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)
1508
+
1509
+ geom = Geometry(new_elements,
1510
+ center=center,
1511
+ rtol=self.rtol,
1512
+ atol=self.atol,
1513
+ is_inner=self.is_inner,
1514
+ is_outer=self.is_outer,
1515
+ concatenate=concatenate,
1516
+ connect=connect,
1517
+ delete=delete_appendices,
1518
+ split=split)
1519
+ geom.with_center_node = self.with_center_node
1520
+
1728
1521
  logger.debug('end copy_shape')
1729
1522
  return geom
1730
1523
 
1731
1524
  def copy_all_elements(self, alpha):
1525
+ logger.debug("begin copy_all_elements(alpha=%s)", alpha)
1732
1526
  if alpha == 0.0:
1733
1527
  T = None
1734
1528
  else:
@@ -1764,19 +1558,25 @@ class Geometry(object):
1764
1558
  el.transform(T, alpha, ndec)
1765
1559
  all_el.append(el)
1766
1560
 
1767
- logger.debug("copy_all_elements: %s lines, %s arcs, %s circles",
1561
+ logger.debug("end copy_all_elements: %s lines, %s arcs, %s circles",
1768
1562
  lines, arcs, circles)
1769
-
1770
1563
  return all_el
1771
1564
 
1772
- def new_clone(self, new_elements, split=False):
1565
+ def new_clone(self, new_elements,
1566
+ split=False,
1567
+ concatenate=False,
1568
+ connect=False,
1569
+ adjust=False):
1773
1570
  return Geometry(new_elements,
1774
1571
  center=self.center,
1775
1572
  rtol=self.rtol,
1776
1573
  atol=self.atol,
1777
1574
  is_inner=self.is_inner,
1778
1575
  is_outer=self.is_outer,
1779
- split=split)
1576
+ split=split,
1577
+ concatenate=concatenate,
1578
+ connect=connect,
1579
+ adjust=adjust)
1780
1580
 
1781
1581
  def is_new_angle(self, alpha_list, alpha):
1782
1582
  for a in alpha_list:
@@ -1784,78 +1584,6 @@ class Geometry(object):
1784
1584
  return False
1785
1585
  return True
1786
1586
 
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
1587
  def find_symmetry(self, radius,
1860
1588
  startangle, endangle, sym_tolerance):
1861
1589
  arealist = self.list_of_areas()
@@ -2082,6 +1810,25 @@ class Geometry(object):
2082
1810
  return [h for (k, h) in legend.items()]
2083
1811
  return []
2084
1812
 
1813
+ def render_areagroups(self, renderer):
1814
+ if not self.areagroup_list:
1815
+ return
1816
+ for area in self.areagroup_list:
1817
+ area.render(renderer,
1818
+ color="yellow",
1819
+ fill=False)
1820
+ return
1821
+
1822
+ def render_magnet_phi(self, renderer):
1823
+ magnets = [a for a in self.list_of_areas()]
1824
+ if not magnets:
1825
+ return
1826
+ arrow_len = [a.magnet_arrow_length() for a in magnets]
1827
+ length = max(arrow_len)
1828
+
1829
+ for area in magnets:
1830
+ area.render_magnet_phi(renderer, length)
1831
+
2085
1832
  def get_points_in_iron(self):
2086
1833
  points = []
2087
1834
  for area in self.list_of_areas():
@@ -2114,6 +1861,10 @@ class Geometry(object):
2114
1861
  atol = 3.0
2115
1862
 
2116
1863
  logger.debug("*** Begin of get_machine() ***")
1864
+
1865
+ logger.debug(">> minmax: %s", mm)
1866
+ logger.debug(">> w=%s, h=%s", width, height)
1867
+
2117
1868
  if np.isclose(height, width, self.rtol, self.atol):
2118
1869
  radius = width/2
2119
1870
  self.set_center([mm[1]-radius, mm[3]-radius])
@@ -2128,6 +1879,8 @@ class Geometry(object):
2128
1879
  logger.info("check for quarter machine")
2129
1880
  radius = width
2130
1881
  self.set_center([mm[0], mm[2]])
1882
+ logger.debug("-- center = %s, radius min/max = %s/%s",
1883
+ self.center, self.min_radius, self.max_radius)
2131
1884
  if self.check_hull(radius, mm[0], mm[2], self.rtol, atol):
2132
1885
  logger.info(" - it is a quarter")
2133
1886
  return Machine(self,
@@ -2303,7 +2056,7 @@ class Geometry(object):
2303
2056
  m_min = min(m_min, m)
2304
2057
 
2305
2058
  y = line_n([p[0]-center[0], p[1]], m_min)
2306
- center[1] = y
2059
+ center = (center[0], y)
2307
2060
  angle = alpha_line(center, p)
2308
2061
 
2309
2062
  self.set_center([round(center[0], 8), round(center[1], 8)])
@@ -2406,8 +2159,20 @@ class Geometry(object):
2406
2159
  return None
2407
2160
 
2408
2161
  def get_center_arcs(self):
2162
+ logger.debug("begin of get_center_arcs")
2409
2163
  center_list = []
2410
- for e in self.elements(Arc):
2164
+ circles = [e for e in self.elements() if is_Circle(e)]
2165
+ logger.debug(" -- %s Circles", len(circles))
2166
+
2167
+ for e in circles:
2168
+ center = (round(e.center[0], 3), round(e.center[1], 3))
2169
+ radius = round(e.radius, 1)
2170
+ center_list.append(([1], center, [radius]))
2171
+
2172
+ arcs = [e for e in self.elements() if is_Arc(e)]
2173
+ logger.debug(" -- %s Arcs", len(arcs))
2174
+
2175
+ for e in arcs:
2411
2176
  center = (round(e.center[0], 3), round(e.center[1], 3))
2412
2177
  radius = round(e.radius, 1)
2413
2178
  c = self.get_same_center(center_list, center, self.rtol, self.atol)
@@ -2429,6 +2194,8 @@ class Geometry(object):
2429
2194
  c2 = arc_list[1]
2430
2195
  if not c1[0] > c2[0]:
2431
2196
  center = None
2197
+
2198
+ logger.debug("end of get_center_arcs: -> %s", center)
2432
2199
  return center
2433
2200
 
2434
2201
  def get_center_dim(self, mm):
@@ -2487,6 +2254,63 @@ class Geometry(object):
2487
2254
  borders += 1
2488
2255
  return (ok, borders)
2489
2256
 
2257
+ def check_airgap(self, startangle, endangle):
2258
+ logger.debug("begin check_airgap")
2259
+ area_id_list = [a.id for a in self.list_of_areas()]
2260
+
2261
+ def delete_id(id):
2262
+ try:
2263
+ i = area_id_list.index(id)
2264
+ except ValueError:
2265
+ return
2266
+ area_id_list[i] = 0
2267
+ # ---
2268
+ def append_area(alist, a):
2269
+ for my_a in alist:
2270
+ if my_a.is_in_touch_with_area(self, a):
2271
+ alist.append(a)
2272
+ delete_id(a.id)
2273
+ return True
2274
+ return False
2275
+ # ---
2276
+ for area in self.area_list:
2277
+ if not area.id in area_id_list:
2278
+ continue
2279
+
2280
+ for a in self.area_list:
2281
+ if area.id == a.id:
2282
+ continue
2283
+ if not a.id in area_id_list:
2284
+ continue
2285
+
2286
+ if area.the_area_is_inside_area(a):
2287
+ delete_id(a.id)
2288
+
2289
+ # collect remaining areas
2290
+ area_list = [a for a in self.area_list if a.id in area_id_list]
2291
+ group_list = {}
2292
+ for area in area_list:
2293
+ if not area.id in area_id_list:
2294
+ continue
2295
+ group_list[area.id] = [area]
2296
+ delete_id(area.id)
2297
+ for a in self.area_list:
2298
+ if area.id == a.id:
2299
+ continue
2300
+ if not a.id in area_id_list:
2301
+ continue
2302
+ if append_area(group_list[area.id], a):
2303
+ continue
2304
+
2305
+ area_list = [a for a in self.area_list if a.id in area_id_list]
2306
+ for area in area_list:
2307
+ group_list[area.id] = [area]
2308
+
2309
+ area_id_list = [int(x) for x in group_list.keys()]
2310
+
2311
+ logger.debug("end check_airgap: return %s", len(area_id_list) > 1)
2312
+ return len(area_id_list) > 1 # bad
2313
+
2490
2314
  def is_border_line(self, center, startangle, endangle, e, atol):
2491
2315
  if isinstance(e, Line):
2492
2316
  if np.isclose(startangle, endangle):
@@ -2647,6 +2471,14 @@ class Geometry(object):
2647
2471
 
2648
2472
  def create_auxiliary_lines(self, rightangle, leftangle):
2649
2473
  logger.debug("begin of create_auxiliary_lines")
2474
+ timer = Timer(start_it=True)
2475
+
2476
+ # for future (next release)
2477
+ # area_list = self.list_of_areas()
2478
+ # builder = AreaBuilder(geom=self)
2479
+ # builder.create_area_groups(area_list)
2480
+ # self.areagroup_list = builder.area_list
2481
+
2650
2482
  self.set_areas_inside_for_all_areas()
2651
2483
 
2652
2484
  logger.debug("-> start create_auxiliary_lines")
@@ -2655,7 +2487,8 @@ class Geometry(object):
2655
2487
  for area in self.list_of_areas():
2656
2488
  if self.create_aux_lines(area, rightangle, leftangle):
2657
2489
  done = True
2658
-
2490
+ t = timer.stop("-- auxiliary lines in %0.4f seconds --")
2491
+ self.journal.put('time_auxiliary_lines', t)
2659
2492
  logger.debug("end of create_auxiliary_lines")
2660
2493
  return done
2661
2494
 
@@ -2664,7 +2497,7 @@ class Geometry(object):
2664
2497
 
2665
2498
  areas_inside = area.areas_inside.values()
2666
2499
  if not areas_inside:
2667
- logger.debug("end create_aux_lines() for %s (no areas inside)",
2500
+ logger.debug("end of create_aux_lines() for %s (no areas inside)",
2668
2501
  area.get_id())
2669
2502
  return False
2670
2503
 
@@ -2861,21 +2694,22 @@ class Geometry(object):
2861
2694
  line = aux_line['line']
2862
2695
  n1 = self.find_the_node(aux_line['p1'])
2863
2696
  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))
2697
+ logger.debug("Line: n1=%s, n2=%s", n1, n2)
2698
+
2699
+ pts = self.split_and_get_intersect_points(line)
2700
+ if len(pts) != 2:
2701
+ logger.error("ERROR in create_aux_lines()")
2702
+ logger.debug("Points: %s", pts)
2703
+ logger.debug("Line: %s", line)
2704
+
2705
+ n1 = self.find_the_node(line.node1(ndec))
2706
+ n2 = self.find_the_node(line.node2(ndec))
2707
+ logger.debug("Line: n1=%s, n2=%s", n1, n2)
2872
2708
  if n1 and n2:
2873
- add_or_join(self,
2874
- n1,
2875
- n2,
2876
- aux_line['line'],
2877
- self.rtol,
2878
- self.atol)
2709
+ logger.debug("Create Line %s", aux_line['pattern'])
2710
+ self.add_element(line,
2711
+ rtol=self.rtol,
2712
+ atol=self.atol)
2879
2713
  logger.debug("=== Create auxiliary line: %s", aux_line)
2880
2714
  if aux_line['connect'] == 'child':
2881
2715
  for a in areas_inside:
@@ -2889,7 +2723,7 @@ class Geometry(object):
2889
2723
  logger.debug("end create_aux_lines() for %s (no iron)",
2890
2724
  area.get_id())
2891
2725
  return done
2892
-
2726
+ return done
2893
2727
  # -----------------
2894
2728
  def id_of_inside_area(p):
2895
2729
  for a in areas_inside:
@@ -2925,7 +2759,10 @@ class Geometry(object):
2925
2759
  # ----------
2926
2760
 
2927
2761
  # Arcs as additional auxiliary connections thru iron
2762
+ logger.debug("Additional Lines in %s", area.identifier())
2928
2763
  for a in area_to_parent_list:
2764
+ logger.debug("Area %s in Parent List", a.identifier())
2765
+
2929
2766
  mid_dist = (a.min_dist + a.max_dist) / 2
2930
2767
  mid_angle = (a.min_angle + a.max_angle) / 2
2931
2768
  arc = Arc(Element(center=self.center,
@@ -2949,12 +2786,14 @@ class Geometry(object):
2949
2786
  radius=mid_dist,
2950
2787
  start_angle=start_angle*180/np.pi,
2951
2788
  end_angle=end_angle*180/np.pi),
2952
- color=aux_color,
2789
+ color='black', #aux_color,
2953
2790
  linestyle=aux_linestyle)
2954
2791
  arc.set_attribute('iron_sep')
2955
2792
  self.split_and_get_intersect_points(arc)
2956
2793
  n = self.find_nodes(pts[0], pts[1])
2957
- self.add_edge(n[0], n[1], arc)
2794
+ self.add_or_join_edge(n[0], n[1], arc,
2795
+ rtol=self.rtol,
2796
+ atol=self.atol)
2958
2797
 
2959
2798
  logger.debug("end create_aux_lines() for %s",
2960
2799
  area.get_id())
@@ -3000,53 +2839,80 @@ class Geometry(object):
3000
2839
  dict12['deleted'] = True
3001
2840
  dict01['deleted'] = True
3002
2841
  line = Line(Element(start=n0, end=n2))
3003
- self.add_edge(n0, n2, line)
2842
+ self.add_element(line,
2843
+ rtol=self.rtol,
2844
+ atol=self.atol)
3004
2845
  return True
3005
2846
 
3006
- def delete_tiny_elements(self, mindist):
2847
+ def search_tiny_elements(self, mindist):
2848
+ logger.debug("begin of search_tiny_elements(%s)", mindist)
3007
2849
  if mindist == 0.0:
3008
- return
2850
+ return []
3009
2851
 
3010
2852
  edges = [edge for edge in self.g.edges(data=True)
3011
2853
  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))
2854
+
2855
+ logger.debug("end of search_tiny_elements: %s tiny elements found",
2856
+ len(edges))
2857
+ return edges
2858
+
2859
+ def delete_tiny_elements(self, mindist):
2860
+ logger.debug("begin of delete_tiny_elements(%s)", mindist)
2861
+ edges = self.search_tiny_elements(mindist)
2862
+ if not edges:
2863
+ logger.debug("-- no tiny elements found")
2864
+ return
2865
+
3015
2866
  deleted = 0
3016
2867
  for edge in edges:
3017
- if edge[2].get('deleted', False):
2868
+ n1 = edge[0]
2869
+ n2 = edge[1]
2870
+ el = edge[2]['object']
2871
+ logger.debug("-- %s: %s <-> %s", el.classname(), n1, n2)
2872
+ logger.debug("Edge: %s", el.classname())
2873
+
2874
+ if n1 is n2:
2875
+ logger.debug("-- delete edge with equal nodes")
2876
+ self._remove_edge(n1, n2)
2877
+ deleted += 1
3018
2878
  continue
3019
2879
 
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]]
2880
+ nbrs_n1 = [nbr for nbr in self.g.neighbors(n1)
2881
+ if not nodes_are_equal(nbr, n2)]
2882
+ nbrs_n2 = [nbr for nbr in self.g.neighbors(n2)
2883
+ if not nodes_are_equal(nbr, n1)]
2884
+
2885
+ if len(nbrs_n1) == 0 and len(nbrs_n2) == 0:
2886
+ # lonesome edge
2887
+ logger.debug("-- delete lonesome edge")
2888
+ self._remove_edge(n1, n2)
2889
+ deleted += 1
2890
+ continue
3024
2891
 
3025
2892
  if len(nbrs_n1) == 1:
3026
- if self._delete_a_tiny_element(edge[1], edge[0],
3027
- edge[2], nbrs_n1[0]):
2893
+ if self._delete_a_tiny_element(n2, n1, edge[2], nbrs_n1[0]):
3028
2894
  deleted += 1
3029
2895
  continue
3030
2896
 
3031
2897
  if len(nbrs_n2) == 1:
3032
- if self._delete_a_tiny_element(edge[0], edge[1],
3033
- edge[2], nbrs_n2[0]):
2898
+ if self._delete_a_tiny_element(n1, n2, edge[2], nbrs_n2[0]):
3034
2899
  deleted += 1
3035
2900
  continue
3036
2901
 
3037
2902
  if deleted:
3038
- logger.info("%s tiny elements deleted", deleted)
2903
+ logger.debug("%s tiny elements deleted", deleted)
2904
+ logger.debug("end of delete_tiny_elements")
3039
2905
  return
3040
2906
 
3041
2907
  def check_shaft_area(self, shaft):
3042
2908
  for a in self.list_of_areas():
3043
2909
  if not shaft.is_identical(a):
3044
2910
  if shaft.is_inside(a, self):
3045
- shaft.type = 6 # iron shaft (Zahn)
2911
+ shaft.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3046
2912
  return
3047
2913
  if shaft.is_touching(a):
3048
2914
  if not a.is_iron():
3049
- shaft.type = 6 # iron shaft (Zahn)
2915
+ shaft.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3050
2916
  return
3051
2917
 
3052
2918
  def mark_connecting_edges(self, windings):
@@ -3060,18 +2926,19 @@ class Geometry(object):
3060
2926
  for e in elist:
3061
2927
  e.init_attributes('lightblue', 'no_fsl')
3062
2928
 
3063
- def search_subregions(self):
2929
+ def search_subregions(self, startangle, endangle, single=False):
3064
2930
  if self.is_stator():
3065
- self.search_stator_subregions()
2931
+ self.search_stator_subregions(startangle, endangle, single=single)
3066
2932
  elif self.is_rotor():
3067
- self.search_rotor_subregions()
2933
+ self.search_rotor_subregions(startangle, endangle, single=single)
3068
2934
  else:
3069
2935
  logger.warning("no stator or rotor assigned")
3070
2936
  self.search_unknown_subregions()
3071
2937
  self.looking_for_corners()
3072
2938
 
3073
2939
  def get_windings(self, type):
3074
- windings = [a for a in self.list_of_areas() if a.type == type]
2940
+ windings = [a for a in self.list_of_areas()
2941
+ if a.is_type(type)]
3075
2942
  for w in windings:
3076
2943
  inside = []
3077
2944
  for a in self.list_of_areas():
@@ -3079,13 +2946,14 @@ class Geometry(object):
3079
2946
  if w.is_inside(a, self):
3080
2947
  inside.append(a)
3081
2948
  if inside:
3082
- w.set_type(0) # air
3083
- return [a for a in self.list_of_areas() if a.type == type]
2949
+ w.set_type(AREA.TYPE_AIR) # air
2950
+ return [a for a in self.list_of_areas()
2951
+ if a.is_type(type)]
3084
2952
 
3085
2953
  def collect_windings(self):
3086
2954
  logger.debug("begin of collect_windings")
3087
- good_windings = self.get_windings(2)
3088
- ugly_windings = self.get_windings(12)
2955
+ good_windings = self.get_windings(AREA.TYPE_WINDINGS)
2956
+ ugly_windings = self.get_windings(AREA.TYPE_WINDINGS_OR_AIR)
3089
2957
 
3090
2958
  logger.debug("-- %s good and %s ugly windings",
3091
2959
  len(good_windings),
@@ -3097,8 +2965,8 @@ class Geometry(object):
3097
2965
 
3098
2966
  if not good_windings:
3099
2967
  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]
2968
+ [w.set_type(AREA.TYPE_WINDINGS) for w in ugly_windings]
2969
+ return [a for a in self.list_of_areas() if a.is_type(AREA.TYPE_WINDINGS)]
3102
2970
 
3103
2971
  # ggod and ugly windings available
3104
2972
  found = True
@@ -3106,27 +2974,28 @@ class Geometry(object):
3106
2974
  found = False
3107
2975
  for a in ugly_windings:
3108
2976
  if a.is_touching_areas(good_windings):
3109
- a.set_type(2)
2977
+ a.set_type(AREA.TYPE_WINDINGS)
3110
2978
  found = True
3111
2979
 
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]
2980
+ good_windings = [a for a in self.list_of_areas()
2981
+ if a.is_type(AREA.TYPE_WINDINGS)]
2982
+ ugly_windings = [a for a in self.list_of_areas()
2983
+ if a.is_type(AREA.TYPE_WINDINGS_OR_AIR)]
3114
2984
 
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]
2985
+ [w.set_type(AREA.TYPE_AIR) for w in ugly_windings]
2986
+ good_windings = [a for a in self.list_of_areas()
2987
+ if a.is_type(AREA.TYPE_WINDINGS)]
3117
2988
 
3118
- logger.debug("return %s bad windings as good windings", len(good_windings))
2989
+ logger.debug("return bad and ugly windings as %s good windings", len(good_windings))
3119
2990
  logger.debug("end of collect_windings")
3120
2991
  return good_windings
3121
2992
 
3122
- def search_stator_subregions(self, place=''):
2993
+ def search_stator_subregions(self,
2994
+ startangle,
2995
+ endangle,
2996
+ single=False):
3123
2997
  logger.debug("Begin of search_stator_subregions")
3124
2998
 
3125
- if place == 'in':
3126
- self.is_inner = True
3127
- elif place == 'out':
3128
- self.is_inner = False
3129
-
3130
2999
  if self.alfa == 0.0:
3131
3000
  self.alfa = np.pi * 2.0
3132
3001
 
@@ -3141,18 +3010,20 @@ class Geometry(object):
3141
3010
  self.max_radius)
3142
3011
 
3143
3012
  windings = self.collect_windings()
3144
- [a.set_type(0) for a in self.list_of_areas() if a.type == 12]
3013
+ [a.set_type(AREA.TYPE_AIR) for a in self.list_of_areas()
3014
+ if a.is_type(AREA.TYPE_WINDINGS_OR_AIR)]
3145
3015
  windings_found = len(windings)
3146
3016
  logger.debug("%d windings found", windings_found)
3017
+ self.has_windings = windings_found > 0
3147
3018
 
3148
3019
  if windings_found > 1:
3149
3020
  windings_surface = [[w.surface, w] for w in windings]
3150
3021
  windings_surface.sort(reverse=True)
3151
- max_size = windings_surface[0][0]
3152
- for sz, w in windings_surface:
3022
+ max_size, max_w = windings_surface[0]
3023
+ for sz, w in windings_surface[1:]:
3153
3024
  logger.debug("winding size = %s", sz)
3154
- if sz / max_size < 0.95:
3155
- w.set_type(0)
3025
+ if sz / max_size < 0.80:
3026
+ w.set_type(AREA.TYPE_AIR)
3156
3027
  if sz / max_size < 0.2:
3157
3028
  windings_found -= 1
3158
3029
  windings = [a for a in self.list_of_areas()
@@ -3160,8 +3031,9 @@ class Geometry(object):
3160
3031
  if windings_found > 2 and len(windings) == 1:
3161
3032
  logger.info("no windings remaining")
3162
3033
  # 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()]
3034
+ [w.set_type(AREA.TYPE_AIR) for w in windings]
3035
+ [a.set_type(AREA.TYPE_IRON) for a in self.list_of_areas()
3036
+ if a.is_iron()]
3165
3037
  windings = []
3166
3038
  elif len(windings) < windings_found:
3167
3039
  logger.info("%d windings remaining", len(windings))
@@ -3197,7 +3069,8 @@ class Geometry(object):
3197
3069
  self.wdg_is_mirrored = False
3198
3070
 
3199
3071
  # air or iron near windings and near airgap ?
3200
- air_areas = [a for a in self.list_of_areas() if a.type == 9]
3072
+ air_areas = [a for a in self.list_of_areas()
3073
+ if a.is_type(AREA.TYPE_AIR_OR_IRON)]
3201
3074
  for a in air_areas:
3202
3075
  if a.around_windings(windings, self):
3203
3076
  logger.debug("Area %s", a.identifier())
@@ -3211,7 +3084,7 @@ class Geometry(object):
3211
3084
  if a.close_to_startangle:
3212
3085
  if not wdg_close_to_startangle:
3213
3086
  logger.debug("#0.1 ===> close to startangle")
3214
- a.type = 6 # iron shaft (Zahn)
3087
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3215
3088
  continue
3216
3089
 
3217
3090
  if a.close_to_endangle:
@@ -3219,10 +3092,10 @@ class Geometry(object):
3219
3092
  logger.debug("#0.2 ===> close to endangle")
3220
3093
  if(a.min_angle < wdg_min_angle and
3221
3094
  a.close_to_ag):
3222
- a.type = 0 # air
3095
+ a.set_type(AREA.TYPE_AIR) # air
3223
3096
  continue
3224
3097
 
3225
- a.type = 6 # iron shaft (Zahn)
3098
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3226
3099
  continue
3227
3100
 
3228
3101
  if greater_equal(a.min_air_angle, wdg_min_angle):
@@ -3232,53 +3105,54 @@ class Geometry(object):
3232
3105
 
3233
3106
  if a.close_to_endangle and self.is_mirrored():
3234
3107
  logger.debug("#1 ===> endangle and mirrored <===")
3235
- a.type = 0 # air
3108
+ a.set_type(AREA.TYPE_AIR) # air
3236
3109
  elif less_equal(a.max_air_angle, wdg_max_angle):
3237
3110
  logger.debug("#2 ===> %s <= %s <===",
3238
3111
  a.max_air_angle,
3239
3112
  wdg_max_angle)
3240
- a.type = 0 # air
3113
+ a.set_type(AREA.TYPE_AIR) # air
3241
3114
  else:
3242
3115
  logger.debug("#3 ===> %s > %s <===",
3243
3116
  a.max_air_angle,
3244
3117
  wdg_max_angle)
3245
- a.type = 6 # iron shaft (Zahn)
3118
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3246
3119
  else:
3247
3120
  logger.debug("#4 ===> %s < %s <===",
3248
3121
  a.min_air_angle,
3249
3122
  wdg_min_angle)
3250
- a.type = 6 # iron shaft (Zahn)
3123
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3251
3124
  else:
3252
3125
  logger.debug("#5 not around windings")
3253
- a.type = 6 # iron shaft (Zahn)
3126
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3254
3127
 
3255
3128
  # yoke or shaft ?
3256
- iron_areas = [a for a in self.list_of_areas() if a.type == 5]
3129
+ iron_areas = [a for a in self.list_of_areas()
3130
+ if a.is_type(AREA.TYPE_YOKE)]
3257
3131
  for a in iron_areas:
3258
3132
  if a.around_windings(windings, self):
3259
3133
  if less(a.min_dist, wdg_max_dist):
3260
3134
  if less_equal(a.max_dist, wdg_max_dist):
3261
- a.type = 6 # iron shaft (Zahn)
3135
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3262
3136
  else:
3263
3137
  dist_low = wdg_max_dist - a.min_dist
3264
3138
  dist_up = a.max_dist - wdg_max_dist
3265
3139
  if dist_low > dist_up:
3266
- a.type = 6 # iron shaft (Zahn)
3140
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3267
3141
 
3268
- shaft_areas = [a for a in self.list_of_areas() if a.type == 10]
3142
+ shaft_areas = [a for a in self.list_of_areas()
3143
+ if a.is_type(AREA.TYPE_SHAFT)]
3269
3144
  if shaft_areas:
3270
3145
  if len(shaft_areas) > 1:
3271
- logger.warn("More than two shafts ?!?")
3146
+ logger.debug("More than one shaft in stator ?!?")
3272
3147
  return
3273
3148
  self.check_shaft_area(shaft_areas[0])
3149
+ logger.debug("End of search_stator_subregions")
3274
3150
 
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
3151
+ def search_rotor_subregions(self,
3152
+ startangle,
3153
+ endangle,
3154
+ single=False):
3155
+ logger.debug("Begin of search_rotor_subregions")
3282
3156
 
3283
3157
  if self.alfa == 0.0:
3284
3158
  self.alfa = np.pi * 2.0
@@ -3290,20 +3164,65 @@ class Geometry(object):
3290
3164
  self.alfa,
3291
3165
  self.center,
3292
3166
  self.min_radius,
3293
- self.max_radius)
3167
+ self.max_radius,
3168
+ startangle,
3169
+ endangle)
3294
3170
  if t in types:
3295
3171
  types[t] += 1
3296
3172
  else:
3297
3173
  types[t] = 1
3298
3174
 
3299
- if 10 in types:
3175
+ if AREA.TYPE_SHAFT in types:
3300
3176
  logger.debug("Shaft is available")
3301
3177
 
3302
- if 4 in types: # magnet rectangle
3303
- if types[4] > 1:
3304
- logger.debug("%s embedded magnets in rotor", types[4])
3178
+ if AREA.TYPE_MAGNET_RECT_NEAR_AIRGAP in types: # magnet rectangle near ag
3179
+ if AREA.TYPE_MAGNET_RECT in types: # magnet rectangle
3180
+ mag_rectangles = [a for a in self.list_of_areas()
3181
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3182
+ for a in mag_rectangles:
3183
+ if self.is_inner:
3184
+ dist_1 = a.max_dist + 0.5
3185
+ dist_2 = self.max_radius + 5
3186
+ else:
3187
+ dist_1 = a_min_dist - 0.5
3188
+ dist_2 = self.min_radius - 5
3189
+
3190
+ mid_angle = a.get_mid_angle(self.center)
3191
+ p1 = point(self.center, dist_1, mid_angle)
3192
+ p2 = point(self.center, dist_2, mid_angle)
3193
+ line = Line(Element(start=p1, end=p2))
3194
+ logger.debug("magnet intersect line: %s to %s", p1, p2)
3195
+ pts = self.split_and_get_intersect_points(line,
3196
+ aktion=False,
3197
+ include_end=False)
3198
+ logger.debug("magnet intersect points: %s", pts)
3199
+ if not pts:
3200
+ a.set_type(AREA.TYPE_MAGNET_UNDEFINED)
3201
+ mag_rectangles = [a for a in self.list_of_areas()
3202
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3203
+ if mag_rectangles: # undo
3204
+ logger.debug("--- undo ---")
3205
+ [a.set_type(AREA.TYPE_MAGNET_RECT) for a in self.list_of_areas()
3206
+ if a.is_type(AREA.TYPE_MAGNET_UNDEFINED)]
3207
+ else:
3208
+ logger.debug("--- set type 3 ---")
3209
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in self.list_of_areas()
3210
+ if a.is_type(AREA.TYPE_MAGNET_RECT_NEAR_AIRGAP)]
3211
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in self.list_of_areas()
3212
+ if a.is_type(AREA.TYPE_MAGNET_UNDEFINED)]
3213
+ types.pop(AREA.TYPE_MAGNET_RECT)
3214
+ else:
3215
+ # set magnet
3216
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in self.list_of_areas()
3217
+ if a.is_type(AREA.TYPE_MAGNET_RECT_NEAR_AIRGAP)]
3218
+ types[AREA.TYPE_MAGNET_RECT_NEAR_AIRGAP] = 0
3219
+
3220
+ if AREA.TYPE_MAGNET_RECT in types: # magnet rectangle
3221
+ if types[AREA.TYPE_MAGNET_RECT] > 1:
3222
+ logger.debug("%s embedded magnets in rotor",
3223
+ types[AREA.TYPE_MAGNET_RECT])
3305
3224
  emb_mag_areas = [a for a in self.list_of_areas()
3306
- if a.type == 4]
3225
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3307
3226
  [a.set_surface(self.is_mirrored()) for a in emb_mag_areas]
3308
3227
  max_surface = 0.0
3309
3228
  max_phi = 0.0
@@ -3315,30 +3234,34 @@ class Geometry(object):
3315
3234
  for a in emb_mag_areas:
3316
3235
  if a.surface < max_surface * 0.20: # too small
3317
3236
  logger.debug(
3318
- "embedded magnet too small: convert to air")
3237
+ "embedded magnet %s too small: convert to air",
3238
+ a.identifier())
3319
3239
  logger.debug("max surface : %s", max_surface)
3320
3240
  logger.debug("area surface: %s", a.surface)
3321
3241
  logger.debug("max phi : %s", max_phi)
3322
3242
  logger.debug("area phi : %s", a.phi)
3323
3243
  if not np.isclose(a.phi, max_phi):
3324
- a.set_type(0) # air
3244
+ a.set_type(AREA.TYPE_AIR) # air
3325
3245
 
3326
3246
  # set iron
3327
- [a.set_type(1) for a in self.list_of_areas() if a.type == 3]
3247
+ [a.set_type(AREA.TYPE_IRON) for a in self.list_of_areas()
3248
+ if a.is_type(AREA.TYPE_MAGNET_AIRGAP)]
3328
3249
 
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]
3250
+ iron_mag_areas = [a for a in self.list_of_areas()
3251
+ if a.is_type(AREA.TYPE_MAGNET_OR_IRON)]
3252
+ air_mag_areas = [a for a in self.list_of_areas()
3253
+ if a.is_type(AREA.TYPE_MAGNET_OR_AIR)]
3331
3254
  ag_areas = [a for a in self.list_of_areas() if a.close_to_ag]
3332
3255
  if len(ag_areas) == 1:
3333
3256
  if len(iron_mag_areas) == 1:
3334
- [a.set_type(3) for a in iron_mag_areas]
3257
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in iron_mag_areas]
3335
3258
  iron_mag_areas = []
3336
3259
  if len(air_mag_areas) == 1:
3337
- [a.set_type(3) for a in air_mag_areas]
3260
+ [a.set_type(AREA.TYPE_MAGNET_AIRGAP) for a in air_mag_areas]
3338
3261
  air_mag_areas = []
3339
3262
 
3340
- [a.set_type(1) for a in iron_mag_areas]
3341
- [a.set_type(0) for a in air_mag_areas]
3263
+ [a.set_type(AREA.TYPE_IRON) for a in iron_mag_areas]
3264
+ [a.set_type(AREA.TYPE_AIR) for a in air_mag_areas]
3342
3265
 
3343
3266
  if self.is_mirrored():
3344
3267
  mid_alfa = round(self.alfa, 3)
@@ -3348,44 +3271,63 @@ class Geometry(object):
3348
3271
  mag_areas = [[abs(round(a.phi, 3) - mid_alfa),
3349
3272
  a.id,
3350
3273
  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]
3274
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3275
+
3276
+ shaft_areas = [a for a in self.list_of_areas()
3277
+ if a.is_type(AREA.TYPE_SHAFT)]
3382
3278
  if shaft_areas:
3383
3279
  if len(shaft_areas) > 1:
3384
- logger.warn("More than two shafts ?!?")
3280
+ logger.debug("More than one shaft in rotor ?!?")
3385
3281
  return
3386
3282
  self.check_shaft_area(shaft_areas[0])
3387
3283
 
3388
- logger.info("end of search_rotor_subregions")
3284
+ magnets = [a for a in self.list_of_areas()
3285
+ if a.is_magnet()]
3286
+ self.has_magnets = len(magnets) > 0
3287
+ for m in magnets:
3288
+ m.phi = m.get_magnet_orientation()
3289
+ logger.debug("%s magnets found in rotor", len(magnets))
3290
+
3291
+ if not single:
3292
+ if not magnets:
3293
+ [a.set_type(AREA.TYPE_AIR) for a in self.list_of_areas()]
3294
+ self.search_stator_subregions(startangle, endangle, single=single)
3295
+ return
3296
+
3297
+ logger.debug("end of search_rotor_subregions")
3298
+
3299
+ def recalculate_magnet_orientation(self):
3300
+ logger.debug("begin of recalculate_magnet_orientation")
3301
+ magnet_areas = [a for a in self.list_of_areas()
3302
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3303
+ self.recalculate_magnet_group(magnet_areas)
3304
+
3305
+ magnet_areas = [a for a in self.list_of_areas()
3306
+ if a.is_type(AREA.TYPE_MAGNET_AIRGAP)]
3307
+ for a in magnet_areas:
3308
+ a.phi = a.get_magnet_orientation()
3309
+ logger.debug("end of recalculate_magnet_orientation")
3310
+
3311
+ def recalculate_magnet_group(self, areas):
3312
+ if not areas:
3313
+ return
3314
+ elements = []
3315
+ for a in areas:
3316
+ elements += a.elements()
3317
+ geom = Geometry(elements, center=self.center)
3318
+ builder = AreaBuilder(geom=geom)
3319
+ if builder.create_area_groups(areas):
3320
+ return # bad
3321
+ group_list = builder.area_list
3322
+ self.areagroup_list = group_list
3323
+ for group in group_list:
3324
+ if not group.is_magnet_rectangle():
3325
+ logger.debug("Warning: group is not a rectangle")
3326
+ group.set_type(AREA.TYPE_MAGNET_RECT)
3327
+ phi = group.get_magnet_orientation()
3328
+ for a in group.areas_of_group:
3329
+ logger.debug("Replace phi %s by %s", a.phi, phi)
3330
+ a.phi = phi
3389
3331
 
3390
3332
  def search_unknown_subregions(self):
3391
3333
  logger.debug("begin of search_unknown_subregions")
@@ -3401,22 +3343,31 @@ class Geometry(object):
3401
3343
  else:
3402
3344
  types[t] = 1
3403
3345
 
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)
3346
+ if types.get(AREA.TYPE_MAGNET_RECT, 0) > 1:
3347
+ logger.debug("%s embedded magnets in rotor",
3348
+ types[AREA.TYPE_MAGNET_RECT])
3349
+ emb_mag_areas = [a for a in self.list_of_areas()
3350
+ if a.is_type(AREA.TYPE_MAGNET_RECT)]
3351
+ [a.set_surface(self.is_mirrored()) for a in emb_mag_areas]
3352
+ max_surface = 0.0
3353
+ for a in emb_mag_areas:
3354
+ max_surface = max(max_surface, a.surface)
3413
3355
 
3414
- for a in emb_mag_areas:
3415
- if a.surface < max_surface * 0.20: # too small
3416
- a.set_type(0) # air
3356
+ for a in emb_mag_areas:
3357
+ if a.surface < max_surface * 0.20: # too small
3358
+ a.set_type(AREA.TYPE_AIR) # air
3417
3359
 
3418
3360
  logger.debug("end of search_unknown_subregions")
3419
3361
 
3362
+ def magnets_in_the_middle(self, midangle):
3363
+ mag_areas = [a for a in self.list_of_areas()
3364
+ if a.is_magnet()]
3365
+ logger.debug("%s magnets in geom", len(mag_areas))
3366
+ for a in mag_areas:
3367
+ if a.max_angle > midangle and a.min_angle < midangle:
3368
+ return True
3369
+ return False
3370
+
3420
3371
  def looking_for_corners(self):
3421
3372
  if self.is_inner:
3422
3373
  logger.debug("looking_for_corners: inner")
@@ -3434,14 +3385,14 @@ class Geometry(object):
3434
3385
 
3435
3386
  def num_areas_of_type(self, type):
3436
3387
  return len([area for area in self.list_of_areas()
3437
- if area.type == type])
3388
+ if area.is_type(type)])
3438
3389
 
3439
3390
  def num_of_windings(self):
3440
- return self.num_areas_of_type(2)
3391
+ return self.num_areas_of_type(AREA.TYPE_WINDINGS)
3441
3392
 
3442
3393
  def area_close_to_endangle(self, type):
3443
3394
  return len([area for area in self.list_of_areas()
3444
- if area.type == type and area.close_to_endangle])
3395
+ if area.is_type(type) and area.close_to_endangle])
3445
3396
 
3446
3397
  def corners_dont_match(self):
3447
3398
  if self.is_mirrored():
@@ -3460,7 +3411,7 @@ class Geometry(object):
3460
3411
  return True
3461
3412
  return False
3462
3413
 
3463
- def search_appendices(self):
3414
+ def get_appendices(self):
3464
3415
  c = 0
3465
3416
  end_nodes = []
3466
3417
  for n in self.g.nodes():
@@ -3473,154 +3424,202 @@ class Geometry(object):
3473
3424
 
3474
3425
  if not is_Circle(el):
3475
3426
  end_nodes.append((n, nbrs[0], el))
3427
+ return end_nodes
3428
+
3429
+ def connect_all_nodes(self,
3430
+ additional_nodes=[],
3431
+ rtol=1e-04, atol=1e-04,
3432
+ main=False):
3433
+ logger.debug("begin of connect_all_nodes")
3434
+ timer = Timer(start_it=True)
3435
+ nodes_list = self.get_nodes()
3436
+ c1 = 0
3437
+ c2 = 0
3438
+ additional_nodes_list = []
3439
+ for n in additional_nodes:
3440
+ if not n in nodes_list:
3441
+ additional_nodes_list.append(n)
3442
+ c1 += 1
3443
+ else:
3444
+ c2 += 1
3445
+ logger.debug("connect_all_nodes: %s added, %s already available", c1, c2)
3446
+
3447
+ corr = self.connect_nodes(nodes_list,
3448
+ rtol=rtol, atol=atol)
3449
+ if additional_nodes_list:
3450
+ corr += self.connect_nodes(additional_nodes_list,
3451
+ omit_single_element=True,
3452
+ rtol=rtol, atol=atol)
3453
+ t = timer.stop("-- {} connections in %0.4f seconds --".format(corr))
3454
+ if main:
3455
+ self.journal.put_nodes_connected(corr)
3456
+ self.journal.put('time_node_connections', t)
3457
+ logger.debug("==> %s nodes connected", corr)
3458
+ logger.debug("end of connect_all_nodes")
3459
+ return corr
3460
+
3461
+ def connect_nodes(self, nodes_list,
3462
+ rtol=1e-03, atol=1e-03,
3463
+ omit_single_element=False,
3464
+ ignore_end=False):
3465
+ logger.debug("begin of connect_nodes(rtol=%s, atol=%s)", rtol, atol)
3466
+ logger.debug("-- %s nodes exist", len(nodes_list))
3476
3467
 
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
3468
+ count = 0
3469
+ for n in nodes_list:
3470
+ if self.node_connected(n,
3471
+ rtol=rtol, atol=atol,
3472
+ omit_single_element=omit_single_element,
3473
+ ignore_end=ignore_end):
3474
+ count += 1
3475
+
3476
+ logger.debug("end of connect_nodes => %s", count)
3477
+ return count
3478
+
3479
+ def connect_all_appendices(self, rtol=1e-04, atol=1e-04, main=False):
3480
+ logger.debug("begin of connect_all_appendices")
3481
+ timer = Timer(start_it=True)
3482
+ appendix_list = self.get_appendices()
3483
+ before = len(appendix_list)
3484
+ if main:
3485
+ self.journal.put_appendices(len(appendix_list))
3486
+ corr = self.connect_appendices(appendix_list, rtol=rtol, atol=atol)
3487
+ corr_total = corr
3488
+
3489
+ if corr < before:
3490
+ appendix_list = self.get_appendices()
3491
+ before = len(appendix_list)
3492
+ corr = self.connect_appendices(appendix_list, rtol=rtol, atol=atol)
3493
+ corr_total += corr
3494
+ t = timer.stop("-- {} connections in %0.4f seconds --".format(corr))
3495
+ if main:
3496
+ self.journal.put_appendices_connected(corr_total)
3497
+ self.journal.put('time_app_connections', t)
3498
+
3499
+ logger.debug("==> %s appendices connected", corr_total)
3500
+ logger.debug("end of connect_all_appendices")
3501
+ return corr_total
3502
+
3503
+ def connect_appendices(self, appendix_list, rtol=1e-03, atol=1e-03, ignore_end=False):
3504
+ logger.debug("begin of connect_appendices(rtol=%s, atol=%s)", rtol, atol)
3505
+ logger.debug("-- %s appendices exist", len(appendix_list))
3506
+ self.fixed_appendices = []
3507
+
3508
+ count = 0
3509
+ for n0, n1, el in appendix_list:
3510
+ logger.debug("Appendix Node at %s", n0)
3511
+ if n0 in self.fixed_appendices:
3512
+ logger.debug(" - Node already fixed")
3481
3513
  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
3514
+ count += self.connect_appendix(n0, n1, el,
3515
+ rtol=rtol, atol=atol,
3516
+ ignore_end=ignore_end)
3492
3517
 
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]))
3518
+ self.fixed_appendices = []
3500
3519
 
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
3520
+ logger.debug("end of connect_appendices => %s", count)
3521
+ return count
3505
3522
 
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")
3523
+ def connect_appendix(self, n0, n1, el, rtol=1e-03, atol=1e-03, ignore_end=False):
3524
+ logger.debug("begin of connect_appendix(%s, rtol=%s, atol=%s)", n0, rtol, atol)
3521
3525
 
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")
3526
+ if points_are_close(n0, n1, rtol=1e-04, atol=1e-04):
3527
+ # a very tiny appendix
3528
+ d = distance(n0, n1)
3529
+ if less(d, 0.001):
3530
+ logger.debug("-- WARNING: a very tiny appendix of length %s", d)
3531
+ nbr_list = [nbr for nbr in self.g.neighbors(n1)
3532
+ if not nodes_are_equal(nbr, n0)]
3527
3533
 
3528
- def search_overlapping_elements(self):
3529
- logger.debug("begin of search_overlapping_elements")
3530
- count = 0
3534
+ if len(nbr_list) == 0:
3535
+ logger.debug("end of connect_appendix: => lonesome appendix -> no action")
3536
+ return 0
3531
3537
 
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])
3538
+ logger.debug(" remove it")
3539
+ self._remove_edge(n0, n1)
3540
+ return 1
3546
3541
 
3547
- if not edges:
3548
- continue
3542
+ if self.node_connected(n0, rtol=rtol, atol=atol, ignore_end=ignore_end):
3543
+ logger.debug("end of connect_appendix: %s CONNECTED", n0)
3544
+ return 1
3549
3545
 
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
3546
+ nn = self.find_other_node(n0)
3547
+ if not nn:
3548
+ logger.debug("end of connect_appendix: => No node found nearby")
3549
+ return 0
3571
3550
 
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
3551
+ logger.debug("Node %s is near %s", n0, nn)
3552
+ logger.debug(" -- appendix %s from %s to %s", el.classname(), n0, n1)
3553
+ try:
3554
+ logger.debug("remove edge of %s from %s to %s",
3555
+ el.classname(), el.p1, el.p2)
3556
+ self._remove_edge(n0, n1)
3557
+ except Exception:
3558
+ f = Path(__file__)
3559
+ msg = "{} #{}: delete of {} - {} failed".format(
3560
+ f.name, lineno(),
3561
+ n0, n1)
3562
+ self.journal.put_warning(msg)
3563
+ logger.warning("WARNING: %s", msg)
3564
+ logger.debug("-- Element %s", el)
3565
+
3566
+ self.add_or_join_edge(nn, n1, el,
3567
+ rtol=rtol,
3568
+ atol=atol)
3569
+ self.fixed_appendices.append(nn)
3570
+ logger.debug("end of connect_appendix: connected")
3571
+ return 1
3580
3572
 
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)
3573
+ def delete_appendices(self, appendix_list):
3574
+ c = 0
3575
+ for n0, n1, e in appendix_list:
3576
+ logger.debug("Deadend Node at %s", n0)
3577
+ c += self.remove_appendix(n0, n1)
3578
+ return c
3585
3579
 
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
3580
+ def delete_all_appendices(self):
3581
+ logger.debug("begin of delete_all_appendices")
3582
+ appendix_list = self.get_appendices()
3583
+ app = len(appendix_list)
3584
+ if not app:
3585
+ logger.debug("end of delete_all_appendices: no appendices")
3586
+ return
3587
+
3588
+ corr = self.delete_appendices(appendix_list)
3589
+ self.journal.put_appendices_deleted(corr)
3593
3590
 
3594
- logger.debug(" -- corrected")
3595
- logger.debug("end of correct_overlapping_lines")
3591
+ logger.debug("==> %s appendices removed", corr)
3592
+ logger.debug("end of delete_all_appendices")
3596
3593
 
3597
- def connect_arc_or_line(self, n, el, n1, n2, tol=1e-05):
3598
- elements = el.split([n], rtol=tol, atol=tol)
3594
+ def connect_arc_or_line(self, n, el, n1, n2, rtol=1e-03, atol=1e-03, mdec=0):
3595
+ elements = el.split([n], rtol=rtol, atol=atol, mdec=mdec)
3599
3596
  if len(elements) != 2:
3600
- logger.info("Not 2 Elements")
3601
- logger.info("Node {} in Element {}".format(n, el))
3597
+ logger.warning("Not 2 Elements")
3598
+ logger.warning("split(rtol=%s, atol=%s, mdec=%s)", rtol, atol, mdec)
3599
+ logger.warning("Node {} in Element {}".format(n, el))
3602
3600
  for e in elements:
3603
3601
  logger.info(e)
3604
3602
  assert(len(elements) == 2)
3605
3603
 
3606
3604
  logger.debug("HIT! Node %s is in %s", n, el)
3607
- logger.debug(" => remove from %s to %s", n1, n2)
3605
+ logger.debug(" => remove %s", el)
3606
+ self.fixed_appendices.append(n1)
3607
+ self.fixed_appendices.append(n2)
3608
3608
  self._remove_edge(n1, n2)
3609
3609
 
3610
3610
  for element in elements:
3611
3611
  logger.debug("Split: %s", element)
3612
3612
 
3613
- rtol = tol
3614
- atol = tol
3615
-
3616
3613
  for element in elements:
3617
3614
  n1_inside = element.is_point_inside(n1,
3618
3615
  rtol=rtol,
3619
3616
  atol=atol,
3617
+ mdec=mdec,
3620
3618
  include_end=True)
3621
3619
  n2_inside = element.is_point_inside(n2,
3622
3620
  rtol=rtol,
3623
3621
  atol=atol,
3622
+ mdec=mdec,
3624
3623
  include_end=True)
3625
3624
  if n1_inside and n2_inside:
3626
3625
  logger.error("FATAL: both inside %s", element)
@@ -3629,37 +3628,63 @@ class Geometry(object):
3629
3628
  else:
3630
3629
  if n1_inside:
3631
3630
  logger.debug(" <= #1 add from %s to %s", n1, n)
3632
- self.add_edge(n1, n, element)
3631
+ self.add_element(element,
3632
+ rtol=self.rtol,
3633
+ atol=self.atol)
3633
3634
  else:
3634
3635
  logger.debug(" <= #2 add from %s to %s", n2, n)
3635
- self.add_edge(n2, n, element)
3636
+ self.add_element(element,
3637
+ rtol=self.rtol,
3638
+ atol=self.atol)
3636
3639
 
3637
- def connect_circle(self, n, el, n1, n2, tol=0.01):
3638
- elements = el.split([n], rtol=tol, atol=tol)
3640
+ def connect_circle(self, n, el, n1, n2, rtol=1e-03, atol=1e-03):
3641
+ elements = el.split([n], rtol=rtol, atol=atol)
3639
3642
  assert(len(elements) == 3)
3640
3643
 
3641
- logger.debug("Node %s is in %s", n, el)
3642
- logger.debug(" => remove from %s to %s", n1, n2)
3644
+ logger.debug("connect_circle: Node %s is in %s", n, el)
3645
+ logger.debug(" => remove %s from %s to %s", el.classname(), n1, n2)
3646
+ e = self.get_edge_element(n1, n2)
3647
+ if not e:
3648
+ logger.error("Element from %s to %s not found", n1, n2)
3649
+ else:
3650
+ logger.debug("Element to Remove: %s", e)
3643
3651
  self._remove_edge(n1, n2)
3652
+
3644
3653
  for element in elements:
3645
- nodes = self.find_nodes(element.start(), element.end())
3646
- self.add_edge(nodes[0], nodes[1], element)
3654
+ self.add_element(element,
3655
+ rtol=self.rtol,
3656
+ atol=self.atol)
3657
+
3658
+ def node_connected(self, n,
3659
+ rtol=1e-03, atol=1e-03,
3660
+ omit_single_element=False,
3661
+ ignore_end=False):
3662
+ mdec = 2
3663
+ count = 0
3664
+ el_list = []
3665
+ for n1, n2, el in self.elements_and_nodes(Shape):
3666
+ if not el.is_near(n):
3667
+ #logger.debug("Node %s is NOT near this edge", n)
3668
+ continue
3669
+ elif el.is_point_inside(n,
3670
+ rtol=rtol,
3671
+ atol=atol,
3672
+ mdec=mdec,
3673
+ include_end=False,
3674
+ ignore_end=ignore_end):
3675
+ logger.debug("Node %s is inside of an edge", n)
3676
+ el_list.append((n1, n2, el))
3647
3677
 
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
3678
+ if omit_single_element and len(el_list) < 2:
3679
+ return 0
3680
+
3681
+ for n1, n2, el in el_list:
3682
+ if is_Circle(el):
3683
+ self.connect_circle(n, el, n1, n2, rtol=rtol, atol=atol)
3684
+ else:
3685
+ self.connect_arc_or_line(n, el, n1, n2, rtol=rtol, atol=atol, mdec=mdec)
3686
+ count += 1
3687
+ return count
3663
3688
 
3664
3689
  def remove_appendix(self, n1, n2, incr_text=''):
3665
3690
  e_dict = self.g.get_edge_data(n1, n2)
@@ -3677,12 +3702,21 @@ class Geometry(object):
3677
3702
  logger.debug("%s remove_appendix(%s, %s)", incr_text, n1, n2)
3678
3703
  self._remove_edge(n1, n2)
3679
3704
  c = 1
3680
- nbrs = [nbr for nbr in self.g.neighbors(n2)]
3705
+ try:
3706
+ nbrs = [nbr for nbr in self.g.neighbors(n2)]
3707
+ except nx.NetworkXError:
3708
+ logger.debug("Node %s already deleted", n2)
3709
+ nbrs = []
3710
+
3681
3711
  if len(nbrs) == 1:
3682
3712
  c += self.remove_appendix(n2, nbrs[0], incr_text + '.')
3683
3713
  return c
3684
3714
 
3685
- def split_and_get_intersect_points(self, el, aktion=True):
3715
+ def adjust_all_points(self):
3716
+ for e in self.elements():
3717
+ e.adjust_points()
3718
+
3719
+ def split_and_get_intersect_points(self, el, aktion=True, include_end=True):
3686
3720
  logger.debug("begin of split_and_get_intersect_points")
3687
3721
  rtol = 1e-03
3688
3722
  atol = 1e-03
@@ -3691,12 +3725,15 @@ class Geometry(object):
3691
3725
  pts = e.intersect_shape(el,
3692
3726
  rtol=rtol,
3693
3727
  atol=atol,
3694
- include_end=True)
3728
+ include_end=include_end)
3695
3729
  if pts:
3730
+ logger.debug("Split %s", e)
3731
+ [logger.debug("-- intersect point %s", p) for p in pts]
3696
3732
  pts_inside = []
3697
3733
  pts_real = []
3698
3734
  for p in pts:
3699
- if not e.is_point_inside(p, rtol, atol, False):
3735
+ incl_end = is_Circle(e)
3736
+ if not e.is_point_inside(p, rtol, atol, include_end=incl_end):
3700
3737
  # get the real point
3701
3738
  n = self.find_the_node(p)
3702
3739
  if n:
@@ -3723,7 +3760,9 @@ class Geometry(object):
3723
3760
  logger.debug(
3724
3761
  "=== OMIT ELEMENT WITH SAME NODES ===")
3725
3762
  else:
3726
- self.add_edge(n[0], n[1], e)
3763
+ self.add_or_join_edge(n[0], n[1], e,
3764
+ rtol=rtol,
3765
+ atol=atol)
3727
3766
  points += pts_real
3728
3767
 
3729
3768
  logger.debug("end of split_and_get_intersect_points")
@@ -3737,6 +3776,30 @@ class Geometry(object):
3737
3776
  return True
3738
3777
  return False
3739
3778
 
3779
+ def _line_inside_magnets(self, p1, p2):
3780
+ for area in self.list_of_areas():
3781
+ if area.is_magnet():
3782
+ if area.is_point_inside(p1):
3783
+ if area.is_point_inside(p2):
3784
+ return True
3785
+ return False
3786
+
3787
+ def _line_inside_air(self, p1, p2):
3788
+ for area in self.list_of_areas():
3789
+ if area.is_air():
3790
+ if area.is_point_inside(p1):
3791
+ if area.is_point_inside(p2):
3792
+ return True
3793
+ return False
3794
+
3795
+ def _line_inside_not_iron(self, p1, p2):
3796
+ for area in self.list_of_areas():
3797
+ if area.is_shaft() or area.is_air() or area.is_magnet():
3798
+ if area.is_point_inside(p1):
3799
+ if area.is_point_inside(p2):
3800
+ return True
3801
+ return False
3802
+
3740
3803
  def inside_area_list(self, p):
3741
3804
  for area in self.list_of_areas():
3742
3805
  if area.is_point_inside(p):
@@ -3749,7 +3812,7 @@ class Geometry(object):
3749
3812
  d = distance(self.center, p)
3750
3813
  logger.debug("-- p = %s, dist = %s", p, d)
3751
3814
  for a in self.inside_area_list(p):
3752
- logger.debug("-- Area type = %s", a.type)
3815
+ logger.debug("-- Area type = %s", a.legend())
3753
3816
  logger.debug(" min=%s, max= %s", a.min_dist, a.max_dist)
3754
3817
  logger.debug(" close to start = %s", a.close_to_startangle)
3755
3818
  logger.debug(" close to end = %s", a.close_to_endangle)
@@ -3775,17 +3838,47 @@ class Geometry(object):
3775
3838
  p1 = p2
3776
3839
  continue
3777
3840
 
3778
- n = self.find_nodes(p1, p2)
3779
3841
  line = Line(Element(start=p1, end=p2),
3780
3842
  color='darkred',
3781
3843
  linestyle='dotted')
3782
- self.add_edge(n[0], n[1], line)
3783
- logger.debug("add line(%s, %s)", n[0], n[1])
3844
+ self.add_element(line,
3845
+ rtol=self.rtol,
3846
+ atol=self.atol)
3847
+ logger.debug("add line(%s)", line)
3784
3848
  created = True
3785
3849
  p1 = p2
3786
3850
 
3787
3851
  return created
3788
3852
 
3853
+ def create_lines_outside_magnets(self, points):
3854
+ logger.debug("begin of create_lines_outside_magnets")
3855
+ if not points:
3856
+ return False
3857
+ created = False
3858
+
3859
+ p1 = points[0]
3860
+ for p2 in points[1:]:
3861
+ logger.debug("try from %s to %s", p1, p2)
3862
+ if not points_are_close(p1, p2):
3863
+ logger.debug("Line from %s to %s", p1, p2)
3864
+ if self._line_inside_not_iron(p1, p2):
3865
+ logger.debug("- not in iron (%s, %s)", p1, p2)
3866
+ p1 = p2
3867
+ continue
3868
+
3869
+ line = Line(Element(start=p1, end=p2),
3870
+ color='darkred',
3871
+ linestyle='dotted')
3872
+ line.set_attribute('iron_sep')
3873
+ self.add_element(line,
3874
+ rtol=self.rtol,
3875
+ atol=self.atol)
3876
+ logger.debug("add line(%s)", line)
3877
+ created = True
3878
+ p1 = p2
3879
+ logger.debug("end of create_lines_outside_magnets")
3880
+ return created
3881
+
3789
3882
  def has_areas_touching_both_sides(self):
3790
3883
  for a in self.area_list:
3791
3884
  if a.is_touching_both_sides():
@@ -3842,9 +3935,146 @@ class Geometry(object):
3842
3935
  logger.debug("end of get_inner_airgap_line #%s", len(nodes))
3843
3936
  return nodes, elements
3844
3937
 
3845
- def create_corner_areas(self):
3938
+ def create_inner_corner_areas(self, startangle, endangle):
3846
3939
  self.set_edge_attributes()
3847
- self.create_inner_corner_auxiliary_areas()
3940
+
3941
+ builder = AreaBuilder(geom=self)
3942
+ builder.create_inner_corner_auxiliary_areas(startangle, endangle)
3943
+
3944
+ def repair_border_line(self, nodes):
3945
+ logger.debug("begin repair_border_line")
3946
+ for d, n, ok in nodes:
3947
+ logger.debug(" node=%s, ok=%s", n, ok)
3948
+
3949
+ d1, n1, ok1 = nodes[0]
3950
+ if not ok1: # fatal => ignore
3951
+ logger.debug("end repair_border_line: missing point %s", n1)
3952
+ return False
3953
+ d1, n1, ok1 = nodes[-1]
3954
+ if not ok1: # fatal => ignore
3955
+ logger.debug("end repair_border_line: missing point %s", n1)
3956
+ return False
3957
+
3958
+ remove_n1 = None
3959
+ for d2, n2, ok2 in nodes[1:]:
3960
+ if ok1 and not ok2:
3961
+ remove_n1 = n1
3962
+ if ok2 and remove_n1:
3963
+ try:
3964
+ self._remove_edge(remove_n1, n2)
3965
+ logger.debug("Remove Line %s -- %s", remove_n1, n2)
3966
+ except nx.NetworkXError:
3967
+ logger.debug("Warning: Remove Line %s -- %s failed", remove_n1, n2)
3968
+ logger.debug("end repair_border_line: failed")
3969
+ return False
3970
+ remove_n1 = None
3971
+ n1 = n2
3972
+ ok1 = ok2
3973
+
3974
+ d1, n1, ok1 = nodes[0]
3975
+ for d2, n2, ok2 in nodes[1:]:
3976
+ if not ok2: # new node
3977
+ self.add_line(n1, n2)
3978
+ logger.debug("Add Line %s -- %s", n1, n2)
3979
+ elif not ok1:
3980
+ self.add_line(n1, n2)
3981
+ logger.debug("Add Line %s -- %s", n1, n2)
3982
+ n1 = n2
3983
+ ok1 = ok2
3984
+ logger.debug("end repair_border_line")
3985
+ return True
3986
+
3987
+ def create_boundery_nodes(self,
3988
+ center,
3989
+ startangle,
3990
+ endangle,
3991
+ rtol=None, atol=None):
3992
+ if not rtol:
3993
+ rtol = 1e-4
3994
+ if not atol:
3995
+ atol = 1e-3
3996
+
3997
+ start_nodes = [n for n in self.angle_nodes(center, startangle, rtol, atol)]
3998
+ end_nodes = [n for n in self.angle_nodes(center, endangle, rtol, atol)]
3999
+ alpha = alpha_angle(startangle, endangle)
4000
+
4001
+ logger.debug("begin of create_boundery_nodes")
4002
+ start_rot_nodes = self.rotate_nodes(alpha, start_nodes)
4003
+ end_rot_nodes = self.rotate_nodes(-alpha, end_nodes)
4004
+
4005
+ def miss_nodelist(src_nodelist, dest_nodelist):
4006
+ nlist = []
4007
+ for src_n in src_nodelist:
4008
+ ok = False
4009
+ for dest_n in dest_nodelist:
4010
+ if points_are_close(src_n, dest_n, rtol=rtol, atol=atol):
4011
+ ok = True
4012
+ break
4013
+ if not ok:
4014
+ nlist.append(src_n)
4015
+ return nlist
4016
+
4017
+ logger.debug("Begin with Nodes Start=%s, End=%s", len(start_nodes), len(end_nodes))
4018
+
4019
+ missing_end_nodes = miss_nodelist(start_rot_nodes, end_nodes)
4020
+ missing_start_nodes = miss_nodelist(end_rot_nodes, start_nodes)
4021
+
4022
+ if missing_start_nodes:
4023
+ logger.debug("%s missing start nodes", len(missing_start_nodes))
4024
+ start_nodes = [(distance(center, n), n, True) for n in start_nodes]
4025
+ for n in missing_start_nodes:
4026
+ start_nodes.append((distance(center, n), n, False))
4027
+ start_nodes.sort()
4028
+ if not self.repair_border_line(start_nodes):
4029
+ logger.debug("end of create_boundery_nodes (failed)")
4030
+ return
4031
+ else:
4032
+ start_nodes = [(distance(center, n), n, True) for n in start_nodes]
4033
+ start_nodes.sort()
4034
+
4035
+ if missing_end_nodes:
4036
+ logger.debug("%s missing end nodes", len(missing_end_nodes))
4037
+ end_nodes = [(distance(center, n), n, True) for n in end_nodes]
4038
+ for n in missing_end_nodes:
4039
+ end_nodes.append((distance(center, n), n, False))
4040
+ end_nodes.sort()
4041
+ if not self.repair_border_line(end_nodes):
4042
+ logger.debug("end of create_boundery_nodes (failed)")
4043
+ return
4044
+ else:
4045
+ end_nodes = [(distance(center, n), n, True) for n in end_nodes]
4046
+ end_nodes.sort()
4047
+
4048
+ start_nodes = [(distance(center, n), n)
4049
+ for n in self.angle_nodes(center, startangle, rtol, atol)]
4050
+ start_nodes.sort()
4051
+ end_nodes = [(distance(center, n), n)
4052
+ for n in self.angle_nodes(center, endangle, rtol, atol)]
4053
+ end_nodes.sort()
4054
+
4055
+ logger.debug("End with Nodes Start=%s, End=%s", len(start_nodes), len(end_nodes))
4056
+
4057
+ nodes = [n for d, n in start_nodes]
4058
+ start_rot_nodes = self.rotate_nodes(alpha, nodes)
4059
+
4060
+ for d, node in start_nodes:
4061
+ self.set_point_of_node(node, node)
4062
+ i = 0
4063
+ if len(end_nodes) == len(start_rot_nodes):
4064
+ for d, node in end_nodes:
4065
+ self.set_point_of_node(node, start_rot_nodes[i])
4066
+ i += 1
4067
+
4068
+ logger.debug("end of create_boundery_nodes")
4069
+ return
4070
+
4071
+ def set_point_of_node(self, node, p):
4072
+ if isinstance(node, list):
4073
+ node = (node[0], node[1])
4074
+ nbrs = self.get_neighbors(node)
4075
+ for nbr in nbrs:
4076
+ e = self.get_edge_element(node, nbr)
4077
+ e.replace_point(node, p)
3848
4078
 
3849
4079
  def create_and_append_area(self, n1, n2):
3850
4080
  rslt = self.get_new_area(n1, n2, False)
@@ -3852,7 +4082,7 @@ class Geometry(object):
3852
4082
  if rslt.get('ok', False):
3853
4083
  area = rslt['area']
3854
4084
  a = Area(area, self.center, 0.0)
3855
- a.type = 0 # air
4085
+ a.set_type(AREA.TYPE_AIR) # air
3856
4086
  self.area_list.append(a)
3857
4087
  return True
3858
4088
  logger.error("No area for air near airgap!!")
@@ -3904,7 +4134,9 @@ class Geometry(object):
3904
4134
  self.add_line(start_cp, n,
3905
4135
  color='red',
3906
4136
  linestyle='dotted')
3907
- self.add_edge(cp, start_cp, start_line)
4137
+ self.add_element(start_line,
4138
+ rtol=self.rtol,
4139
+ atol=self.atol)
3908
4140
  self.create_and_append_area(start_cp, n)
3909
4141
  self.start_corners = self.get_corner_nodes(self.center,
3910
4142
  0.0)
@@ -3931,7 +4163,9 @@ class Geometry(object):
3931
4163
  self.add_line(end_cp, n,
3932
4164
  color='red',
3933
4165
  linestyle='dotted')
3934
- self.add_edge(cp, end_cp, end_line)
4166
+ self.add_element(end_line,
4167
+ rtol=self.rtol,
4168
+ atol=self.atol)
3935
4169
  self.create_and_append_area(n, end_cp)
3936
4170
  self.end_corners = self.get_corner_nodes(self.center,
3937
4171
  self.alfa)