Best Python code snippet using autotest_python
terraincast.py
Source:terraincast.py
1from ursina import *2from ursina import distance as ursina_distance3from math import inf4from ursina.hit_info import HitInfo5678def prepare_terrain(terrain, debug=False, calculate_normals=True):910 #does calculations that are needed for every terraincast check, and sets up the entities that manage transofrmations11 #has the option to calculate all face normals for the terrain (quicker while running, but takes time to initiate)1213 terrain._cast = Entity(parent=terrain,14 model='sphere',15 color=color.orange,16 world_scale=0.1,17 position=(0, 1, 0),18 visible=debug,)19 if debug:20 terrain._cast.bound = Entity(parent=terrain,21 model='cube',22 color=color.rgba(255, 0, 0, 100))2324 terrain._cast.direction = Entity(parent=terrain,25 position=(0, 1, 0))2627 height_values = terrain.model.height_values2829 terrain._cast.width = terrain.model.width30 terrain._cast.depth = terrain.model.depth31 terrain._cast.aspect_ratio = terrain._cast.depth / terrain._cast.width3233 #correction_scale needed to account for cases where the other dimension is the smaller, so treated as 1 now34 if terrain._cast.depth < terrain._cast.width:35 terrain._cast.correction_scale = 1 / terrain._cast.aspect_ratio36 else:37 terrain._cast.correction_scale = 13839 terrain._cast.max = max([max(i) for i in height_values])40 terrain._cast.min = min([min(i) for i in height_values])4142 if calculate_normals:43 terrain._cast.prepared_height_values = []44 for scan_x, v in enumerate(height_values):45 row_to_add = []46 for scan_z, w in enumerate(v):47 quad_to_add = []48 for sub_face in [False, True]:49 quad_to_add.append(_terraincast_get_plane(terrain, scan_x, scan_z, sub_face))50 row_to_add.append(quad_to_add)51 terrain._cast.prepared_height_values.append(row_to_add)525354def _terraincast_get_plane(terrain, scan_x, scan_z, sub_face):55 #gets details needed for each plane that makes up the terrain56 from numpy import cross57 height_values = terrain.model.height_values58 if scan_z == len(height_values[0]) - 1 and scan_x == len(height_values) - 1:59 start = Vec3(scan_x, height_values[scan_x][scan_z], scan_z)60 right = Vec3(scan_x + 1, height_values[scan_x][scan_z], scan_z)61 left = Vec3(scan_x, height_values[scan_x][scan_z], scan_z + 1)6263 elif scan_z == len(height_values[0]) - 1:64 start = Vec3(scan_x, height_values[scan_x][scan_z], scan_z)65 right = Vec3(scan_x, height_values[scan_x][scan_z], scan_z + 1)66 left = Vec3(scan_x + 1, height_values[scan_x + 1][scan_z], scan_z + 1)67 # print('edge')6869 elif scan_x == len(height_values) - 1:70 start = Vec3(scan_x, height_values[scan_x][scan_z], scan_z)71 right = Vec3(scan_x, height_values[scan_x][scan_z + 1], scan_z + 1)72 left = Vec3(scan_x + 1, height_values[scan_x][scan_z + 1], scan_z + 1)7374 elif sub_face:75 start = Vec3(scan_x, height_values[scan_x][scan_z], scan_z)76 right = Vec3(scan_x, height_values[scan_x][scan_z + 1], scan_z + 1)77 left = Vec3(scan_x + 1, height_values[scan_x + 1][scan_z + 1], scan_z + 1)7879 else:80 start = Vec3(scan_x, height_values[scan_x][scan_z], scan_z)81 right = Vec3(scan_x + 1, height_values[scan_x + 1][scan_z], scan_z)82 left = Vec3(scan_x + 1, height_values[scan_x + 1][scan_z + 1], scan_z + 1)8384 normal = cross(left - start, right - start)85 if normal[1] < 0:86 normal = - normal87 normal = normal.tolist()88 normal = Vec3(*normal).normalized()8990 return start, normal919293def terraincast(origin,94 terrain,95 direction=Vec3(0, -1, 0),96 distance=inf,97 iterations=inf,98 debug=False,99 calculate_normals=True,100 ):101 from numpy import dot102 origin = Vec3(*origin)103 direction = Vec3(*direction)104105 height_values = terrain.model.height_values106 current_iterations = 0107108 if not hasattr(terrain, "_cast"):109 prepare_terrain(terrain, debug, calculate_normals)110111 #transformations to make terraincast line up with model space, then "height_values grid" space112 terrain._cast.world_position = origin113 terrain._cast.position += terrain.origin114115 terrain._cast.direction.world_position = terrain.world_position + direction.normalized()116117 model_origin = terrain._cast.position118 model_origin[0] = model_origin[0] / terrain._cast.correction_scale119 model_origin[2] = model_origin[2] / terrain._cast.correction_scale120121 model_origin = model_origin + Vec3(0.5, 0, 0.5 * terrain._cast.aspect_ratio)122123 model_direction = terrain._cast.direction.position124 model_direction[1] = model_direction[1] * terrain._cast.correction_scale125126 #sets up scan information that iterates through the grid (height_values "grid" space essentially)127 scan_direction = Vec3(model_direction[0] * terrain._cast.width, model_direction[1],128 model_direction[2] * terrain._cast.width)129 scan_tile = Vec3(model_origin[0] * terrain._cast.width, model_origin[1], model_origin[2] * terrain._cast.width)130 original_tile = Vec3(model_origin[0] * terrain._cast.width, model_origin[1], model_origin[2] * terrain._cast.width)131132 scan_max_distance = ursina_distance(Vec3(0, 0, 0), scan_direction) * distance133134 searching = True135 sub_face = False136137 # handle case where ray starts outside model138 x_scalar = 0139 y_scalar = 0140 z_scalar = 0141142 if scan_tile[0] < 0 and scan_direction[0] > 0:143 x_scalar = (0 - scan_tile[0]) / scan_direction[0]144 elif scan_tile[0] > len(height_values) and scan_direction[0] < 0:145 x_scalar = abs((scan_tile[0] - (len(height_values))) / scan_direction[0])146147 if scan_tile[2] < 0 and scan_direction[2] > 0:148 z_scalar = (0 - scan_tile[2]) / scan_direction[2]149 elif scan_tile[2] > len(height_values[0]) and scan_direction[2] < 0:150 z_scalar = abs((scan_tile[2] - (len(height_values[0]))) / scan_direction[2])151152 if scan_tile[1] < terrain._cast.min and scan_direction[1] > 0:153 y_scalar = (terrain._cast.min - scan_tile[1]) / scan_direction[1]154 elif scan_tile[1] > terrain._cast.max and scan_direction[1] < 0:155 y_scalar = abs((scan_tile[1] - terrain._cast.max) / scan_direction[1])156157 scan_tile += scan_direction * max([x_scalar, y_scalar, z_scalar])158159 #main loop through grid160 while searching:161162 #determines indexes required from grid163 scan_x = int(floor(scan_tile[0]))164 scan_z = int(floor(scan_tile[2]))165 if scan_tile[0] == scan_x and scan_direction[0] < 0:166 scan_x -= 1167 scan_x = max(scan_x, 0)168169 if scan_tile[2] == scan_z and scan_direction[2] < 0:170 scan_z -= 1171 scan_z = max(scan_z, 0)172173 current_iterations += 1174175 #failure cases176 if current_iterations == iterations:177 searching = False178 elif scan_x >= len(height_values):179 searching = False180 elif scan_z >= len(height_values[0]):181 searching = False182 elif scan_x < 0:183 searching = False184 elif scan_z < 0:185 searching = False186 elif scan_tile[1] > terrain._cast.max + 1:187 searching = False188 elif scan_tile[1] < terrain._cast.min - 1:189 searching = False190 elif ursina_distance(scan_tile, original_tile) > scan_max_distance:191 searching = False192193 if not searching:194 break195196 if calculate_normals:197 start, normal = terrain._cast.prepared_height_values[scan_x][scan_z][sub_face]198 else:199 start, normal = _terraincast_get_plane(terrain, scan_x, scan_z, sub_face)200201 bottom_dot = dot(scan_direction, normal)202 top_dot = dot(start - original_tile, normal)203 if bottom_dot != 0:204 magnitude = top_dot / bottom_dot205 elif top_dot == 0:206 magnitude = 0207 else:208 magnitude = None209210 if magnitude is not None:211 point = original_tile + magnitude * scan_direction212 else:213 magnitude = 0214 point = Vec3(scan_x + 2, 0, scan_z + 2)215216 in_front = magnitude >= 0217 correct_sub_triangle = (point[0] % 1 <= point[2] % 1) == sub_face or point[0] % 1 == point[2] % 1218 x_tolerance = abs(point[0] - scan_x - 0.5) <= 0.5219 z_tolerance = abs(point[2] - scan_z - 0.5) <= 0.5220 #success case221 if in_front and correct_sub_triangle and x_tolerance and z_tolerance:222 break223224 elif sub_face:225 # works out next "tile" to move to226 if scan_direction[0] > 0:227 x_scalar = (1 - scan_tile[0] % 1) / scan_direction[0]228 elif scan_direction[0] < 0:229 corrected = (-scan_tile[0]) % 1230 x_scalar = abs((1 - corrected) / scan_direction[0])231 else:232 x_scalar = None233234 if scan_direction[2] > 0:235 z_scalar = (1 - scan_tile[2] % 1) / scan_direction[2]236 elif scan_direction[2] < 0:237 corrected = (-scan_tile[2]) % 1238 z_scalar = abs((1 - corrected) / scan_direction[2])239 else:240 z_scalar = None241242 if x_scalar is not None and (z_scalar is None or x_scalar < z_scalar):243 scan_tile += x_scalar * scan_direction244 elif z_scalar is not None:245 scan_tile += z_scalar * scan_direction246 else:247 searching = False248 break249250 sub_face = not sub_face251252 if debug:253 #generates bounding box254 l = -0.5 * terrain._cast.correction_scale - terrain.origin[0]255 r = 0.5 * terrain._cast.correction_scale - terrain.origin[0]256257 f = 0.5 * terrain._cast.aspect_ratio * terrain._cast.correction_scale - terrain.origin[2]258 b = -0.5 * terrain._cast.aspect_ratio * terrain._cast.correction_scale - terrain.origin[2]259260 u = terrain._cast.max - terrain.origin[1]261 d = terrain._cast.min - terrain.origin[1]262263 verts = (264 Vec3(l, d, b), Vec3(r, d, b), Vec3(r, u, b), Vec3(l, u, b),265 Vec3(l, d, f), Vec3(r, d, f), Vec3(r, u, f), Vec3(l, u, f)266 )267268 tris = (269 (0, 1, 2, 3), (5, 4, 7, 6), # forward, back270 (3, 2, 6, 7), (4, 5, 1, 0), # up, down271 (1, 5, 6, 2), (4, 0, 3, 7) # right, left272 )273 cube = Mesh(verts, tris)274 terrain._cast.bound.model = cube275 terrain._cast.bound.model.generate()276 if searching:277 #geneartess hit info and undoes some transformations278 point = Vec3(point[0] / terrain._cast.width,279 point[1],280 point[2] / terrain._cast.width)281282 point -= Vec3(0.5, 0, 0.5 * terrain._cast.aspect_ratio)283284 point[0] = point[0] * terrain._cast.correction_scale285 point[2] = point[2] * terrain._cast.correction_scale286 terrain._cast.position = point287 terrain._cast.position -= terrain.origin288289 terrain._cast.visible = debug290291 terrain._cast.direction.position = normal / terrain._cast.correction_scale292293 hit = HitInfo(hit=True)294 hit.point = point295 hit.world_point = terrain._cast.world_position296297 hit.normal = Vec3(*normal)298 hit.world_normal = terrain._cast.direction.world_position - terrain.world_position299 hit.distance = ursina_distance(origin, hit.world_point)300 hit.entity = terrain301 hit.entities = [terrain, ]302 hit.hits = [True, ]303 if hit.distance > distance:304 hit = HitInfo(hit=False)305 return hit306 else:307 terrain._cast.visible = False308309 hit = HitInfo(hit=False)310 return hit311312313if __name__ == '__main__':314 app = Ursina()315316 terrainEntity = Entity(model=Terrain('heightmap_1', skip=8),317 scale=(20, 5, 20),318 rotation=(30, 40, 50),319 origin=(1, 1, 1),320 texture='heightmap_1')321322 hit_entity = Entity(model='sphere', scale=0.1)323 EditorCamera()324325326 def update():327 hit = terraincast(camera.world_position, terrainEntity, direction=camera.forward, debug=True)328 if hit:329 hit_entity.position = hit.world_point + hit.world_normal330331 hit.entity.rotation_y += 2*time.dt332333 Sky()
...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!