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!!
