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.
- femagtools/__init__.py +2 -2
- femagtools/bch.py +1 -1
- femagtools/dxfsl/area.py +334 -332
- femagtools/dxfsl/areabuilder.py +131 -10
- femagtools/dxfsl/conv.py +27 -9
- femagtools/dxfsl/converter.py +390 -125
- femagtools/dxfsl/corner.py +3 -0
- femagtools/dxfsl/femparser.py +1 -1
- femagtools/dxfsl/fslrenderer.py +290 -246
- femagtools/dxfsl/functions.py +4 -2
- femagtools/dxfsl/geom.py +1120 -886
- femagtools/dxfsl/journal.py +53 -22
- femagtools/dxfsl/machine.py +250 -74
- femagtools/dxfsl/plotrenderer.py +34 -3
- femagtools/dxfsl/shape.py +380 -103
- femagtools/dxfsl/symmetry.py +679 -110
- femagtools/femag.py +27 -2
- femagtools/forcedens.py +65 -40
- femagtools/fsl.py +71 -28
- femagtools/losscoeffs.py +46 -0
- femagtools/machine/effloss.py +8 -1
- femagtools/machine/im.py +3 -1
- femagtools/machine/pm.py +12 -11
- femagtools/machine/sizing.py +14 -11
- femagtools/machine/sm.py +114 -33
- femagtools/machine/utils.py +38 -34
- femagtools/model.py +12 -2
- femagtools/moo/population.py +1 -1
- femagtools/parstudy.py +17 -1
- femagtools/plot/__init__.py +1 -1
- femagtools/plot/char.py +24 -7
- femagtools/plot/forcedens.py +56 -29
- femagtools/plot/mcv.py +4 -1
- femagtools/plot/phasor.py +6 -1
- femagtools/poc.py +17 -10
- femagtools/templates/cogg_calc.mako +7 -1
- femagtools/templates/displ_stator_rotor.mako +33 -0
- femagtools/templates/fieldcalc.mako +10 -16
- femagtools/templates/pm_sym_f_cur.mako +1 -1
- femagtools/tks.py +3 -9
- {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/LICENSE +1 -0
- {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/METADATA +7 -4
- {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/RECORD +50 -49
- tests/engines/__init__.py +0 -20
- tests/geom/__init__.py +0 -20
- tests/moo/__init__.py +0 -20
- tests/test_model.py +8 -1
- {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/WHEEL +0 -0
- {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/entry_points.txt +0 -0
- {femagtools-1.6.7.dist-info → femagtools-1.7.0.dist-info}/top_level.txt +0 -0
femagtools/dxfsl/shape.py
CHANGED
@@ -16,8 +16,8 @@ from .functions import point, points_are_close, points_on_arc
|
|
16
16
|
from .functions import alpha_line, alpha_angle, alpha_triangle
|
17
17
|
from .functions import normalise_angle, min_angle, max_angle, get_angle_of_arc
|
18
18
|
from .functions import lines_intersect_point, nodes_are_equal
|
19
|
-
from .functions import is_angle_inside, intersect_point
|
20
|
-
from .functions import middle_angle, middle_point_of_line
|
19
|
+
from .functions import is_angle_inside, intersect_point, point_greater_equal
|
20
|
+
from .functions import middle_angle, middle_point_of_line, elevation_angle
|
21
21
|
|
22
22
|
logger = logging.getLogger('femagtools.geom')
|
23
23
|
|
@@ -116,12 +116,8 @@ class Shape(object):
|
|
116
116
|
def dy(self):
|
117
117
|
return (self.p2[1]-self.p1[1])
|
118
118
|
|
119
|
-
def m(self, none_val=None):
|
120
|
-
|
121
|
-
if m is None:
|
122
|
-
return none_val
|
123
|
-
else:
|
124
|
-
return m
|
119
|
+
def m(self, none_val=None, dec=0):
|
120
|
+
return line_m(self.p1, self.p2, none_val=none_val, dec=dec)
|
125
121
|
|
126
122
|
def n(self, m):
|
127
123
|
return line_n(self.p1, m)
|
@@ -213,7 +209,10 @@ class Shape(object):
|
|
213
209
|
if d1 == d2:
|
214
210
|
logger.warning("distances of %s and %s are equal (%s / %s)",
|
215
211
|
self.n1, self.n2, d1, d2)
|
216
|
-
raise ValueError('both nodes are equal in element')
|
212
|
+
#raise ValueError('both nodes are equal in element')
|
213
|
+
logger.warning("Points of %s are %s and %s",
|
214
|
+
self.classname(), self.p1, self.p2)
|
215
|
+
return 0
|
217
216
|
|
218
217
|
if d1 < d2:
|
219
218
|
return 1
|
@@ -232,48 +231,86 @@ class Shape(object):
|
|
232
231
|
return 0.0
|
233
232
|
|
234
233
|
def minmax_angle_dist_from_center(self,
|
235
|
-
min_alfa,
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
234
|
+
min_alfa,
|
235
|
+
max_alfa,
|
236
|
+
center,
|
237
|
+
circ):
|
240
238
|
points = self.intersect_circle(circ, include_end=True)
|
241
|
-
logger.debug("self={}".format(self))
|
242
|
-
logger.debug("points={}".format(points))
|
243
239
|
if not points:
|
244
|
-
logger.debug(" - no points")
|
245
240
|
return None
|
246
241
|
my_min_angle = min_alfa
|
247
242
|
my_max_angle = max_alfa
|
248
|
-
logger.debug(" - min {}, max {}"
|
249
|
-
.format(my_min_angle, my_max_angle))
|
250
243
|
for p in points:
|
251
244
|
alpha = alpha_line(center, p)
|
252
245
|
my_min_angle = min_angle(my_min_angle, alpha)
|
253
246
|
my_max_angle = max_angle(my_max_angle, alpha)
|
254
|
-
logger.debug(" - min {}, max {}, alpha {}"
|
255
|
-
.format(my_min_angle, my_max_angle, alpha))
|
256
247
|
|
257
|
-
logger.debug("end of minmax_angle_dist_from_center")
|
258
248
|
return (my_min_angle, my_max_angle)
|
259
249
|
|
260
|
-
def concatenate(self, n1, n2, el
|
250
|
+
def concatenate(self, n1, n2, el,
|
251
|
+
rtol=1e-05, atol=1e-05,
|
252
|
+
mdec=0,
|
253
|
+
overlapping=False):
|
261
254
|
if isinstance(el, Line):
|
262
|
-
return self.concatenate_line(n1, n2, el
|
255
|
+
return self.concatenate_line(n1, n2, el,
|
256
|
+
rtol=rtol, atol=atol,
|
257
|
+
mdec=mdec,
|
258
|
+
overlapping=overlapping)
|
263
259
|
if isinstance(el, Arc):
|
264
|
-
return self.concatenate_arc(n1, n2, el
|
260
|
+
return self.concatenate_arc(n1, n2, el,
|
261
|
+
rtol=rtol, atol=atol,
|
262
|
+
overlapping=overlapping)
|
263
|
+
|
264
|
+
if isinstance(el, Circle):
|
265
|
+
return self.concatenate_circle(n1, n2, el,
|
266
|
+
rtol=rtol, atol=atol,
|
267
|
+
overlapping=overlapping)
|
265
268
|
return None
|
266
269
|
|
267
|
-
def concatenate_line(self, n1, n2, el
|
270
|
+
def concatenate_line(self, n1, n2, el,
|
271
|
+
rtol=1e-05, atol=1e-05,
|
272
|
+
mdec=0,
|
273
|
+
overlapping=False):
|
268
274
|
return None
|
269
275
|
|
270
|
-
def concatenate_arc(self, n1, n2, el
|
276
|
+
def concatenate_arc(self, n1, n2, el,
|
277
|
+
rtol=1e-05, atol=1e-05,
|
278
|
+
overlapping=False):
|
271
279
|
return None
|
272
280
|
|
281
|
+
def concatenate_circle(self, n1, n2, el,
|
282
|
+
rtol=1e-05, atol=1e-05,
|
283
|
+
overlapping=False):
|
284
|
+
return None
|
285
|
+
|
286
|
+
def points_sorted(self, rtol=1e-05, atol=1e-05):
|
287
|
+
if point_greater_equal(self.p1, self.p2, rtol=rtol, atol=atol):
|
288
|
+
return self.p2, self.p1
|
289
|
+
else:
|
290
|
+
return self.p1, self.p2
|
291
|
+
|
273
292
|
def rotate(self, T, p):
|
274
293
|
n = T.dot(np.array((p[0], p[1])))
|
275
294
|
return (n[0], n[1])
|
276
295
|
|
296
|
+
def is_tiny(self, mindist):
|
297
|
+
return distance(self.p1, self.p2) < mindist
|
298
|
+
|
299
|
+
def adjust_points(self):
|
300
|
+
self.p1 = self.n1
|
301
|
+
self.p2 = self.n2
|
302
|
+
|
303
|
+
def replace_point(self, node, point):
|
304
|
+
if nodes_are_equal(node, self.n1):
|
305
|
+
self.p1 = point
|
306
|
+
elif nodes_are_equal(node, self.n2):
|
307
|
+
self.p2 = point
|
308
|
+
else:
|
309
|
+
logger.warning("Node %s not in element", node)
|
310
|
+
|
311
|
+
def is_near(self, n):
|
312
|
+
return False
|
313
|
+
|
277
314
|
def print_nodes(self):
|
278
315
|
return " n1={}/n2={}".format(self.n1, self.n2)
|
279
316
|
|
@@ -304,6 +341,8 @@ class Circle(Shape):
|
|
304
341
|
center = e.center
|
305
342
|
self.center = lf*center[0] + xoff, lf*center[1] + yoff
|
306
343
|
self.radius = lf*e.radius
|
344
|
+
self.startangle = 0.0
|
345
|
+
self.endangle = 0.0
|
307
346
|
self.p1 = self.center[0]-self.radius, self.center[1]
|
308
347
|
self.p2 = self.center[0]+self.radius, self.center[1]
|
309
348
|
self.n1 = None
|
@@ -388,6 +427,10 @@ class Circle(Shape):
|
|
388
427
|
def center_of_connection(self, ndec=6):
|
389
428
|
return (self.center[0] + self.radius, self.center[1])
|
390
429
|
|
430
|
+
def maxdist(self, r):
|
431
|
+
r0 = np.linalg.norm(self.center)
|
432
|
+
return max(abs(r-r0-self.radius), abs(r-r0+self.radius))
|
433
|
+
|
391
434
|
def overlapping_shape(self, e, rtol=1e-03, atol=1e-03):
|
392
435
|
if not (isinstance(e, Arc) or isinstance(e, Circle)):
|
393
436
|
# end overlapping_shape: Circle (not Arc or Circle)
|
@@ -445,7 +488,10 @@ class Circle(Shape):
|
|
445
488
|
d = distance(self.center, p)
|
446
489
|
|
447
490
|
if np.isclose(d, self.radius, rtol, atol):
|
448
|
-
if line.is_point_inside(p,
|
491
|
+
if line.is_point_inside(p,
|
492
|
+
rtol=rtol,
|
493
|
+
atol=atol,
|
494
|
+
include_end=include_end):
|
449
495
|
# Wenn der Abstand d dem Radius entspricht, handelt es sich um
|
450
496
|
# eine Tangente und es gibt genau einen Schnittpunkt
|
451
497
|
if include_end:
|
@@ -465,8 +511,14 @@ class Circle(Shape):
|
|
465
511
|
# Die Schnittpunkte p1 und p2 sind bestimmt. Nun muss noch sicher
|
466
512
|
# gestellt werden, dass sie innerhalb des Start- und Endpunkts der
|
467
513
|
# Linie liegen
|
468
|
-
p1_inside = line.is_point_inside(p1,
|
469
|
-
|
514
|
+
p1_inside = line.is_point_inside(p1,
|
515
|
+
rtol=rtol,
|
516
|
+
atol=atol,
|
517
|
+
include_end=include_end)
|
518
|
+
p2_inside = line.is_point_inside(p2,
|
519
|
+
rtol=rtol,
|
520
|
+
atol=atol,
|
521
|
+
include_end=include_end)
|
470
522
|
if p1_inside:
|
471
523
|
if p2_inside:
|
472
524
|
return [p1, p2]
|
@@ -510,22 +562,60 @@ class Circle(Shape):
|
|
510
562
|
# let Arc do the work
|
511
563
|
return arc.intersect_circle(self, rtol, atol, include_end)
|
512
564
|
|
513
|
-
def
|
565
|
+
def concatenate_arc(self, n1, n2, el,
|
566
|
+
rtol=1e-03, atol=1e-03,
|
567
|
+
overlapping=False):
|
568
|
+
if not points_are_close(self.center, el.center):
|
569
|
+
return None
|
570
|
+
if not np.isclose(self.radius, el.radius):
|
571
|
+
return None
|
572
|
+
# it's a circle
|
573
|
+
return Circle(Element(center=self.center, radius=self.radius))
|
574
|
+
|
575
|
+
def concatenate_circle(self, n1, n2, el,
|
576
|
+
rtol=1e-03, atol=1e-03,
|
577
|
+
overlapping=False):
|
578
|
+
if not points_are_close(self.center, el.center):
|
579
|
+
return None
|
580
|
+
if not np.isclose(self.radius, el.radius):
|
581
|
+
return None
|
582
|
+
# it's a circle
|
583
|
+
return Circle(Element(center=self.center, radius=self.radius))
|
584
|
+
|
585
|
+
def is_point_inside(self, p,
|
586
|
+
rtol=1e-03,
|
587
|
+
atol=1e-03,
|
588
|
+
include_end=False,
|
589
|
+
ignore_end=False,
|
590
|
+
mdec=0):
|
514
591
|
""" returns true if p is on circle
|
515
592
|
"""
|
516
593
|
d = distance(p, self.center)
|
517
|
-
|
594
|
+
if not np.isclose(d, self.radius, rtol=rtol, atol=atol):
|
595
|
+
return False
|
596
|
+
if points_are_close(p, self.p1, rtol=rtol, atol=atol):
|
597
|
+
return include_end
|
598
|
+
elif points_are_close(p, self.p2, rtol=rtol, atol=atol):
|
599
|
+
return include_end
|
600
|
+
return True
|
518
601
|
|
519
|
-
def split(self, points, rtol, atol):
|
602
|
+
def split(self, points, rtol=1e-03, atol=1e-03, mdec=0):
|
520
603
|
""" Die Funktion splittet das Circle-Objekt an den vorgegebenen Punkten
|
521
604
|
und gibt eine Liste der neu enstandenen Elemente aus.
|
522
605
|
"""
|
523
|
-
if len(points)
|
606
|
+
if len(points):
|
524
607
|
p = points[0]
|
525
608
|
split_arcs = []
|
526
609
|
alpha1 = alpha_line(self.center, p)
|
527
|
-
|
528
|
-
|
610
|
+
if len(points) == 2:
|
611
|
+
p = points[1]
|
612
|
+
alpha3 = alpha_line(self.center, p)
|
613
|
+
alpha2 = middle_angle(alpha1, alpha3)
|
614
|
+
alpha4 = middle_angle(alpha3, alpha1)
|
615
|
+
else:
|
616
|
+
alpha2 = normalise_angle(alpha1 + np.pi/2)
|
617
|
+
alpha3 = normalise_angle(alpha1 - np.pi/2)
|
618
|
+
alpha4 = None
|
529
619
|
|
530
620
|
arc = Arc(Element(center=self.center, radius=self.radius,
|
531
621
|
start_angle=alpha1*180/np.pi,
|
@@ -539,8 +629,17 @@ class Circle(Shape):
|
|
539
629
|
arc.copy_attributes(self)
|
540
630
|
split_arcs.append(arc)
|
541
631
|
|
632
|
+
if alpha4:
|
633
|
+
arc = Arc(Element(center=self.center, radius=self.radius,
|
634
|
+
start_angle=alpha3*180/np.pi,
|
635
|
+
end_angle=alpha4*180/np.pi))
|
636
|
+
arc.copy_attributes(self)
|
637
|
+
split_arcs.append(arc)
|
638
|
+
else:
|
639
|
+
alpha4 = alpha3
|
640
|
+
|
542
641
|
arc = Arc(Element(center=self.center, radius=self.radius,
|
543
|
-
start_angle=
|
642
|
+
start_angle=alpha4*180/np.pi,
|
544
643
|
end_angle=alpha1*180/np.pi))
|
545
644
|
arc.copy_attributes(self)
|
546
645
|
split_arcs.append(arc)
|
@@ -565,6 +664,17 @@ class Circle(Shape):
|
|
565
664
|
def get_angle_of_arc(self):
|
566
665
|
return np.pi*2.0
|
567
666
|
|
667
|
+
def is_near(self, n):
|
668
|
+
if n[0] > self.center[0] + self.radius + 1e-02:
|
669
|
+
return False
|
670
|
+
if n[0] < self.center[0] - self.radius - 1e-02:
|
671
|
+
return False
|
672
|
+
if n[1] > self.center[1] + self.radius + 1e-02:
|
673
|
+
return False
|
674
|
+
if n[1] < self.center[1] - self.radius - 1e-02:
|
675
|
+
return False
|
676
|
+
return True
|
677
|
+
|
568
678
|
def __str__(self):
|
569
679
|
return "Circle c={}, r={}".format(self.center, self.radius)
|
570
680
|
|
@@ -656,6 +766,12 @@ class Arc(Circle):
|
|
656
766
|
x, y = self(midangle)
|
657
767
|
return (round(x, ndec), round(y, ndec))
|
658
768
|
|
769
|
+
def maxdist(self, r):
|
770
|
+
a = np.array([np.linalg.norm(self.center),
|
771
|
+
np.linalg.norm(self.p1),
|
772
|
+
np.linalg.norm(self.p2)])
|
773
|
+
return np.max(np.abs(a-r))
|
774
|
+
|
659
775
|
def length(self):
|
660
776
|
"""returns length of this arc"""
|
661
777
|
d = alpha_angle(self.startangle, self.endangle)
|
@@ -666,9 +782,9 @@ class Arc(Circle):
|
|
666
782
|
def get_alpha(self, n):
|
667
783
|
a = alpha_line(n, self.center)
|
668
784
|
if points_are_close(n, self.n1):
|
669
|
-
alpha1 = normalise_angle(a + np.pi
|
785
|
+
alpha1 = normalise_angle(a + np.pi * 0.5)
|
670
786
|
elif points_are_close(n, self.n2):
|
671
|
-
alpha1 = normalise_angle(a - np.pi
|
787
|
+
alpha1 = normalise_angle(a - np.pi * 0.5)
|
672
788
|
else:
|
673
789
|
alpha1 = 0.0
|
674
790
|
return alpha1
|
@@ -701,9 +817,9 @@ class Arc(Circle):
|
|
701
817
|
return None
|
702
818
|
|
703
819
|
points = []
|
704
|
-
if self.is_point_inside(e.p1, rtol, atol):
|
705
|
-
if self.is_point_inside(e.p2, rtol, atol):
|
706
|
-
if e.is_point_inside(self.p2, rtol, atol):
|
820
|
+
if self.is_point_inside(e.p1, rtol=rtol, atol=atol):
|
821
|
+
if self.is_point_inside(e.p2, rtol=rtol, atol=atol):
|
822
|
+
if e.is_point_inside(self.p2, rtol=rtol, atol=atol):
|
707
823
|
# a Circle
|
708
824
|
points.append(e.p1)
|
709
825
|
points.append(self.p2)
|
@@ -719,23 +835,23 @@ class Arc(Circle):
|
|
719
835
|
points.append(self.p1)
|
720
836
|
points.append(e.p1)
|
721
837
|
points.append(self.p2)
|
722
|
-
if e.is_point_inside(self.p2, rtol, atol):
|
838
|
+
if e.is_point_inside(self.p2, rtol=rtol, atol=atol):
|
723
839
|
points.append(e.p2)
|
724
840
|
|
725
|
-
elif self.is_point_inside(e.p2, rtol, atol):
|
841
|
+
elif self.is_point_inside(e.p2, rtol=rtol, atol=atol):
|
726
842
|
points.append(e.p1)
|
727
843
|
points.append(self.p1)
|
728
844
|
points.append(e.p2)
|
729
845
|
points.append(self.p2)
|
730
846
|
|
731
|
-
elif e.is_point_inside(self.p1, rtol, atol):
|
847
|
+
elif e.is_point_inside(self.p1, rtol=rtol, atol=atol):
|
732
848
|
points.append(e.p1)
|
733
849
|
points.append(self.p1)
|
734
850
|
points.append(self.p2)
|
735
|
-
if e.is_point_inside(self.p2, rtol, atol):
|
851
|
+
if e.is_point_inside(self.p2, rtol=rtol, atol=atol):
|
736
852
|
points.append(e.p2)
|
737
853
|
|
738
|
-
elif e.is_point_inside(self.p2, rtol, atol):
|
854
|
+
elif e.is_point_inside(self.p2, rtol=rtol, atol=atol):
|
739
855
|
if not points_are_close(self.p1, e.p1, rtol=rtol, atol=atol):
|
740
856
|
logger.error("FATAL ERROR in overlapping_shape() of Arc")
|
741
857
|
|
@@ -759,12 +875,17 @@ class Arc(Circle):
|
|
759
875
|
Schnittpunkte bestimmt und in einer Liste ausgegeben
|
760
876
|
"""
|
761
877
|
points = super(Arc, self).intersect_line(line, rtol, atol, include_end)
|
878
|
+
if not points:
|
879
|
+
return []
|
762
880
|
|
763
881
|
# all possible points have been found
|
764
882
|
# Lets see if they are on a arc
|
765
883
|
remaining_points = []
|
766
884
|
for p in points:
|
767
|
-
if self.is_point_inside(p,
|
885
|
+
if self.is_point_inside(p,
|
886
|
+
rtol=rtol,
|
887
|
+
atol=atol,
|
888
|
+
include_end=include_end):
|
768
889
|
remaining_points.append(p)
|
769
890
|
return remaining_points
|
770
891
|
|
@@ -779,7 +900,10 @@ class Arc(Circle):
|
|
779
900
|
# (has been assumed as a circle)
|
780
901
|
remaining_points = []
|
781
902
|
for p in points:
|
782
|
-
if arc.is_point_inside(p,
|
903
|
+
if arc.is_point_inside(p,
|
904
|
+
rtol=rtol,
|
905
|
+
atol=atol,
|
906
|
+
include_end=include_end):
|
783
907
|
remaining_points.append(p)
|
784
908
|
return remaining_points
|
785
909
|
|
@@ -800,16 +924,21 @@ class Arc(Circle):
|
|
800
924
|
# Intersection points exist. Take the ones on the arc
|
801
925
|
remaining_points = []
|
802
926
|
for p in points:
|
803
|
-
if self.is_point_inside(p,
|
927
|
+
if self.is_point_inside(p,
|
928
|
+
rtol=rtol,
|
929
|
+
atol=atol,
|
930
|
+
include_end=include_end):
|
804
931
|
remaining_points.append(p)
|
805
932
|
return remaining_points
|
806
933
|
|
807
|
-
def split(self, points, rtol=1e-03, atol=1e-03):
|
934
|
+
def split(self, points, rtol=1e-03, atol=1e-03, mdec=0):
|
808
935
|
""" return a list of arcs by splitting
|
809
936
|
"""
|
810
937
|
points_inside = [p
|
811
938
|
for p in points
|
812
|
-
if self.is_point_inside(p,
|
939
|
+
if self.is_point_inside(p,
|
940
|
+
rtol=rtol,
|
941
|
+
atol=atol)]
|
813
942
|
if len(points_inside) == 1:
|
814
943
|
p = points_inside[0]
|
815
944
|
split_arcs = []
|
@@ -844,31 +973,89 @@ class Arc(Circle):
|
|
844
973
|
end_angle=self.endangle*180/np.pi))
|
845
974
|
return a1, a2
|
846
975
|
|
847
|
-
def concatenate_arc(self, n1, n2, el
|
976
|
+
def concatenate_arc(self, n1, n2, el,
|
977
|
+
rtol=1e-03, atol=1e-03,
|
978
|
+
overlapping=False):
|
848
979
|
if not points_are_close(self.center, el.center):
|
849
980
|
return None
|
850
981
|
if not np.isclose(self.radius, el.radius):
|
851
982
|
return None
|
852
983
|
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
984
|
+
my_start = normalise_angle(self.startangle)
|
985
|
+
my_end = normalise_angle(self.endangle)
|
986
|
+
el_start = normalise_angle(el.startangle)
|
987
|
+
el_end = normalise_angle(el.endangle)
|
988
|
+
|
989
|
+
logger.debug("begin of concatenate_arc")
|
990
|
+
logger.debug("my startangle: %s, endangle: %s", my_start, my_end)
|
991
|
+
logger.debug("el startangle: %s, endangle: %s", el_start, el_end)
|
992
|
+
|
993
|
+
start_angle = None
|
994
|
+
end_angle = None
|
995
|
+
|
996
|
+
if np.isclose(my_start, el_end, rtol=rtol, atol=atol):
|
997
|
+
if is_angle_inside(my_start, my_end, el_start): # Circle
|
998
|
+
logger.debug("1: new startangle is 0 (Circle)")
|
999
|
+
start_angle = 0.0
|
1000
|
+
end_angle = 0.0
|
1001
|
+
else:
|
1002
|
+
logger.debug("1: new startangle is el: %s", el_start)
|
1003
|
+
start_angle = el_start
|
1004
|
+
end_angle = my_end
|
1005
|
+
elif np.isclose(el_start, my_end, rtol=rtol, atol=atol):
|
1006
|
+
logger.debug("2: new startangle is my: %s", my_start)
|
1007
|
+
start_angle = my_start
|
1008
|
+
end_angle = el_end
|
1009
|
+
|
1010
|
+
if start_angle is None:
|
1011
|
+
if overlapping:
|
1012
|
+
if is_angle_inside(my_start, my_end, el_start):
|
1013
|
+
logger.debug("3: new startangle is my: %s", my_start)
|
1014
|
+
start_angle = my_start
|
1015
|
+
elif is_angle_inside(el_start, el_end, my_start):
|
1016
|
+
logger.debug("4: new startangle is el: %s", el_start)
|
1017
|
+
start_angle = el_start
|
1018
|
+
if start_angle is None:
|
1019
|
+
return None
|
1020
|
+
|
1021
|
+
if is_angle_inside(my_start, my_end, el_end):
|
1022
|
+
end_angle = my_end
|
1023
|
+
elif is_angle_inside(el_start, el_end, my_end):
|
1024
|
+
end_angle = el_end
|
1025
|
+
if end_angle is None:
|
1026
|
+
return None
|
1027
|
+
else:
|
1028
|
+
return None
|
861
1029
|
|
862
|
-
logger.debug("
|
863
|
-
|
864
|
-
|
1030
|
+
logger.debug("new startangle: %s, endangle: %s", start_angle, end_angle)
|
1031
|
+
|
1032
|
+
if np.isclose(start_angle, end_angle):
|
1033
|
+
# it's a circle
|
1034
|
+
return Circle(Element(center=self.center, radius=self.radius))
|
1035
|
+
|
1036
|
+
logger.debug("end of concatenate_arc")
|
865
1037
|
return Arc(Element(center=self.center,
|
866
1038
|
radius=self.radius,
|
867
1039
|
start_angle=start_angle,
|
868
1040
|
end_angle=end_angle),
|
869
1041
|
rf=1)
|
870
1042
|
|
871
|
-
def
|
1043
|
+
def concatenate_circle(self, n1, n2, el,
|
1044
|
+
rtol=1e-03, atol=1e-03,
|
1045
|
+
overlapping=False):
|
1046
|
+
if not points_are_close(self.center, el.center):
|
1047
|
+
return None
|
1048
|
+
if not np.isclose(self.radius, el.radius):
|
1049
|
+
return None
|
1050
|
+
# it's a circle
|
1051
|
+
return Circle(Element(center=self.center, radius=self.radius))
|
1052
|
+
|
1053
|
+
def is_point_inside(self, p,
|
1054
|
+
rtol=1e-03,
|
1055
|
+
atol=1e-03,
|
1056
|
+
include_end=False,
|
1057
|
+
ignore_end=False,
|
1058
|
+
mdec=0):
|
872
1059
|
""" returns true if p is on arc
|
873
1060
|
"""
|
874
1061
|
# logger.debug("is_point_inside: p=%s", p)
|
@@ -1114,6 +1301,11 @@ class Line(Shape):
|
|
1114
1301
|
y = (self.p1[1]+self.p2[1])/2
|
1115
1302
|
return (x, y)
|
1116
1303
|
|
1304
|
+
def maxdist(self, r):
|
1305
|
+
r1 = np.linalg.norm(self.p1)
|
1306
|
+
r2 = np.linalg.norm(self.p2)
|
1307
|
+
return max([abs(r1-r), abs(r2-r)])
|
1308
|
+
|
1117
1309
|
def length(self):
|
1118
1310
|
return np.sqrt(self.dx()**2 + self.dy()**2)
|
1119
1311
|
|
@@ -1121,6 +1313,9 @@ class Line(Shape):
|
|
1121
1313
|
px = self.center_of_connection()
|
1122
1314
|
return alpha_line(px, n)
|
1123
1315
|
|
1316
|
+
def get_positive_angle(self):
|
1317
|
+
return elevation_angle(alpha_line(self.p1, self.p2))
|
1318
|
+
|
1124
1319
|
def range(self, step=1.0):
|
1125
1320
|
"""returns evenly spaced values"""
|
1126
1321
|
num = max(int(self.length()/step), 1)
|
@@ -1183,8 +1378,14 @@ class Line(Shape):
|
|
1183
1378
|
if all:
|
1184
1379
|
return[point]
|
1185
1380
|
|
1186
|
-
if line.is_point_inside(point,
|
1187
|
-
|
1381
|
+
if line.is_point_inside(point,
|
1382
|
+
rtol=rtol,
|
1383
|
+
atol=atol,
|
1384
|
+
include_end=include_end):
|
1385
|
+
if self.is_point_inside(point,
|
1386
|
+
rtol=rtol,
|
1387
|
+
atol=atol,
|
1388
|
+
include_end=include_end):
|
1188
1389
|
return [point]
|
1189
1390
|
return []
|
1190
1391
|
|
@@ -1201,15 +1402,15 @@ class Line(Shape):
|
|
1201
1402
|
"""
|
1202
1403
|
return circle.intersect_line(self, rtol, atol, include_end)
|
1203
1404
|
|
1204
|
-
def split(self, points, rtol=1e-03, atol=1e-03):
|
1405
|
+
def split(self, points, rtol=1e-03, atol=1e-03, mdec=0):
|
1205
1406
|
""" Die Funktion splittet das Line-Objekt an den vorgegebenen Punkten
|
1206
1407
|
und gibt eine Liste der neu enstandenen Elemente aus.
|
1207
1408
|
"""
|
1208
1409
|
points_inside = [(distance(p, self.p1), p)
|
1209
1410
|
for p in points if self.is_point_inside(p,
|
1210
|
-
rtol,
|
1211
|
-
|
1212
|
-
|
1411
|
+
rtol=rtol,
|
1412
|
+
atol=atol,
|
1413
|
+
mdec=mdec)]
|
1213
1414
|
if len(points_inside) > 0:
|
1214
1415
|
points_inside.append((0.0, self.p1))
|
1215
1416
|
points_inside.append((distance(self.p1, self.p2), self.p2))
|
@@ -1235,45 +1436,107 @@ class Line(Shape):
|
|
1235
1436
|
l2 = Line(Element(start=pm, end=self.p2))
|
1236
1437
|
return l1, l2
|
1237
1438
|
|
1238
|
-
def concatenate_line(self, n1, n2, el
|
1239
|
-
|
1439
|
+
def concatenate_line(self, n1, n2, el,
|
1440
|
+
rtol=1e-05, atol=1e-05,
|
1441
|
+
mdec=0,
|
1442
|
+
overlapping=False):
|
1443
|
+
none_val = 9999999.0
|
1444
|
+
my_m = self.m(none_val, dec=mdec)
|
1445
|
+
el_m = el.m(none_val, dec=mdec)
|
1446
|
+
#logger.debug("concatenate_line: my m=%s, el m=%s", my_m, el_m)
|
1447
|
+
if not np.isclose(my_m, el_m):
|
1448
|
+
#logger.debug("concatenate_line #1: m %s and %s are not close", my_m, el_m)
|
1240
1449
|
return None
|
1241
|
-
|
1242
1450
|
if n1 and n2:
|
1451
|
+
#logger.debug("concatenate_line #2: Nodes %s and %s", n1, n2)
|
1243
1452
|
return Line(Element(start=n1, end=n2))
|
1244
1453
|
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
if points_are_close(
|
1252
|
-
return Line(Element(start=
|
1454
|
+
my_p1, my_p2 = self.points_sorted(rtol=rtol, atol=atol)
|
1455
|
+
el_p1, el_p2 = el.points_sorted(rtol=rtol, atol=atol)
|
1456
|
+
|
1457
|
+
logger.debug("my p1: %s, p2: %s", my_p1,my_p2)
|
1458
|
+
logger.debug("el p1: %s, p2: %s", el_p1,el_p2)
|
1459
|
+
|
1460
|
+
if points_are_close(my_p2, el_p1, rtol=rtol, atol=atol):
|
1461
|
+
return Line(Element(start=my_p1, end=el_p2))
|
1462
|
+
if points_are_close(my_p1, el_p2, rtol=rtol, atol=atol):
|
1463
|
+
return Line(Element(start=el_p1, end=my_p2))
|
1464
|
+
|
1465
|
+
if overlapping:
|
1466
|
+
if points_are_close(my_p1, el_p1, rtol=rtol, atol=atol):
|
1467
|
+
my_d = distance(my_p1, my_p2)
|
1468
|
+
el_d = distance(el_p1, el_p2)
|
1469
|
+
if el_d > my_d:
|
1470
|
+
return Line(Element(start=el_p1, end=el_p2))
|
1471
|
+
else:
|
1472
|
+
return Line(Element(start=my_p1, end=my_p2))
|
1473
|
+
|
1474
|
+
if points_are_close(my_p2, el_p2, rtol=rtol, atol=atol):
|
1475
|
+
my_d = distance(my_p1, my_p2)
|
1476
|
+
el_d = distance(el_p1, el_p2)
|
1477
|
+
if el_d > my_d:
|
1478
|
+
return Line(Element(start=el_p1, end=el_p2))
|
1479
|
+
else:
|
1480
|
+
return Line(Element(start=my_p1, end=my_p2))
|
1481
|
+
|
1482
|
+
start = None
|
1483
|
+
if self.is_point_inside(el_p1,
|
1484
|
+
rtol=rtol,
|
1485
|
+
atol=atol,
|
1486
|
+
include_end=True,
|
1487
|
+
mdec=mdec):
|
1488
|
+
start = my_p1
|
1489
|
+
elif el.is_point_inside(my_p1,
|
1490
|
+
rtol=rtol,
|
1491
|
+
atol=atol,
|
1492
|
+
include_end=True,
|
1493
|
+
mdec=mdec):
|
1494
|
+
start = el_p1
|
1495
|
+
if start is None:
|
1496
|
+
logger.debug("concatenate_line #4: no start")
|
1497
|
+
return None
|
1498
|
+
end = None
|
1499
|
+
if self.is_point_inside(el_p2,
|
1500
|
+
rtol=rtol,
|
1501
|
+
atol=atol,
|
1502
|
+
include_end=True,
|
1503
|
+
mdec=mdec):
|
1504
|
+
end = my_p2
|
1505
|
+
elif el.is_point_inside(my_p2,
|
1506
|
+
rtol=rtol,
|
1507
|
+
atol=atol,
|
1508
|
+
include_end=True,
|
1509
|
+
mdec=mdec):
|
1510
|
+
end = el_p2
|
1511
|
+
if end is None:
|
1512
|
+
logger.debug("concatenate_line #4: no end")
|
1513
|
+
return None
|
1514
|
+
|
1515
|
+
return Line(Element(start=start, end=end))
|
1516
|
+
|
1253
1517
|
return None
|
1254
1518
|
|
1255
1519
|
def is_point_inside(self, point,
|
1256
1520
|
rtol=1e-03,
|
1257
1521
|
atol=1e-03,
|
1258
|
-
include_end=False
|
1259
|
-
|
1522
|
+
include_end=False,
|
1523
|
+
ignore_end=False,
|
1524
|
+
mdec=0):
|
1525
|
+
""" returns True if point is between start and end point of the line
|
1260
1526
|
"""
|
1261
|
-
if
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
if m1 is not None or m2 is not None:
|
1275
|
-
return False
|
1276
|
-
elif not np.isclose(m1, m2, rtol, atol):
|
1527
|
+
if not ignore_end:
|
1528
|
+
if points_are_close(point, self.p1, rtol, atol):
|
1529
|
+
return include_end
|
1530
|
+
if points_are_close(point, self.p2, rtol, atol):
|
1531
|
+
return include_end
|
1532
|
+
|
1533
|
+
elevation_tol = np.pi / 360 / 8 # 1/8 degree
|
1534
|
+
elevation_line = elevation_angle(alpha_line(self.p1, self.p2))
|
1535
|
+
elevation_point1 = elevation_angle(alpha_line(self.p1, point))
|
1536
|
+
elevation_point2 = elevation_angle(alpha_line(point, self.p2))
|
1537
|
+
|
1538
|
+
if not (np.isclose(elevation_line, elevation_point1, rtol=rtol, atol=atol) or \
|
1539
|
+
np.isclose(elevation_line, elevation_point2, rtol=rtol, atol=atol)):
|
1277
1540
|
return False
|
1278
1541
|
|
1279
1542
|
length = distance(self.p1, self.p2)
|
@@ -1299,7 +1562,9 @@ class Line(Shape):
|
|
1299
1562
|
n = line_n(self.p1, m)
|
1300
1563
|
p = intersect_point(center, self.p1, m, n)
|
1301
1564
|
|
1302
|
-
if self.is_point_inside(p,
|
1565
|
+
if self.is_point_inside(p,
|
1566
|
+
rtol=1e-03,
|
1567
|
+
atol=1e-03):
|
1303
1568
|
dist_min = min(distance(center, p), dist_min)
|
1304
1569
|
|
1305
1570
|
return (dist_min, dist_max)
|
@@ -1314,9 +1579,10 @@ class Line(Shape):
|
|
1314
1579
|
else:
|
1315
1580
|
alpha_p2 = alpha_line(center, self.p2)
|
1316
1581
|
if alpha_p1 is None:
|
1317
|
-
|
1582
|
+
assert(alpha_p2 is not None)
|
1583
|
+
return (alpha_p2, alpha_p2)
|
1318
1584
|
if alpha_p2 is None:
|
1319
|
-
|
1585
|
+
return (alpha_p1, alpha_p1)
|
1320
1586
|
if alpha_angle(alpha_p1, alpha_p2) < np.pi:
|
1321
1587
|
return (alpha_p1, alpha_p2)
|
1322
1588
|
else:
|
@@ -1331,6 +1597,17 @@ class Line(Shape):
|
|
1331
1597
|
def get_angle_of_arc(self):
|
1332
1598
|
return 0.0
|
1333
1599
|
|
1600
|
+
def is_near(self, n):
|
1601
|
+
if n[0] > max(self.p1[0], self.p2[0]) + 1e-02:
|
1602
|
+
return False
|
1603
|
+
if n[0] < min(self.p1[0], self.p2[0]) - 1e-02:
|
1604
|
+
return False
|
1605
|
+
if n[1] > max(self.p1[1], self.p2[1]) + 1e-02:
|
1606
|
+
return False
|
1607
|
+
if n[1] < min(self.p1[1], self.p2[1]) - 1e-02:
|
1608
|
+
return False
|
1609
|
+
return True
|
1610
|
+
|
1334
1611
|
def __str__(self):
|
1335
1612
|
return "Line p1={}, p2={}, n1={}, n2={}".format(self.p1,
|
1336
1613
|
self.p2,
|