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