Stereographic Projection - Hint #2

Still Under Construction and Testing

#!/usr/bin/python3 # ==================================================================== # intersection of a line and plane (code found on the web) # ==================================================================== import numpy as np import graphics as gr import coordinate_conversion as cc import sys # -------------------------------------------------------------------- # calculate the intersection # -------------------------------------------------------------------- def intersect_line_plane(line_point,line_direction, plane_point,plane_normal): line_point = np.array(line_point) line_direction = np.array(line_direction) plane_point = np.array(plane_point) plane_normal = np.array(plane_normal) dot_product_direction_normal = np.dot(line_direction,plane_normal) if dot_product_direction_normal == 0: # Line is parallel to the plane if np.dot(line_point-plane_point,plane_normal) == 0: return "Line lies in the plane (infinite intersections)" else: return "Line is parallel to the plane and does not intersect" else: # Unique intersection point t = -np.dot(line_point-plane_point,plane_normal)/ \ dot_product_direction_normal intersection_point = line_point + (t * line_direction) return intersection_point # -------------------------------------------------------------------- # ---- create a graphics window (window coordinates) # -------------------------------------------------------------------- def create_a_graphics_window(width:int, height:int, d3axes:bool=False, planeoutline:bool=False, origin_offset:tuple=(0,0), title:str=None) -> gr.GraphWin: ''' Create graphics window and maybe 3D Cartesian axes. All calculations are window coordinates and based on the graphics window's height and width. Window Coordinates Cartesian Coordinates (0,0) +Y *---------- +X | | | | | | |(0,0,0) | *---------- +X +Y / / +Z Note: The viewer is assumed to be on the Z axis at +infinity. (There is no perspective size change due to an object's distance from the viewer.) ''' # ---- create a graphics window win = gr.GraphWin(title,width,height) win.setBackground("white") # ---- draw 3D axes? if d3axes: # ---- center of graphics window (origin - 0,0) # ---- (in window coordinates) xorigin = round(width/2.0) yorigin = round(height/2.0) # ---- length of X,Y,Z axis lines # ---- (in window coordinates) x_axis_length = round(xorigin/2.0) y_axis_length = round(yorigin/2.0) z_axis_length = round((x_axis_length+y_axis_length)/4.0) # ---- origin's offset from the center of window # ---- (in window coordinates) xoffset = origin_offset[0] yoffset = origin_offset[1] xo = xorigin + xoffset # orgin X + offset yo = yorigin + yoffset # orgin Y + offset # ---- draw X axis (line) ##xl = gr.Line(gr.Point(xo,yo), ## gr.Point(xo-1+x_axis_length,yo)) xl = gr.Line(gr.Point(xo-1-x_axis_length,yo), gr.Point(xo-1+x_axis_length,yo)) xl.setWidth(2) xl.setFill("black") xl.draw(win) t = gr.Text(gr.Point(xo-1+x_axis_length+10,yo),' +X') t.setFace("courier") t.setSize(12) t.setTextColor("black") t.draw(win) # ---- draw Y axis (line) ##yl = gr.Line(gr.Point(xo,yo), ## gr.Point(xo,yo+1-y_axis_length)) yl = gr.Line(gr.Point(xo,yo+1+y_axis_length), gr.Point(xo,yo+1-y_axis_length)) yl.setWidth(2) yl.setFill("black") yl.draw(win) t = gr.Text(gr.Point(xo,yo+1-y_axis_length-10),'+Y') t.setTextColor("black") t.setFace("courier") t.setSize(12) t.draw(win) # ---- draw Z axis (line) zl = gr.Line(gr.Point(xo,yo), gr.Point(1-z_axis_length+xo+5, z_axis_length+yo-1+5)) ##zl = gr.Line(gr.Point(1-z_axis_length+xo,yo, ## z_axis_length-yo-1), ## gr.Point(1-z_axis_length+xo, ## z_axis_length+yo-1)) zl.setWidth(2) zl.setFill("black") zl.draw(win) t = gr.Text(gr.Point(1-z_axis_length+xo-5, z_axis_length+yo+15),'+Z') t.setTextColor("black") t.setFace("courier") t.setSize(12) t.draw(win) # ---- draw an outline of the plane if planeoutline: ulx = 1 + xo - z_axis_length # upper left X uly = -1 + yo - z_axis_length # upper left Y lrx = 1 + xo + z_axis_length # lower left X lry = -1 + yo + z_axis_length # lower left Y print() print('plane coordinates') print(f'upper left X,Y = {ulx:.3f},{uly:.3f}') print(f'lower right X,y = {lrx:.3f},{lry:.3f}') c = gr.Circle(gr.Point(ulx,uly),4) c.setFill('blue') c.draw(win) ##ol = gr.Line(gr.Point(ulx,uly),gr.Point(ulx,lry)) ##ol.setWidth(1) ##ol.setFill("black") ##ol.draw(win) return (win,xoffset,yoffset) # -------------------------------------------------------------- # ---- draw a 3D point (on 2D plane) # ---- Note: origin offset X,Y are window coordinates # -------------------------------------------------------------- def draw_a_point(win:gr.GraphWin, pt:tuple, radius=4, point_color:str='black', origin_offset:tuple=(0,0)) -> None: ''' draw a point Note: a 3D point is a tuple (x,y,z) but window coordinates X,Y (Z=0) are used to draw a point (circle) ''' x = pt[0] # Cartesian coord y = pt[1] # Cartesian coord # ---- convert point Cartesian coords to window coords wx1,wy1 = cc.center_to_win_coords(x,y, win.width,win.height) # ---- draw a point (small circle) wxo1 = wx1 + origin_offset[0] wyo1 = wy1 + origin_offset[1] c = gr.Circle(gr.Point(wxo1,wyo1),radius) c.setFill(point_color) if radius > 10: c.setOutline("black") c.setWidth(2) c.draw(win) return # -------------------------------------------------------------- # ---- draw a line between two 3D points (on a 2D plane) # ---- Note: origin offsets are window coordinates # -------------------------------------------------------------- def draw_a_line(win:gr.GraphWin, pt1:tuple, pt2:tuple, line_color:str='black', origin_offset:tuple=(0,0)) -> None: ''' draw a line between two points Note: a 3D point is a tuple (x,y,z) but window coordinates X,Y (Z=0) are used to draw a line ''' # ---- convert point #1 Cartesian coords to window coords x = pt1[0] # Cartesian coord y = pt1[1] # Cartesian coord wx1,wy1 = cc.center_to_win_coords(x,y, win.width,win.height) # ---- convert point #2 Cartesian coords to window coords x = pt2[0] # Cartesian coord y = pt2[1] # Cartesian coord wx2,wy2 = cc.center_to_win_coords(x,y, win.width,win.height) # ---- draw a line l = gr.Line(gr.Point(wx1,wy1),gr.Point(wx2,wy2)) l.setWidth(3) l.setFill(line_color) l.draw(win) return # -------------------------------------------------------------------- # ---- main # -------------------------------------------------------------------- if __name__ == '__main__': # ---- example 1 #line_pt = [200, 0, 200] #line_dir = [0, 100, 0] #plane_pt = [0, 0, 0] #plane_norm = [0, 100, 0] # ---- example 2 #line_pt = [0, 100, 0] #line_dir = [100, 100, 100] #plane_pt = [ 0, 0, 0] #plane_norm = [ 0, 100, 0] # ---- example 3 line_pt = [200, 200, 200] line_dir = [200, 200, 0] plane_pt = [ 0, 0, 100] plane_norm = [100, 100, 0] # line is (200,200,100),(400,400,200) # ---- create graphics window and draw axes win,x_offset,y_offset = create_a_graphics_window(801,801, d3axes=True, planeoutline=True, title='Line/Plane Intersection Test') print() print('Window X,Y offset') print(f'x offset = {x_offset:.3f}') print(f'y offset = {y_offset:.3f}') # ---- calculate line/plane intersection coordinates intersection = intersect_line_plane(line_pt,line_dir, plane_pt,plane_norm) print() print('intersection in Cartesian coordinates') print(f'x = {intersection[0]:.3f}') print(f'y = {intersection[1]:.3f}') print(f'z = {intersection[2]:.3f}') # ---- draw line/plane intersection point draw_a_point(win,(intersection[0],intersection[1]), point_color='red') # ---- draw line (segment) draw_a_line(win,(200,200,100),(400,400,200), line_color='green') # ---------------------------------------------------------------- # ---- wait for a mouse click in the window, then exit print() click = win.getMouse() win.close() sys.exit()