[–] 2 points 6 days ago

If I ask an LLM to do something, the commit message is usually just the prompt. If it's for code I wrote myself, my process is to take the message, read it over, then edit appropriately before running git commit myself. It seems that this last step is what does it.

  • source
  • parent
  • context
  • [–] 1 point 3 weeks ago

    In my opinion, the purpose of documentation isn't just documenting. It's a contract. It tells you what parts of the API are meant to be user-facing and that the devs will try to keep backwards compatible from one release to the next.

  • source
  • [–] 2 points 1 month ago

    I don't think it's exercise related. Even back when I competed in some fairly cardio-heavy sports (~8h per week of cardio/endurance work on top of regular strength training), medical masks still felt incredibly suffocating.

  • source
  • parent
  • context
  • [–] 17 points 1 month ago

    The problem is that all the rules contradict each other in one way or another. If you know the reason for the rule, then you know which ones take precedence in each situation. Otherwise, you're just making arbitrary choices on which ones to follow and which to break, and if you can just arbitrarily break a rule with no obvious consequences, then why bother ever following it?

  • source
  • [–] 1 point 1 month ago

    A little too good. The hard part is putting an end to the focus. The workaround to that is to purposely maintain a state of half-focus so that breaking away is easier, but then I'm not actually focused.

  • source
  • [–] 16 points 2 months ago (1 child)

    I got this too a few weeks ago and couldn't find any information on how to convert the address back to normal. I guess it makes sense if most people don't get those results. My fix was to just use a different search engine.

    fyi, I got it while I was logged in.

  • source
  •  

    I'm working on some tools for manipulating panorama images and as a first step, I made a simple python script for viewing the images. I'm sharing it here for anyone who might find it useful to have a working implementation to reference.

    It's set up as a uv script, so you can run it with uv run script.py image.jpg where script.py is the file containing this code.

    A few things I'm not quite happy with at the moment:

    1. The mouse control mapping function is wrong, but it works well enough to be usable.
    2. The script needs better clarity and consistency in variable naming when converting between any of the five different coordinate systems.

    spoiler

    # /// script  
    # dependencies = [  
    #   "numpy",  
    #   "pillow",  
    #   "pygame",  
    # ]  
    # ///  
    
    # Convention:  
    #   From the perspective of a viewer looking through the viewport...  
    #   In 2D, the x-axis points to the right, and the y-axis points up.  
    #   In 3D, we just extend this.  
    #       The x-axis points to the right, the y-axis points up, and the z-axis points forward into the screen.  
    #   When yaw = pitch = roll = 0, we are looking forward at the point (x,y,z) = (0,0,1) on the unit sphere  
    #   We use the right hand rule for rotation direction. With the right thumb pointing in the direction of the axis, then a positive rotation around that axis (i.e. a rotation that increases the angle) follows the direction of the fingers' curl.  
    
    
    from collections import defaultdict  
    import itertools  
    from pathlib import Path  
    import sys  
    
    import numpy as np  
    from PIL import Image  
    import pygame  
    
    
    def ypr_to_rotation_matrix(yaw, pitch, roll):  
        # Create the rotation matrices  
        # See https://en.wikipedia.org/wiki/Rotation_matrix#General_3D_rotations  
    
        rotation_matrix_yaw = np.array([  
            [np.cos(yaw), 0, -np.sin(yaw)],  
            [0,           1, 0          ],  
            [np.sin(yaw), 0, np.cos(yaw)]  
        ])  
        rotation_matrix_pitch = np.array([  
            [1, 0,             0            ],  
            [0, np.cos(pitch), -np.sin(pitch)],  
            [0, np.sin(pitch), np.cos(pitch) ]  
        ])  
        rotation_matrix_roll = np.array([  
            [np.cos(roll), -np.sin(roll), 0],  
            [np.sin(roll), np.cos(roll),  0],  
            [0,            0,             1]  
        ])  
    
        rotation_matrix = rotation_matrix_yaw @ rotation_matrix_pitch @ rotation_matrix_roll  
    
        return rotation_matrix  
    
    
    def equirectangular_to_rectilinear_image(img: Image.Image, size: tuple[int,int], viewport_dist: float, yaw, pitch, roll) -> Image.Image:  
        """  
        Args:  
            img: Input equirectangular image.  
            size: Output image size (width, height) in pixels.  
            viewport_dist: The distance between the viewport plane and the viewer. Assume the input image is on a unit sphere.  
        """  
    
        output_mesh = np.meshgrid(np.arange(size[0]), np.arange(size[1]))  
        output_x = output_mesh[0].flatten()  
        output_y = output_mesh[1].flatten()  
    
        # Compute the point on the viewport plane in 3D space  
        output_3d_x = (output_x - size[0] // 2) / size[0]  
        #output_3d_y = (output_y - size[1] // 2) / size[1]  
        output_3d_y = (output_y - size[1] // 2) / size[0]  
        output_3d_z = np.full_like(output_3d_x, viewport_dist)  
    
        # Normalize to put them on the unit sphere  
        norm = np.sqrt(output_3d_x ** 2 + output_3d_y ** 2 + output_3d_z ** 2)  
        unit_x = output_3d_x / norm  
        unit_y = output_3d_y / norm  
        unit_z = output_3d_z / norm  
    
        # Rotate the unit sphere coordinates based on the yaw/pitch/roll angles  
        rotation_matrix = ypr_to_rotation_matrix(yaw, pitch, roll)  
        rotated_coords = rotation_matrix @ np.vstack((unit_x, unit_y, unit_z))  
    
        # Convert back to lat/long coordinates  
        rotated_x, rotated_y, rotated_z = rotated_coords  
        latitude_1  = np.arcsin(rotated_y)  
        longitude_1 = np.arctan2(rotated_x, rotated_z)  
    
        # Convert to pixel coordinates in the equirectangular image  
        equirectangular_x = (longitude_1 / (2 * np.pi) * img.width).astype(int) % img.width  
        equirectangular_y = ((latitude_1 + np.pi / 2) / np.pi * img.height).astype(int) % img.height  
    
        # Sample the equirectangular image to create the rectilinear image  
        rectilinear_image = np.array(img)[equirectangular_y, equirectangular_x]  
    
        return Image.fromarray(rectilinear_image.reshape(size[1], size[0], -1))  
    
    
    def map_mouse_drag(mouse_coord_start: tuple[int,int], mouse_coord_end: tuple[int,int], viewport_size: tuple[int,int], viewport_dist: float) -> tuple[float,float,float]:  
        """  
        Given a mouse click and drag event, compute the corresponding change in rotation.  
    
        Args:  
            mouse_coord_start: Mousedown coordinates on the image. Top-left corner is (0,0), bottom-right corner is `viewport_size`.  
            mouse_coord_end: Coordinate of the cursor after the click and drag. Follows the same convention as `mouse_coord_start`.  
            viewport_size: (width, height) of the viewport in pixels.  
            viewport_dist: Distance between the viewer and the viewport. A distance of 1 means the viewport is tangent to the unit sphere on which the image lies.  
        """  
    
        # Convert to numpy arrays  
        size = viewport_size[0]  
        np_start = np.array([mouse_coord_start[0]/size, mouse_coord_start[1]/size, viewport_dist])  
        np_end = np.array([mouse_coord_end[0]/size, mouse_coord_end[1]/size, viewport_dist])  
    
        # Map mouse coordinates to points in the unit sphere  
        unit_start = np_start / np.sqrt((np_start ** 2).sum())  
        unit_end   = np_end   / np.sqrt((np_end   ** 2).sum())  
    
        # Project onto the x-y plane  
        proj_start = np.array([unit_start[0], 0, unit_start[2]])  
        proj_end   = np.array([unit_end[0],   0, unit_end[2]])  
    
        # a x b = |a| |b| sin(theta) n  
        # If positive, then the angle is positive going from a to b. Otherwise, it's negative.  
        # Compute the y component of proj_start x proj_end  
        # (note: all other components are 0)  
        cross_product_y = unit_end[2] * unit_start[0] - unit_end[0] * unit_start[2]  
        mag_proj_start = np.sqrt((proj_start ** 2).sum())  
        mag_proj_end   = np.sqrt((proj_end   ** 2).sum())  
        sin_delta_yaw = cross_product_y / (mag_proj_start * mag_proj_end)  
        delta_yaw = -np.arcsin(sin_delta_yaw) # sign will match that of `sin_delta_yaw`  
    
        # Project onto the y-z plane  
        proj_start = np.array([0, unit_start[1], unit_start[2]])  
        proj_end   = np.array([0, unit_end[1],   unit_end[2]])  
    
        # Compute the x component of proj_start x proj_end  
        cross_product_x = unit_end[2] * unit_start[1] - unit_end[1] * unit_start[2]  
        mag_proj_start = np.sqrt((proj_start ** 2).sum())  
        mag_proj_end   = np.sqrt((proj_end   ** 2).sum())  
        sin_delta_pitch = cross_product_x / (mag_proj_start * mag_proj_end)  
        delta_pitch = -np.arcsin(sin_delta_pitch) # sign will match that of `sin_delta_yaw`  
    
        return (delta_yaw, delta_pitch, 0)  
    
    
    def viewer(image: Image.Image, size: tuple[int, int]):  
        yaw = 0  
        pitch = 0  
        roll = 0  
        viewport_dist = 0.5  
        delta_yaw = np.pi / 100  
        delta_pitch = np.pi / 100  
        delta_roll = np.pi / 100  
    
        key_is_down = defaultdict(lambda: False)  
        mousedown_coord = None # Relative to the window (i.e. top-left is (0,0))  
        mousedown_ypr = None  
        mouse_coord = None # Relative to the window  
        pygame.init()  
        screen = pygame.display.set_mode(size)  
        clock = pygame.time.Clock()  
    
        for i in itertools.count():  
            # Process player inputs.  
            for event in pygame.event.get():  
                if event.type == pygame.QUIT:  
                    pygame.quit()  
                    raise SystemExit  
                elif event.type == pygame.KEYDOWN:  
                    key_is_down[event.key] = True  
                elif event.type == pygame.KEYUP:  
                    key_is_down[event.key] = False  
                elif event.type == pygame.MOUSEMOTION:  
                    mouse_coord = event.pos  
                elif event.type == pygame.MOUSEBUTTONDOWN:  
                    if event.button == 1:  
                        mousedown_coord = event.pos  
                        mousedown_ypr = (yaw, pitch, roll)  
                elif event.type == pygame.MOUSEBUTTONUP:  
                    if event.button == 1:  
                        mousedown_coord = None  
                        mousedown_ypr = None  
    
            # Do logical updates here.  
            if mousedown_coord is None:  
                if key_is_down[pygame.K_LEFT]:  
                    yaw += delta_yaw  
                if key_is_down[pygame.K_RIGHT]:  
                    yaw -= delta_yaw  
                if key_is_down[pygame.K_UP]:  
                    pitch += delta_pitch  
                if key_is_down[pygame.K_DOWN]:  
                    pitch -= delta_pitch  
                if key_is_down[pygame.K_q]:  
                    roll -= delta_roll  
                if key_is_down[pygame.K_e]:  
                    roll += delta_roll  
            else:  
                assert mousedown_ypr is not None  
                assert mouse_coord is not None  
                delta_ypr = map_mouse_drag(  
                    mouse_coord_start = mousedown_coord,  
                    mouse_coord_end = mouse_coord,  
                    viewport_size = size,  
                    viewport_dist = viewport_dist,  
                )  
                yaw, pitch, roll = (  
                    mousedown_ypr[0] + delta_ypr[0],  
                    mousedown_ypr[1] + delta_ypr[1],  
                    mousedown_ypr[2] + delta_ypr[2],  
                )  
    
            img = equirectangular_to_rectilinear_image(  
              img = image,  
              size = size,  
              viewport_dist = viewport_dist,  
              yaw = yaw, pitch = pitch, roll = roll,  
            )  
    
            # Render the graphics here.  
            surface = pygame.image.fromstring(  
                    img.tobytes(), img.size, img.mode  
            )  
            screen.blit(surface, (0, 0))  
    
            pygame.display.flip()  
    
            clock.tick(20)  
    
        pygame.quit()  
    
    
    def load_image(file_path: Path, target_width: int = 500) -> Image.Image:  
        img_full_res = Image.open(file_path)  
    
        width, height = img_full_res.size  
    
        # Calculate target height based on aspect ratio  
        ratio = target_width / float(width)  
        target_height = int(float(height) * float(ratio))  
    
        # Resize with the fastest/cheapest method  
        img_low_res = img_full_res.resize(  
                (target_width, target_height),  
                Image.Resampling.NEAREST,  
        )  
    
        return img_low_res  
    
    
    def main():  
        args = sys.argv  
    
        file_path = Path(args[1])  
    
        viewer(  
            image = load_image(file_path),  
            size = (300, 200),  
        )  
    
    
    if __name__ == '__main__':  
        main()  
    

     

    Progress bars often come with text that tells you what it's doing. In recent years, it seems that a lot of them stopped actually telling you what they're doing and instead give you a silly unrelated message (e.g. Panoramax would give me things like "Calculating Cornish sunshine", "Measuring the high tides", "Brewing tea", etc). Where/how did this trend start?

    Edit: Thanks for all the responses! It looks like this is much older than I originally thought. I played SimCity 2000 as a kid, but at that age, "reticulating splines" just sounded like normal computer jargon to me.

    A progress bar with the caption "Maturing cheddars"
    view more: next ›