| 
				
			 | 
			
			
				@@ -3,6 +3,7 @@ from math import sqrt 
			 | 
		
	
		
			
			| 
				3
			 | 
			
				3
			 | 
			
			
				 from math import degrees 
			 | 
		
	
		
			
			| 
				4
			 | 
			
				4
			 | 
			
			
				 from math import acos 
			 | 
		
	
		
			
			| 
				5
			 | 
			
				5
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				6
			 | 
			
			
				+from synergine2.exceptions import SynergineException 
			 | 
		
	
		
			
			| 
				6
			 | 
			
				7
			 | 
			
			
				 from synergine2.simulation import SubjectMechanism, Subjects, Subject 
			 | 
		
	
		
			
			| 
				7
			 | 
			
				8
			 | 
			
			
				 from synergine2.simulation import Simulation as BaseSimulation 
			 | 
		
	
		
			
			| 
				8
			 | 
			
				9
			 | 
			
			
				  
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -81,6 +82,14 @@ DIRECTION_MODIFIERS = { 
			 | 
		
	
		
			
			| 
				81
			 | 
			
				82
			 | 
			
			
				 } 
			 | 
		
	
		
			
			| 
				82
			 | 
			
				83
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				83
			 | 
			
				84
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				85
			 | 
			
			
				+class XYZException(SynergineException): 
			 | 
		
	
		
			
			| 
				
			 | 
			
				86
			 | 
			
			
				+    pass 
			 | 
		
	
		
			
			| 
				
			 | 
			
				87
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				88
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				89
			 | 
			
			
				+class PositionNotPossible(XYZException): 
			 | 
		
	
		
			
			| 
				
			 | 
			
				90
			 | 
			
			
				+    pass 
			 | 
		
	
		
			
			| 
				
			 | 
			
				91
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				92
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				84
			 | 
			
				93
			 | 
			
			
				 def get_degree_from_north(a, b): 
			 | 
		
	
		
			
			| 
				85
			 | 
			
				94
			 | 
			
			
				     if a == b: 
			 | 
		
	
		
			
			| 
				86
			 | 
			
				95
			 | 
			
			
				         return 0 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -130,6 +139,9 @@ class ProximityMixin(object): 
			 | 
		
	
		
			
			| 
				130
			 | 
			
				139
			 | 
			
			
				     direction_round_decimals = 0 
			 | 
		
	
		
			
			| 
				131
			 | 
			
				140
			 | 
			
			
				     distance_round_decimals = 2 
			 | 
		
	
		
			
			| 
				132
			 | 
			
				141
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				142
			 | 
			
			
				+    def have_to_check_position_is_possible(self) -> bool: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				143
			 | 
			
			
				+        return True 
			 | 
		
	
		
			
			| 
				
			 | 
			
				144
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				133
			 | 
			
				145
			 | 
			
			
				     def get_for_position( 
			 | 
		
	
		
			
			| 
				134
			 | 
			
				146
			 | 
			
			
				             self, 
			 | 
		
	
		
			
			| 
				135
			 | 
			
				147
			 | 
			
			
				             position, 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -145,6 +157,9 @@ class ProximityMixin(object): 
			 | 
		
	
		
			
			| 
				145
			 | 
			
				157
			 | 
			
			
				                 if subject == exclude_subject: 
			 | 
		
	
		
			
			| 
				146
			 | 
			
				158
			 | 
			
			
				                     continue 
			 | 
		
	
		
			
			| 
				147
			 | 
			
				159
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				160
			 | 
			
			
				+                if self.have_to_check_position_is_possible() and not simulation.is_possible_position(subject.position): 
			 | 
		
	
		
			
			| 
				
			 | 
			
				161
			 | 
			
			
				+                    continue 
			 | 
		
	
		
			
			| 
				
			 | 
			
				162
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				148
			 | 
			
				163
			 | 
			
			
				                 distance = round( 
			 | 
		
	
		
			
			| 
				149
			 | 
			
				164
			 | 
			
			
				                     self.get_distance_of( 
			 | 
		
	
		
			
			| 
				150
			 | 
			
				165
			 | 
			
			
				                         position=position, 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -196,18 +211,35 @@ class XYZSubjects(Subjects): 
			 | 
		
	
		
			
			| 
				196
			 | 
			
				211
			 | 
			
			
				         # TODO: init xyz with given list 
			 | 
		
	
		
			
			| 
				197
			 | 
			
				212
			 | 
			
			
				         self.xyz = {} 
			 | 
		
	
		
			
			| 
				198
			 | 
			
				213
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				214
			 | 
			
			
				+    def have_to_check_position_is_possible(self) -> bool: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				215
			 | 
			
			
				+        return True 
			 | 
		
	
		
			
			| 
				
			 | 
			
				216
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				199
			 | 
			
				217
			 | 
			
			
				     def remove(self, value: XYZSubjectMixin): 
			 | 
		
	
		
			
			| 
				200
			 | 
			
				218
			 | 
			
			
				         super().remove(value) 
			 | 
		
	
		
			
			| 
				201
			 | 
			
				219
			 | 
			
			
				         del self.xyz[value.position] 
			 | 
		
	
		
			
			| 
				202
			 | 
			
				220
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				203
			 | 
			
				221
			 | 
			
			
				     def append(self, p_object: XYZSubjectMixin): 
			 | 
		
	
		
			
			| 
				204
			 | 
			
				222
			 | 
			
			
				         super().append(p_object) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				223
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				224
			 | 
			
			
				+        if self.have_to_check_position_is_possible() \ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				225
			 | 
			
			
				+           and not self.simulation.is_possible_subject_position(p_object, p_object.position): 
			 | 
		
	
		
			
			| 
				
			 | 
			
				226
			 | 
			
			
				+            raise PositionNotPossible('Position {} for {} is not possible'.format( 
			 | 
		
	
		
			
			| 
				
			 | 
			
				227
			 | 
			
			
				+                p_object.position, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				228
			 | 
			
			
				+                p_object, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				229
			 | 
			
			
				+            )) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				230
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				205
			 | 
			
				231
			 | 
			
			
				         self.xyz[p_object.position] = p_object 
			 | 
		
	
		
			
			| 
				206
			 | 
			
				232
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				207
			 | 
			
				233
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				208
			 | 
			
				234
			 | 
			
			
				 class XYZSimulation(BaseSimulation): 
			 | 
		
	
		
			
			| 
				209
			 | 
			
				235
			 | 
			
			
				     accepted_subject_class = XYZSubjects 
			 | 
		
	
		
			
			| 
				210
			 | 
			
				236
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				237
			 | 
			
			
				+    def is_possible_subject_position(self, subject: XYZSubjectMixin, position: tuple) -> bool: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				238
			 | 
			
			
				+        return self.is_possible_position(position) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				239
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				240
			 | 
			
			
				+    def is_possible_position(self, position: tuple) -> bool: 
			 | 
		
	
		
			
			| 
				
			 | 
			
				241
			 | 
			
			
				+        return True 
			 | 
		
	
		
			
			| 
				
			 | 
			
				242
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				211
			 | 
			
				243
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				212
			 | 
			
				244
			 | 
			
			
				 def get_direction_from_north_degree(degree: float): 
			 | 
		
	
		
			
			| 
				213
			 | 
			
				245
			 | 
			
			
				     for range, direction in DIRECTION_FROM_NORTH_DEGREES.items(): 
			 |