femagtools 1.8.17__py3-none-any.whl → 1.8.19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
femagtools/dxfsl/geom.py CHANGED
@@ -35,7 +35,7 @@ from .functions import middle_angle, positive_angle
35
35
  from .functions import normalise_angle, is_same_angle
36
36
  from .functions import part_of_circle, gcd
37
37
  from .functions import point_on_arc, points_on_line, nodes_are_equal
38
- from .functions import area_size
38
+ from .functions import area_size, get_angle_of_arc
39
39
  import io
40
40
  import time
41
41
 
@@ -401,11 +401,11 @@ class Geometry(object):
401
401
  for n in self.g.nodes()}
402
402
  nx.relabel_nodes(self.g, mapping, copy=False)
403
403
 
404
- def rotate_nodes(self, alpha, nodes):
404
+ def get_rotated_nodes(self, alpha, nodes):
405
405
  T = np.array(((np.cos(alpha), -np.sin(alpha)),
406
406
  (np.sin(alpha), np.cos(alpha))))
407
- rotnodes = np.dot(T, np.asarray(nodes).T).T.tolist()
408
- return rotnodes
407
+ nodes = [T.dot(np.array((n[0], n[1]))).tolist() for n in nodes]
408
+ return nodes
409
409
 
410
410
  def rotate(self, alpha):
411
411
  """rotates all objects by angle alpha"""
@@ -1142,20 +1142,30 @@ class Geometry(object):
1142
1142
  rtol=self.rtol,
1143
1143
  atol=self.atol)
1144
1144
 
1145
- def get_corner_nodes(self, center, angle):
1146
- rtol = 1e-4
1147
- atol = 1e-4
1148
-
1145
+ def get_corner_nodes(self, center, angle, rtol=1e-4, atol=1e-4):
1149
1146
  center_added, corners = self.get_corner_list(center, angle, rtol, atol)
1150
1147
  if len(corners) < 2:
1151
1148
  return () # not enough corners
1152
1149
  return (corners[0].point(), corners[len(corners)-1].point())
1153
1150
 
1154
- def set_start_corners(self, center, angle):
1155
- self.start_corners = self.get_corner_nodes(center, angle)
1151
+ def set_start_corners(self, center, angle, rtol=1e-4, atol=1e-4):
1152
+ self.start_corners = self.get_corner_nodes(center, angle, rtol=rtol, atol=atol)
1153
+
1154
+ def set_end_corners(self, center, angle, rtol=1e-4, atol=1e-4):
1155
+ self.end_corners = self.get_corner_nodes(center, angle, rtol=rtol, atol=atol)
1156
+
1157
+ def set_virtual_start_end_corners(self):
1158
+ assert(not self.start_corners)
1159
+ assert(not self.end_corners)
1156
1160
 
1157
- def set_end_corners(self, center, angle):
1158
- self.end_corners = self.get_corner_nodes(center, angle)
1161
+ dist_list = [(distance(self.center, n), n) for n in self.nodes()]
1162
+ dist_list.sort()
1163
+ d1, c1 = dist_list[0]
1164
+ d2, c2 = dist_list[-1]
1165
+ corners = (c1, c2)
1166
+ self.start_corners = corners
1167
+ self.end_corners = corners
1168
+ return
1159
1169
 
1160
1170
  def get_angle(self, alpha1, alpha2):
1161
1171
  if np.isclose(alpha1, alpha2, 0.001, 0.001):
@@ -1172,7 +1182,7 @@ class Geometry(object):
1172
1182
  nx.set_edge_attributes(self.g, False, 1)
1173
1183
  nx.set_edge_attributes(self.g, False, 2)
1174
1184
 
1175
- def create_list_of_areas(self, main=False, delete=False):
1185
+ def create_list_of_areas(self, main=False, delete=False, nolog=True):
1176
1186
  """ return list of areas for each node and their neighbors
1177
1187
  """
