from tkinter import * from R2Graph import * import math def main(): points = [] mouseButtons = [] objectIDs = [] triangleComputed = False bisectors = [] inCenter = R2Point(0., 0.) inRadius = 0. scaleX = 40.; scaleY = 40. root = Tk() root.title("Triangle") root.geometry("800x600") panel = Frame(root) drawButton = Button(panel, text="Draw") clearButton = Button(panel, text="Clear") drawArea = Canvas(root, bg="white") panel.pack(side=TOP, fill=X) drawButton.pack(side=LEFT, padx=4, pady=4) clearButton.pack(side=LEFT, padx=4, pady=4) drawArea.pack(side=TOP, fill=BOTH, expand=True, padx=4, pady=4) root.update() def map(t): w = drawArea.winfo_width() h = drawArea.winfo_height() centerX = w/2. centerY = h/2. x = centerX + t.x*scaleX y = centerY - t.y*scaleY return (x, y) def invmap(p): w = drawArea.winfo_width() h = drawArea.winfo_height() centerX = w/2. centerY = h/2. x = (p[0] - centerX)/scaleX y = (centerY - p[1])/scaleY return R2Point(x, y) def xMin(): w = drawArea.winfo_width() return (-(w/scaleX)/2.) def xMax(): return (-xMin()) def yMin(): w = drawArea.winfo_height() return (-(w/scaleY)/2.) def yMax(): return (-yMin()) def drawGrid(): ix0 = int(xMin()) ix1 = int(xMax()) x = ix0 while x <= ix1: if x != 0: p0 = map(R2Point(x, yMin())) p1 = map(R2Point(x, yMax())) drawArea.create_line(p0, p1, fill="lightGray", width=1) x += 1 iy0 = int(yMin()) iy1 = int(yMax()) y = iy0 while y <= iy1: if y != 0: p0 = map(R2Point(xMin(), y)) p1 = map(R2Point(xMax(), y)) drawArea.create_line(p0, p1, fill="lightGray", width=1) y += 1 # Draw x-axis drawArea.create_line( map(R2Point(xMin(), 0.)), map(R2Point(xMax(), 0.)), fill="black", width=2 ) # Draw y-axis drawArea.create_line( map(R2Point(0., yMin())), map(R2Point(0., yMax())), fill="black", width=2 ) def onMouseRelease(e): # print("Mouse release event:", e) p = (e.x, e.y) t = invmap(p) points.append(t) mouseButtons.append(e.num) drawPoint(t, e.num) def drawPoint(t, mouseButton = 1): vx = R2Vector(0.2, 0.) vy = R2Vector(0., 0.2) color = "red" if mouseButton == 2: color = "green" elif mouseButton == 3: color = "magenta" lineID = drawArea.create_line( map(t - vx), map(t + vx), fill=color, width=3 ) objectIDs.append(lineID) lineID = drawArea.create_line( map(t - vy), map(t + vy), fill=color, width=3 ) objectIDs.append(lineID) def drawPoints(): for i in range(len(points)): drawPoint(points[i], mouseButtons[i]) def onDraw(): if not triangleComputed and len(points) >= 3: computeTriangle() drawTriangle() def computeTriangle(): nonlocal triangleComputed, bisectors, inCenter, inRadius if len(points) < 3: triangleComputed = False return (inCenter, inRadius, bisectors) = computeInscribedCircle(points) triangleComputed = True def drawTriangle(): if len(points) < 3 or not triangleComputed: return # Draw a triangle path = [ map(points[0]), map(points[1]), map(points[2]), map(points[0]) ] lineID = drawArea.create_line(path, fill="blue", width=3) objectIDs.append(lineID) # Draw bisectors for i in range(3): lineID = drawArea.create_line( map(points[i]), map(bisectors[i]), fill="green", width=2 ) objectIDs.append(lineID) # Draw an inscribed circle rx = inCenter + R2Vector(inRadius, 0.) ry = inCenter + R2Vector(0., inRadius) leftTop = map(inCenter - rx + ry) bottomRight = map(inCenter + rx - ry) lineID = drawArea.create_oval( leftTop, bottomRight, fill=None, outline="red", width=2 ) objectIDs.append(lineID) # Draw a circle center pixelCenter = map(inCenter) lineID = drawArea.create_oval( pixelCenter[0] - 4, pixelCenter[1] - 4, pixelCenter[0] + 4, pixelCenter[1] + 4, fill="red", outline="black", width=1 ) objectIDs.append(lineID) def clearPicture(): for i in objectIDs: drawArea.delete(i) objectIDs.clear() def onClear(): nonlocal triangleComputed clearPicture() points.clear() mouseButtons.clear() triangleComputed = False def onConfigure(e): drawArea.delete("all") drawGrid() drawPoints() if triangleComputed: drawTriangle() drawButton.configure(command = onDraw) clearButton.configure(command = onClear) drawArea.bind("", onMouseRelease) drawArea.bind("", onMouseRelease) drawArea.bind("", onMouseRelease) drawArea.bind("", onConfigure) drawGrid() # plotFunction(func) root.mainloop() def computeInscribedCircle(points): assert(len(points) >= 3) bisectors = [] for i in range(3): inext = i + 1 if inext == 3: inext = 0 iprev = i - 1 if iprev == (-1): iprev = 2 vnext = points[inext] - points[i] vnext.normalize() vprev = points[iprev] - points[i] vprev.normalize() vbis = vnext + vprev (_, bis) = intersectLines( points[i], vbis, points[inext], points[iprev] - points[inext] ) bisectors.append(bis) (_, center) = intersectLines( points[0], bisectors[0] - points[0], points[1], bisectors[1] - points[1] ) radius = center.distanceToLine( points[0], points[1] - points[0] ) return (center, radius, bisectors) if __name__ == "__main__": main()