visible_segments.py
1     
2    import operator as op; 
3    import functools as ft; 
4    from typing import Tuple; 
5     
6    from geometry2d import *; 
7     
8    withOutput=True; #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<# 
9    #------------------------------------------------------------------------------# 
10    
11   T = TypeVar('T'); 
12    
13   def flatten(data:List[List[T]])->List[T]: 
14       """ Returns all elements of the inner list elements 
15           packed in a list in same sequence 
16       """ 
17       return ft.reduce(op.concat,data); 
18    
19   def tuple2Generator(seq:Sequence[T])->Tuple[T]: 
20       Ie=len(seq)-1; 
21       if Ie<0: return; 
22       for Ix in range(Ie): 
23           yield (seq[Ix],seq[Ix+1]); 
24   # end tuple2Generator 
25    
26   def tuple3Generator(seq:Sequence[T])->Tuple[T]: 
27       Ie=len(seq)-2; 
28       if Ie<0: return; 
29       for Ix in range(Ie): 
30           yield (seq[Ix],seq[Ix+1],seq[Ix+2]); 
31   # end tuple3Generator 
32   #------------------------------------------------------------------------------# 
33    
34   def removePointsOnSegments(points:List[Points])->None: 
35       pL=points; 
36       for (p1,p2,p3) in tuple3Generator(pL[:]): 
37           sgm=Segments(p1,p3); 
38           if sgm.isPointInside(p2): 
39               pL.remove(p2); 
40       # end for 
41   # end removePointsOnSegments 
42    
43   def testForFullCircle(pt0:Points,points:Sequence[Points])->None: 
44       """ Der Polygonzug soll den Punkt pt0 nicht vollständig 
45           umschließen 
46           :raises InvalidDataError 
47       """ 
48       totalAngle=0; 
49       for (p1,p2) in tuple2Generator(points): 
50           sec=Sectors.toSector(pt0,p1,p2); 
51           totalAngle+=sec.openingAngleOf(); 
52       # end for 
53       if (totalAngle<twicePi) and not areAnglesEqual(totalAngle,twicePi): 
54           pass; 
55       else: 
56           raise InvalidDataError('Full circle data'); 
57       # end if 
58   # end testForFullCircle 
59    
60   def printBegin(pt0:Points)->None: 
61       if True: 
62           print('\n#'+'-'*78+'#'); 
63           print('\nObserver position:',pt0); 
64   # end printBegin 
65    
66   def printFinal(points:Sequence[Points])->None: 
67       if True: 
68           print('\nVisible part - points: ',len(points)); 
69           for pt in points: 
70               print(pt); 
71   # end printFinal 
72   #------------------------------------------------------------------------------# 
73   #------------------------------------------------------------------------------# 
74    
75   # Eingangsparameter sind der Standort des Beobachters und die Punkte des 
76   # Polygonzuges 
77    
78   def simpleFilter(pObserver:Points, 
79                    pTrain:PolygonTrains)->None: 
80       pt0=pObserver; 
81    
82       printBegin(pt0); 
83    
84       # Der Beobachtungspunkt darf nicht als Punkt enthalten sein. 
85    
86       if pTrain.Points.count(pt0)>0: 
87           raise InvalidDataError('pObserver in pTrain'); 
88    
89       # Aus Punktepaaren werden die Einzelsegmente des Polygonzuges gebildet 
90    
91       segments=pTrain.getSegments(); 
92    
93       # Der Beobachtungspunkt darf in keinem Segment liegen 
94    
95       for sgm in segments: 
96           if sgm.isPointInside(pt0): 
97               raise InvalidDataError('pObserver in segment'); 
98    
99       # Die Segmente duerfen sich nicht ueberschneiden 
100   
101      Segments.areNotIntersecting(segments); 
102   
103      # Der Beobachterstandort und die Punkte des Polygonzuges bilden 
104      # Strahlen, die hier zu einem Strahlenbueschel zusammengefasst werden 
105   
106      coneOfRays=ConesOfRays.createFromPoints(pt0,pTrain.Points); 
107   
108      # Die Strahlen bilden mit der x-Achse einen Winkel. Die Strahlen 
109      # werden nach dem aufsteigenden Winkel sortiert 
110   
111      coneOfRays.Rays.sort(key=lambda ray: ray.Direction.dirAngleOf()); 
112   
113      # Schneidet ein Strahl ein Segment im Innern, so wird dieses Segment 
114      # in zwei Einzelsegmente zerlegt. 
115   
116      coneOfRays.divideIntersectedSegments(segments); 
117   
118      # Die Segmmente werden Sektoren zugeordnet, wobei die Sektoren 
119      # aus zwei benachbarten Strahlenpaaren gebildet werden 
120   
121      ld=[dirc.Direction for dirc in coneOfRays.Rays]; 
122      allSectors=[SectorWithSegments(pt0,*tdir) for tdir in tuple2Generator(ld)]; 
123   
124      # Die Segmente werden in die zugehoerigen Sektoren gepackt 
125   
126      for sgm in segments: 
127          SectorWithSegments.addToList(allSectors,sgm); 
128   
129      # Aus jedem Sektor wird das Segment herausgesucht, das dem Beobachter 
130      # am naechsten ist: das sichtbare Segment! 
131   
132      visiblePart=[sec.getMinimalDistanceSegment() for sec in allSectors] 
133   
134      # Die Einzelpunkte der sichtbaren Segmente sind: 
135   
136      visiblePartPointList=flatten([[sgm.P1,sgm.P2] for sgm in visiblePart]); 
137   
138      # Doppelt auftretende Punkte werden bereinigt 
139   
140      pL=visiblePartPointList; 
141      [pL.remove(pt) for pt in pL[:] if pL.count(pt)>1]; 
142   
143      # Die Punkte werden (ganz wie die Strahlen) nach dem Winkel sortiert 
144   
145      def keyByAnglesPoints(pt:Points)->float: 
146          return (pt-pt0).dirAngleOf(); 
147      visiblePartPointList.sort(key=keyByAnglesPoints); 
148   
149      # Ein Punkt, der auf einem Segment liegt, gebildet aus 
150      # den beiden benachbarten Punkten, wird entfernt 
151   
152      pL=visiblePartPointList; 
153      removePointsOnSegments(pL); 
154   
155      # Der resultierende Polygonzug soll nicht vollstaendig um den Beobachter 
156      # herum laufen 
157   
158      pL=visiblePartPointList; 
159      testForFullCircle(pt0,pL); 
160   
161      printFinal(visiblePartPointList); 
162  # end simpleFilter 
163  #------------------------------------------------------------------------------# 
164  #------------------------------------------------------------------------------# 
165   
166  if __name__ == '__main__': 
167      print('\n# Beginning Test ...\n'); 
168  #------------------------------------------------------------------------------# 
169  #------------------------------------------------------------------------------# 
170   
171      if True: 
172          pt1=Points(1,1); 
173          pt2=Points(3,2); 
174          pt3=Points(4,2); 
175          pt4=Points(3,3); 
176          pt5=Points(5,4); 
177          pt6=Points(5,3); 
178          pt7=Points(6,3); 
179          pt8=Points(6,4); 
180          ptL=[pt1,pt2,pt3,pt4,pt5,pt6,pt7,pt8]; 
181          pTrain=PolygonTrains(ptL); 
182   
183          if withOutput: 
184              print('\n#'+'-'*78+'\n'); 
185              print('\nPolygonTrain points:\n',pTrain); 
186   
187          if True: 
188              pt0=Points(0,0); 
189              simpleFilter(pt0,pTrain); 
190   
191          if True: 
192              pt0=Points(2,0); 
193              simpleFilter(pt0,pTrain); 
194   
195          if True: 
196              pt0=Points(3,0); 
197              simpleFilter(pt0,pTrain); 
198   
199          if True: 
200              pt0=Points(4,0); 
201              simpleFilter(pt0,pTrain); 
202   
203          if True: 
204              pt0=Points(5,0); 
205              simpleFilter(pt0,pTrain); 
206   
207          if True: 
208              pt0=Points(6,0); 
209              simpleFilter(pt0,pTrain); 
210      # end if 
211  #------------------------------------------------------------------------------# 
212   
213      if True: 
214          pt11=Points(3,1); 
215          pt12=Points(2,2); 
216          pt13=Points(4,2); 
217          #pt14=Points(3,3); 
218          pt15=Points(1,3); 
219          pt16=Points(0,4); 
220          pt17=Points(5,3); 
221          pt18=Points(6,3); 
222          pt19=Points(6,4); 
223          ptL=[pt11,pt12,pt13,pt15,pt16,pt17,pt18,pt19]; 
224          pTrain=PolygonTrains(ptL); 
225   
226          if withOutput: 
227              print('\n#'+'-'*78+'#'); 
228              print('\nPolygonTrain points:\n',pTrain); 
229   
230          pt0=Points(4,0); 
231          simpleFilter(pt0,pTrain); 
232      # end if 
233  #------------------------------------------------------------------------------# 
234  #------------------------------------------------------------------------------# 
235      print('\n# Finished Test.\n'); 
236  # end if main 
237  #------------------------------------------------------------------------------# 
238  #------------------------------------------------------------------------------# 
239