1178
1188
  if delete: # clear list of areas
@@ -1183,7 +1193,7 @@ class Geometry(object):
1183
1193
  # list already available
1184
1194
  return
1185
1195
 
1186
- areabuilder = AreaBuilder(geom=self)
1196
+ areabuilder = AreaBuilder(geom=self, nolog=nolog)
1187
1197
  areabuilder.create_list_of_areas(main=main)
1188
1198
  self.area_list = areabuilder.area_list
1189
1199
  logger.debug("area list created")
@@ -1904,6 +1914,19 @@ class Geometry(object):
1904
1914
  self.area_list = []
1905
1915
  return nodes_deleted > 0
1906
1916
 
1917
+ def delete_needless_elements(self, radius):
1918
+ self.area_list = []
1919
+ for e in self.elements():
1920
+ if greater(distance(self.center, e.p1), radius):
1921
+ self.remove_edge(e)
1922
+ elif greater(distance(self.center, e.p2), radius):
1923
+ self.remove_edge(e)
1924
+ elif is_Arc(e):
1925
+ p = e.center_of_connection()
1926
+ if greater(distance(self.center, p), radius):
1927
+ self.remove_edge(e)
1928
+ self.delete_all_appendices()
1929
+
1907
1930
  def render_areagroups(self, renderer):
1908
1931
  if not self.areagroup_list:
1909
1932
  return
@@ -2036,11 +2059,47 @@ class Geometry(object):
2036
2059
  return c
2037
2060
  return None
2038
2061
 
2062
+ def check_hull_radius(self, center, radius, hull_points):
2063
+ logger.debug("check_hull_radius")
2064
+ min_r = radius
2065
+ max_r = radius
2066
+ for p in hull_points:
2067
+ d = round(distance(center, p), 2)
2068
+ min_r = min(min_r, d)
2069
+ max_r = max(max_r, d)
2070
+
2071
+ if min_r > radius * 0.8:
2072
+ # radius is ok, adjust hill line
2073
+ return True, max_r > radius
2074
+
2075
+ return False, False
2076
+
2039
2077
  def get_machine_part(self, mm):
2040
2078
  logger.debug("*** Begin of get_machine_part() ***")
2041
2079
 
2042
2080
  h_points = [h for h in convex_hull(self.virtual_nodes())]
2043
- center = self.get_center(h_points, mm)
2081
+ center, radius = self.get_center_arcs(mm)
2082
+ if center and radius:
2083
+ center_left = round(center[0] - mm[0], 4)
2084
+ center_right = round(mm[1] - center[0], 4)
2085
+ center_down = round(center[1] - mm[2], 4)
2086
+ center_up = round(mm[3] - center[1], 4)
2087
+ min_r = min(center_left, center_right, center_up, center_down)
2088
+ max_r = max(center_left, center_right, center_up, center_down)
2089
+ is_full = min_r > max_r / 2
2090
+
2091
+ ok, adjust_hull = self.check_hull_radius(center, radius, h_points)
2092
+ if is_full and ok:
2093
+ self.set_center([round(center[0], 8), round(center[1], 8)])
2094
+ self.area_list = []
2095
+ machine = Machine(self,
2096
+ radius=radius,
2097
+ startangle=0.0,
2098
+ endangle=0.0)
2099
+ return machine
2100
+
2101
+ center = self.get_center(center, h_points, mm)
2102
+
2044
2103
  logger.debug(" - Center is %s", center)
2045
2104
 
2046
2105
  min_radius = 99999
@@ -2259,9 +2318,14 @@ class Geometry(object):
2259
2318
  def is_same_center(self, center_lst, center, rtol, atol):
2260
2319
  for c in center_lst:
2261
2320
  if points_are_close(c['center'], center['center'], rtol, atol):
