import operator as op; import functools as ft; from typing import Tuple; from geometry2d import *; withOutput=True; #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<# #------------------------------------------------------------------------------# T = TypeVar('T'); def flatten(data:List[List[T]])->List[T]: """ Returns all elements of the inner list elements packed in a list in same sequence """ return ft.reduce(op.concat,data); def tuple2Generator(seq:Sequence[T])->Tuple[T]: Ie=len(seq)-1; if Ie<0: return; for Ix in range(Ie): yield (seq[Ix],seq[Ix+1]); # end tuple2Generator def tuple3Generator(seq:Sequence[T])->Tuple[T]: Ie=len(seq)-2; if Ie<0: return; for Ix in range(Ie): yield (seq[Ix],seq[Ix+1],seq[Ix+2]); # end tuple3Generator #------------------------------------------------------------------------------# def removePointsOnSegments(points:List[Points])->None: pL=points; for (p1,p2,p3) in tuple3Generator(pL[:]): sgm=Segments(p1,p3); if sgm.isPointInside(p2): pL.remove(p2); # end for # end removePointsOnSegments def testForFullCircle(pt0:Points,points:Sequence[Points])->None: """ Der Polygonzug soll den Punkt pt0 nicht vollständig umschließen :raises InvalidDataError """ totalAngle=0; for (p1,p2) in tuple2Generator(points): sec=Sectors.toSector(pt0,p1,p2); totalAngle+=sec.openingAngleOf(); # end for if (totalAngleNone: if True: print('\n#'+'-'*78+'#'); print('\nObserver position:',pt0); # end printBegin def printFinal(points:Sequence[Points])->None: if True: print('\nVisible part - points: ',len(points)); for pt in points: print(pt); # end printFinal #------------------------------------------------------------------------------# #------------------------------------------------------------------------------# # Eingangsparameter sind der Standort des Beobachters und die Punkte des # Polygonzuges def simpleFilter(pObserver:Points, pTrain:PolygonTrains)->None: pt0=pObserver; printBegin(pt0); # Der Beobachtungspunkt darf nicht als Punkt enthalten sein. if pTrain.Points.count(pt0)>0: raise InvalidDataError('pObserver in pTrain'); # Aus Punktepaaren werden die Einzelsegmente des Polygonzuges gebildet segments=pTrain.getSegments(); # Der Beobachtungspunkt darf in keinem Segment liegen for sgm in segments: if sgm.isPointInside(pt0): raise InvalidDataError('pObserver in segment'); # Die Segmente duerfen sich nicht ueberschneiden Segments.areNotIntersecting(segments); # Der Beobachterstandort und die Punkte des Polygonzuges bilden # Strahlen, die hier zu einem Strahlenbueschel zusammengefasst werden coneOfRays=ConesOfRays.createFromPoints(pt0,pTrain.Points); # Die Strahlen bilden mit der x-Achse einen Winkel. Die Strahlen # werden nach dem aufsteigenden Winkel sortiert coneOfRays.Rays.sort(key=lambda ray: ray.Direction.dirAngleOf()); # Schneidet ein Strahl ein Segment im Innern, so wird dieses Segment # in zwei Einzelsegmente zerlegt. coneOfRays.divideIntersectedSegments(segments); # Die Segmmente werden Sektoren zugeordnet, wobei die Sektoren # aus zwei benachbarten Strahlenpaaren gebildet werden ld=[dirc.Direction for dirc in coneOfRays.Rays]; allSectors=[SectorWithSegments(pt0,*tdir) for tdir in tuple2Generator(ld)]; # Die Segmente werden in die zugehoerigen Sektoren gepackt for sgm in segments: SectorWithSegments.addToList(allSectors,sgm); # Aus jedem Sektor wird das Segment herausgesucht, das dem Beobachter # am naechsten ist: das sichtbare Segment! visiblePart=[sec.getMinimalDistanceSegment() for sec in allSectors] # Die Einzelpunkte der sichtbaren Segmente sind: visiblePartPointList=flatten([[sgm.P1,sgm.P2] for sgm in visiblePart]); # Doppelt auftretende Punkte werden bereinigt pL=visiblePartPointList; [pL.remove(pt) for pt in pL[:] if pL.count(pt)>1]; # Die Punkte werden (ganz wie die Strahlen) nach dem Winkel sortiert def keyByAnglesPoints(pt:Points)->float: return (pt-pt0).dirAngleOf(); visiblePartPointList.sort(key=keyByAnglesPoints); # Ein Punkt, der auf einem Segment liegt, gebildet aus # den beiden benachbarten Punkten, wird entfernt pL=visiblePartPointList; removePointsOnSegments(pL); # Der resultierende Polygonzug soll nicht vollstaendig um den Beobachter # herum laufen pL=visiblePartPointList; testForFullCircle(pt0,pL); printFinal(visiblePartPointList); # end simpleFilter #------------------------------------------------------------------------------# #------------------------------------------------------------------------------# if __name__ == '__main__': print('\n# Beginning Test ...\n'); #------------------------------------------------------------------------------# #------------------------------------------------------------------------------# if True: pt1=Points(1,1); pt2=Points(3,2); pt3=Points(4,2); pt4=Points(3,3); pt5=Points(5,4); pt6=Points(5,3); pt7=Points(6,3); pt8=Points(6,4); ptL=[pt1,pt2,pt3,pt4,pt5,pt6,pt7,pt8]; pTrain=PolygonTrains(ptL); if withOutput: print('\n#'+'-'*78+'\n'); print('\nPolygonTrain points:\n',pTrain); if True: pt0=Points(0,0); simpleFilter(pt0,pTrain); if True: pt0=Points(2,0); simpleFilter(pt0,pTrain); if True: pt0=Points(3,0); simpleFilter(pt0,pTrain); if True: pt0=Points(4,0); simpleFilter(pt0,pTrain); if True: pt0=Points(5,0); simpleFilter(pt0,pTrain); if True: pt0=Points(6,0); simpleFilter(pt0,pTrain); # end if #------------------------------------------------------------------------------# if True: pt11=Points(3,1); pt12=Points(2,2); pt13=Points(4,2); #pt14=Points(3,3); pt15=Points(1,3); pt16=Points(0,4); pt17=Points(5,3); pt18=Points(6,3); pt19=Points(6,4); ptL=[pt11,pt12,pt13,pt15,pt16,pt17,pt18,pt19]; pTrain=PolygonTrains(ptL); if withOutput: print('\n#'+'-'*78+'#'); print('\nPolygonTrain points:\n',pTrain); pt0=Points(4,0); simpleFilter(pt0,pTrain); # end if #------------------------------------------------------------------------------# #------------------------------------------------------------------------------# print('\n# Finished Test.\n'); # end if main #------------------------------------------------------------------------------# #------------------------------------------------------------------------------#