2262
- radius = center['radius'][0]
2263
- if not radius in c['radius']:
2264
- c['radius'].append(radius)
2321
+ new_radius, new_phi = center['radiuslist'][0]
2322
+ c_radiuslist = [r for r, p in c['radiuslist']]
2323
+ try:
2324
+ i = c_radiuslist.index(new_radius)
2325
+ c_radius, c_phi = c['radiuslist'][i]
2326
+ c['radiuslist'][i][1] = c_phi + new_phi
2327
+ except:
2328
+ c['radiuslist'].append([new_radius, new_phi])
2265
2329
  c['count'] = c['count'] + 1
2266
2330
  return True
2267
2331
  return False
@@ -2283,7 +2347,6 @@ class Geometry(object):
2283
2347
  return None
2284
2348
  cy_list = [(c['center'][0], c) for c in c_list]
2285
2349
  cy_list.sort()
2286
- [logger.info("y=%s, c=%s", y, c) for y, c in cy_list]
2287
2350
  y, c = cy_list[0]
2288
2351
  return c
2289
2352
 
@@ -2302,14 +2365,23 @@ class Geometry(object):
2302
2365
  return True
2303
2366
  return False
2304
2367
 
2368
+ def get_best_radius(radiuslist):
2369
+ radiuslist.sort(reverse=True)
2370
+ r1, phi1 = radiuslist[0]
2371
+ for r2, phi2 in radiuslist[1:]:
2372
+ if phi2 > phi1:
2373
+ return r2
2374
+ break
2375
+ return r1
2376
+
2305
2377
  circles = [e for e in self.elements() if is_Circle(e)]
2306
2378
  logger.debug(" -- %s Circles", len(circles))
2307
2379
 
2308
2380
  for e in circles:
2309
2381
  center = (round(e.center[0], 3), round(e.center[1], 3))
2382
+ angle = e.get_angle_of_arc()
2310
2383
  entry = {'center': center,
2311
- 'radius': [round(e.radius, 1)],
2312
- 'phi': e.get_angle_of_arc(),
2384
+ 'radiuslist': [[round(e.radius, 1), angle]],
2313
2385
  'dist': e.length(),
2314
2386
  'inside': center_is_inside(center),
2315
2387
  'count': 1}
@@ -2320,9 +2392,9 @@ class Geometry(object):
2320
2392
 
2321
2393
  for e in arcs:
2322
2394
  center = (round(e.center[0], 3), round(e.center[1], 3))
2395
+ angle = e.get_angle_of_arc()
2323
2396
  entry = {'center': center,
2324
- 'radius': [round(e.radius, 1)],
2325
- 'phi': e.get_angle_of_arc(),
2397
+ 'radiuslist': [[round(e.radius, 1), angle]],
2326
2398
  'dist': e.length(),
2327
2399
  'inside': center_is_inside(center),
2328
2400
  'count': 1}
@@ -2330,7 +2402,7 @@ class Geometry(object):
2330
2402
  center_list.append(entry)
2331
2403
 
2332
2404
  center = None
2333
- arc_list = [[c['count'], len(c['radius']), c['phi'], n, c]
2405
+ arc_list = [[c['count'], len(c['radiuslist']), n, c]
2334
2406
  for n, c in enumerate(center_list)]
2335
2407
  arc_list.sort(reverse=True)
2336
2408
 
@@ -2340,63 +2412,63 @@ class Geometry(object):
2340
2412
  [logger.debug("Arc %s", arc) for arc in arc_list]
2341
2413
  if not arc_list:
2342
2414
  logger.debug("end of get_center_arcs: no arcs")
2343
- return None
2415
+ return None, 0
2344
2416
 
2345
- cnt, cr1, p, n, c1 = arc_list[0]
2417
+ cnt, cr1, n, c1 = arc_list[0]
2346
2418
  logger.debug("First Entry: %s", c1)
2347
2419
  center = c1['center']
2420
+ radius = get_best_radius(c1['radiuslist'])
2348
2421
  if len(arc_list) > 1:
2349
- cnt, cr2, p, n, c2 = arc_list[1]
2422
+ cnt, cr2, n, c2 = arc_list[1]
2350
2423
  logger.debug("Second Entry: %s", c2)
2351
2424
  if not cr1 > cr2:
2352
2425
  center = None
2353
2426
 
2354
2427
  if center:
2355
- logger.debug("end of get_center_arcs: -> %s", center)
2356
- return center
2428
+ logger.debug("end of get_center_arcs: c=%s, r=%s", center, radius)
2429
+ return center, radius
2357
2430
 
2358
2431
  c_entry = self.get_center_with_x(center_list, x_min)
2359
2432
  if c_entry:
2360
2433
  center = c_entry['center']
2361
2434
  if center[1] < y_min:
2362
- logger.debug("end of get_center_arcs: x -> %s", center)
2363
- return center
2435
+ logger.debug("end of get_center_arcs (x): c=%s", center)
2436
+ return center, 0
2437
+
2364
2438
  c_entry = self.get_center_with_y(center_list, y_min)
2365
2439
  if c_entry:
2366
2440
  center = c_entry['center']
2367
2441
  if center[0] < x_min:
2368
- logger.debug("end of get_center_arcs: y -> %s", center)
2369
- return center
2442
+ logger.debug("end of get_center_arcs (y): c=%s", center)
2443
+ return center, 0
2370
2444
 
2371
2445
  logger.debug("end of get_center_arcs: no center found")
2372
- return None
2446
+ return None, 0
2373
2447
 
2374
2448
  def get_center_dim(self, mm):
2375
2449
  return (round(mm[0], 4), round(mm[2], 4))
2376
2450
 
2377
- def get_center(self, points, mm):
2378
- logger.debug("Begin of get_center(%s points)", len(points))
2379
- if len(points) < 3:
2451
+ def get_center(self, center_arcs, hull_points, mm):
2452
+ logger.debug("Begin of get_center(%s hull-points)", len(hull_points))
2453
+ if len(hull_points) < 3:
2380
2454
  return None
2381
2455
 
2382
2456
  center = None
2383
2457
  # Zuerst suchen wir anhand der Circle- und Arc-Segmente nach einem
2384
2458
  # möglichen Center-Punkt.
2385
- center_arcs = self.get_center_arcs(mm)
2386
-
2387
2459
  if center_arcs:
2388
2460
  center = center_arcs
2389
2461
  else:
2390
2462
  # Wir finden keine Arc-Objekte, welche uns einen Hinweis auf den
2391
2463
  # Center geben können. Wir versuchen in der Verzweiflung mit
2392
2464
  # center_hull oder x(min) und y(min)
2393
- center_hull = self.get_center_hull(points)
2465
+ center_hull = self.get_center_hull(_hull_points)
2394
2466
  if center_hull:
2395
2467
  center = center_hull
2396
2468
  else:
2397
2469
  center = self.get_center_dim(mm)
2398
2470
 
2399
- center_xaxis = self.get_center_xaxis(points)
2471
+ center_xaxis = self.get_center_xaxis(hull_points)
2400
2472
  y = center_xaxis[1]
2401
2473
  if y is not None:
2402
2474
  if np.isclose(y, center[1], atol=0.3):
@@ -3265,6 +3337,31 @@ class Geometry(object):
3265
3337
  return [a for a in self.list_of_areas()
3266
3338
  if a.is_type(type)]
3267
3339
 
3340
+ def is_tooth(self, a, windings, wdg_min_dist, wdg_max_dist):
3341
+ if a.around_windings(windings, self):
3342
+ if a.close_to_ag:
3343
+ return True
3344
+ if self.is_inner:
3345
+ if greater(a.min_dist, wdg_min_dist, atol=1e-1):
3346
+ return True
3347
+ else:
3348
+ if less(a.max_dist, wdg_max_dist, atol=1e-1):
3349
+ return True
3350
+ return False
3351
+
3352
+ def between_airgap_and_winding(self, a,
3353
+ wdg_min_angle,
3354
+ wdg_max_angle,
3355
+ wdg_min_dist,
3356
+ wdg_max_dist):
3357
+ if greater_equal(a.min_angle, wdg_min_angle) and \
3358
+ less_equal(a.max_angle, wdg_max_angle):
3359
+ if self.is_inner:
3360
+ return less_equal(wdg_max_dist, a.min_dist)
3361
+ else:
3362
+ return less_equal(a.max_dist, wdg_min_dist)
3363
+ return False
3364
+
3268
3365
  def collect_windings(self):
3269
3366
  logger.debug("begin of collect_windings")
3270
3367
  good_windings = self.get_windings(AREA.TYPE_WINDINGS)
@@ -3337,7 +3434,7 @@ class Geometry(object):
3337
3434
  max_size, max_w = windings_surface[0]
3338
3435
  for sz, w in windings_surface[1:]:
3339
3436
  logger.debug("winding size = %s", sz)
3340
- if sz / max_size < 0.70:
3437
+ if sz / max_size < 0.60:
3341
3438
  w.set_type(AREA.TYPE_AIR)
3342
3439
  if sz / max_size < 0.2:
3343
3440
  windings_found -= 1
@@ -3387,7 +3484,7 @@ class Geometry(object):
3387
3484
  air_areas = [a for a in self.list_of_areas()
3388
3485
  if a.is_type(AREA.TYPE_AIR_OR_IRON)]
3389
3486
  for a in air_areas:
3390
- if a.around_windings(windings, self):
3487
+ if a.around_windings(windings, self) and less(a.min_dist, wdg_max_dist - 0.5):
3391
3488
  logger.debug("Area %s", a.identifier())
3392
3489
  logger.debug(" - air-angle min/max = %s/%s",
3393
3490
  a.min_air_angle,
@@ -3409,7 +3506,6 @@ class Geometry(object):
3409
3506
  a.close_to_ag):
3410
3507
  a.set_type(AREA.TYPE_AIR) # air
3411
3508
  continue
3412
-
3413
3509
  a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3414
3510
  continue
3415
3511
 
@@ -3438,14 +3534,28 @@ class Geometry(object):
3438
3534
  a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3439
3535
  else:
3440
3536
  logger.debug("#5 not around windings")
3441
- a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3537
+ if self.between_airgap_and_winding(a,
3538
+ wdg_min_angle, wdg_max_angle,
3539
+ wdg_min_dist, wdg_max_dist):
3540
+ a.set_type(AREA.TYPE_AIR) # air
3541
+ else:
3542
+ if self.is_inner:
3543
+ if greater(a.min_dist, wdg_min_dist, atol=1e-1):
3544
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3545
+ else:
3546
+ a.set_type(AREA.TYPE_YOKE) # iron shaft (Joch)
3547
+ else:
3548
+ if less(a.max_dist, wdg_max_dist, atol=1e-1):
3549
+ a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3550
+ else:
3551
+ a.set_type(AREA.TYPE_YOKE) # iron shaft (Joch)
3442
3552
 
3443
3553
  # yoke or shaft ?
3444
3554
  iron_areas = [a for a in self.list_of_areas()
3445
3555
  if a.is_type(AREA.TYPE_YOKE)]
3446
3556
  for a in iron_areas:
3447
3557
  if a.around_windings(windings, self):
3448
- if less(a.min_dist, wdg_max_dist):
3558
+ if less(a.min_dist, wdg_max_dist - 0.5):
3449
3559
  if less_equal(a.max_dist, wdg_max_dist):
3450
3560
  a.set_type(AREA.TYPE_TOOTH) # iron shaft (Zahn)
3451
3561
  else:
@@ -3765,16 +3875,44 @@ class Geometry(object):
3765
3875
  a_midangle = a.get_mid_angle(self.center)
3766
3876
  if np.isclose(midangle, a_midangle, atol=1e-2, rtol=1e-2):
3767
3877
  s = a.area_size()
3768
- mags.append([s, n, a])
3878
+ mags.append([s, n, a, a_midangle])
3769
3879
 
3770
3880
  if not mags:
3771
- return False
3881
+ logger.debug("possible_magnet_in_the_middle: No Areas for Magnets")
3882
+ return None
3883
+
3772
3884
  mags.sort(reverse=True)
3773
- s, n, a = mags[0]
3774
- a.set_type(AREA.TYPE_MAGNET_AIRGAP)
3775
- a.phi = midangle
3776
- a.mag_width = (a.max_dist - a.min_dist) * 0.9
3777
- return a
3885
+ to_angle = np.pi / 2
3886
+ for s, n, a, mid in mags:
3887
+ angle = to_angle - mid
3888
+ nodelist = a.list_of_nodes()
3889
+ nodes = self.get_rotated_nodes(angle, nodelist)
3890
+ p1 = self.center
3891
+ p2 = point(self.center, self.max_radius + 10, mid)
3892
+ line = Line(Element(start=p1, end=p2))
3893
+ nodelist = a.get_intersect_points(line)
3894
+ mid_nodes = self.get_rotated_nodes(angle, nodelist)
3895
+ if self.is_possible_magnet(nodes, mid_nodes):
3896
+ a.set_type(AREA.TYPE_MAGNET_AIRGAP)
3897
+ a.phi = mid
3898
+ a.mag_width = (a.max_dist - a.min_dist) * 0.9
3899
+ return a
3900
+
3901
+ logger.debug("possible_magnet_in_the_middle: No Magnets")
3902
+ return None
3903
+
3904
+ def is_possible_magnet(self, all_nodes, mid_nodes):
3905
+ all_y = [n[1] for n in all_nodes]
3906
+ all_y.sort()
3907
+ mid_y = [n[1] for n in mid_nodes]
3908
+ mid_y.sort()
3909
+
3910
+ logger.debug("is_possible_magnet: mid y min/max = %s/%s", mid_y[0], mid_y[-1])
3911
+ logger.debug("is_possible_magnet: all y min/max = %s/%s", all_y[0], all_y[-1])
3912
+
3913
+ if all_y[0] > mid_y[-1]:
3914
+ return False
3915
+ return True
3778
3916
 
3779
3917
  def force_area_as_magnet(self, area):
3780
3918
  for a in self.list_of_areas():
@@ -3804,20 +3942,33 @@ class Geometry(object):
3804
3942
  return False
3805
3943
 
3806
3944
  def looking_for_corners(self):
3807
- if self.is_inner:
3808
- logger.debug("looking_for_corners: inner")
3809
- start_cp = self.start_corners[-1]
3810
- end_cp = self.end_corners[-1]
3811
- else:
3812
- logger.debug("looking_for_corners: outer")
3813
- start_cp = self.start_corners[0]
3814
- end_cp = self.end_corners[0]
3815
- logger.debug("looking_for_corners: start=%s, end=%s",
3816
- start_cp, end_cp)
3945
+ try:
3946
+ if self.is_inner:
3947
+ logger.debug("looking_for_corners: inner")
3948
+ start_cp = self.start_corners[-1]
3949
+ end_cp = self.end_corners[-1]
3950
+ else:
3951
+ logger.debug("looking_for_corners: outer")
3952
+ start_cp = self.start_corners[0]
3953
+ end_cp = self.end_corners[0]
3954
+ logger.debug("looking_for_corners: start=%s, end=%s",
3955
+ start_cp, end_cp)
3956
+ except IndexError:
3957
+ return
3958
+
3817
3959
  for area in self.list_of_areas():
3818
3960
  area.mark_airgap_corners(start_cp, end_cp)
3819
3961
  return
3820
3962
 
3963
+ def get_areas_of_type(self, types=()):
3964
+ return [area for area in self.list_of_areas()
3965
+ if area.type in types]
3966
+
3967
+ def get_areas_of_irons(self):
3968
+ return self.get_areas_of_type((AREA.TYPE_IRON,
3969
+ AREA.TYPE_YOKE,
3970
+ AREA.TYPE_TOOTH,))
3971
+
3821
3972
  def num_areas_of_type(self, types=()):
3822
3973
  return len([area for area in self.list_of_areas()
3823
3974
  if area.type in types])
@@ -4164,6 +4315,16 @@ class Geometry(object):
4164
4315
  for e in self.elements():
4165
4316
  e.adjust_points()
4166
4317
 
4318
+ def split_with_point(self, p):
4319
+ for e in self.elements(Shape):
4320
+ elements = e.split([p])
4321
+ if elements:
4322
+ self.remove_edge(e)
4323
+ for e in elements:
4324
+ self.add_element(e, rtol=self.rtol, atol=self.atol)
4325
+ return True
4326
+ return False
4327
+
4167
4328
  def split_and_get_intersect_points(self, el, aktion=True, include_end=True):
4168
4329
  logger.debug("begin of split_and_get_intersect_points")
4169
4330
  rtol = 1e-03
@@ -4320,6 +4481,41 @@ class Geometry(object):
4320
4481
  builder = AreaBuilder(geom=self)
4321
4482
  return builder.create_inner_corner_auxiliary_areas(startangle, endangle)
4322
4483
 
4484
+ def adjust_outer_hull_for_symmetry(self):
4485
+ logger.debug("adjust_outer_hull_for_symmetry()")
4486
+ areas = self.list_of_areas()
4487
+ builder = AreaBuilder(geom=self)
4488
+ op_nodes, op_el = builder.get_outer_opposite_airgap_line()
4489
+ if not op_nodes:
4490
+ logger.warning("Fatal: No nodes found")
4491
+ return False
4492
+
4493
+ radiuslist = {}
4494
+ n1 = op_nodes[0]
4495
+ d1 = distance(self.center, n1)
4496
+ a1 = alpha_line(self.center, n1)
4497
+ for n2 in op_nodes[1:]:
4498
+ d2 = distance(self.center, n2)
4499
+ a2 = alpha_line(self.center, n2)
4500
+ if np.isclose(d1, d2, rtol=1e-3, atol=1e-2):
4501
+ r = round((d1 + d2) / 2, 1)
4502
+ alpha = get_angle_of_arc(a2, a1)
4503
+ radius_alpha = radiuslist.get(r, 0.0) + alpha
4504
+ radiuslist[r] = radius_alpha
4505
+
4506
+ n1 = n2
4507
+ d1 = d2
4508
+ a1 = a2
4509
+
4510
+ rlist = [(radiuslist[r], r) for r in radiuslist]
4511
+ rlist.sort(reverse=True)
4512
+ alpha, best_radius = rlist[0]
4513
+ if np.isclose(best_radius, self.max_radius, rtol=1e-3, atol=1e-2):
4514
+ return False
4515
+ logger.debug("Best Outer Radius is %s", best_radius)
4516
+ self.adjust_outer_hull(best_radius)
4517
+ return True
4518
+
4323
4519
  def close_outer_winding_areas(self):
4324
4520
  logger.debug("begin close_outer_winding_areas(%s areas)",
4325
4521
  len(self.area_list))
@@ -4641,3 +4837,9 @@ class Geometry(object):
4641
4837
 
4642
4838
  with io.open(name, 'w', encoding='utf-8') as f:
4643
4839
  f.write('\n'.join(content))
4840
+
4841
+ def adjust_outer_hull(self, new_radius):
4842
+ c = Circle(Element(center=self.center, radius=new_radius))
4843
+ self.add_element(c, 1e-3, 1e-3)
4844
+ self.delete_needless_elements(new_radius)
4845
+ self.max_radius = new_radius