def _hyperbolic_arc_d(self, z0, z3, first=False): """ Function to construct Bezier path as an approximation to the hyperbolic arc between the complex numbers z0 and z3 in the hyperbolic plane. """ w0 = self._cayley_transform(z0) w3 = self._cayley_transform(z3) if w0.real()==0 and w3.real() == 0: y = (w0.imag() + w0.imag())/2 #self.path.append([(0,w0.imag()),CC(0,y), (0,w3.imag())]) self._graphics.add_primitive(BezierPath([(0,w0.imag()),CC(0,y), (0,w3.imag())],self._options)) return z0,z3 = CC(z0), CC(z3) if z0.imag() == 0 and z3.imag() == 0: p = (z0.real()+z3.real())/2 r = abs(z0-p) zm = CC(p, r) self._hyperbolic_arc_d(z0, zm, first) self._hyperbolic_arc_d(zm, z3) return else: p = (abs(z0)*abs(z0)-abs(z3)*abs(z3))/(z0-z3).real()/2 # center of the circle in H r = abs(z0-p) # radius of the circle in H zm = ((z0+z3)/2-p)/abs((z0+z3)/2-p)*r+p t = (8*zm-4*(z0+z3)).imag()/3/(z3-z0).real() z1 = z0 + t*CC(z0.imag(), (p-z0.real())) z2 = z3 - t*CC(z3.imag(), (p-z3.real())) zm = self._cayley_transform(zm) w1 = self._cayley_transform(z1) w2 = self._cayley_transform(z2) c = self._cayley_transform(CC(p,0)) # center of circle on the unit disk. r = abs(w1-c) # radius theta = t self._graphics.add_primitive(Arc((zm.real(),zm.imag()),r,sector=(-t,t),options=self._options))
def _geodesic_between_two_points_d(x1,y1,x2,y2,z0=I): r""" Geodesic path between two points represented in the unit disc by the map w = (z-I)/(z+I) INPUTS: - ''(x1,y1)'' -- starting point (0<y1<=infinity) - ''(x2,y2)'' -- ending point (0<y2<=infinity) - ''z0'' -- (default I) the point in the upper corresponding to the point 0 in the disc. I.e. the transform is w -> (z-I)/(z+I) OUTPUT: - ''ca'' -- a polygonal approximation of a circular arc centered at c and radius r, starting at t0 and ending at t1 EXAMPLES:: sage: l=_geodesic_between_two_points_d(0.1,0.2,0.0,0.5) """ pi=RR.pi() from sage.plot.plot import line from sage.functions.trig import (cos,sin) # First compute the points if(y1<0 or y2<0 ): raise ValueError,"Need points in the upper half-plane! Got y1=%s, y2=%s" %(y1,y2) if(y1==infinity): P1=CC(1 ) else: P1=CC((x1+I*y1-z0)/(x1+I*y1-z0.conjugate())) if(y2==infinity): P2=CC(1 ) else: P2=CC((x2+I*y2-z0)/(x2+I*y2-z0.conjugate())) # First find the endpoints of the completed geodesic in D if(x1==x2): a=CC((x1-z0)/(x1-z0.conjugate())) b=CC(1 ) else: c=RR(y1**2 -y2**2 +x1**2 -x2**2 )/RR(2 *(x1-x2)) r=RR(sqrt(y1**2 +(x1-c)**2 )) a=c-r b=c+r a=CC((a-z0)/(a-z0.conjugate())) b=CC((b-z0)/(b-z0.conjugate())) if( abs(a+b) < 1E-10 ): # On a diagonal return line([[P1.real(),P1.imag()],[P2.real(),P2.imag()]]) th_a=a.argument() th_b=b.argument() # Compute the center of the circle in the disc model if( min(abs(b-1 ),abs(b+1 ))< 1E-10 and min(abs(a-1 ),abs(a+1 ))>1E-10 ): c=b+I*(1 -b*cos(th_a))/sin(th_a) elif( min(abs(b-1 ),abs(b+1 ))> 1E-10 and min(abs(a-1 ),abs(a+1 ))<1E-10 ): c=a+I*(1 -a*cos(th_b))/RR(sin(th_b)) else: cx=(sin(th_b)-sin(th_a))/sin(th_b-th_a) c=cx+I*(1 -cx*cos(th_b))/RR(sin(th_b)) # First find the endpoints of the completed geodesic r=abs(c-a) t1=CC(P1-c).argument() t2=CC(P2-c).argument() #print "t1,t2=",t1,t2 return _circ_arc(t1,t2,c,r)
def _hyperbolic_arc_d(self, z0, z3, first=False): """ Function to construct Bezier path as an approximation to the hyperbolic arc between the complex numbers z0 and z3 in the hyperbolic plane. """ w0 = self._cayley_transform(z0) w3 = self._cayley_transform(z3) if self._verbose>0: print "in plane z0,z3=",z0,z3 print "in disc: ",w0,w3 npts = self._npts if z0 == infinity or z0==CC(infinity): zm = [z3 + CC(0,j+0.5) for j in range(npts-2)] wm = [self._cayley_transform(x) for x in zm] pts = [w3] pts.extend(wm) pts.append(w0) opt = self._options opt['fill']=False self._graphics.add_primitive(BezierPath([[(x.real(),x.imag()) for x in pts ]],opt)) return if z3 == infinity or z3==CC(infinity): zm = [z0 + CC(0,j+0.5) for j in range(npts-2)] wm = [self._cayley_transform(x) for x in zm] pts = [w0] pts.extend(wm) pts.append(w3) opt = self._options opt['fill']=False self._graphics.add_primitive(BezierPath([[(x.real(),x.imag()) for x in pts ]],opt)) #self._graphics.add_primitive(Line([w1.real(),w2.real()],[w1.imag(),w2.imag()],self._options)) #self.path.append([(0,w0.imag()),CC(0,y), (0,w3.imag())]) return x0=z0.real(); y0 = z0.imag() x3=z3.real(); y3 = z3.imag() if y0 == 0 and y3 == 0: p = (z0.real()+z3.real())/2 r = abs(z0-p) zm = CC(p, r) self._hyperbolic_arc_d(z0, zm, first) self._hyperbolic_arc_d(zm, z3) return else: if abs(x0-x3)<1e-10: ## on the same vertical line xmid = (x0+x3)*0.5; h = y3-y0 zm = [ CC(xmid,y0+t*h/(npts-1)) for t in range(npts) ] else: p = RR((x0+x3)*(x3-x0)+(y0+y3)*(y3-y0))/(2*(x3-x0)) r = RR((p - x0)**2 + y0**2).sqrt() # radius of the circle in H zm = ((z0+z3)/2-p)/abs((z0+z3)/2-p)*r+p # midpoint (at least approximately) of geodesic between z0 and z3 t0 = CC(z0 - p).argument() t3 = CC(z3 - p).argument() if self._verbose>1: print "x0,x3=",x0,x3 print "t0,t3=",t0,t3 print "r=",r print "opt=",self._options if x0 <= x3: zm = [p + r*CC(0,(t0+t*(t3-t0)/(npts-1))).exp() for t in range(npts)] else: zm = [p + r*CC(0,(t0+t*(t3-t0)/(npts-1))).exp() for t in range(npts)] #print "zm=",zm #zm.insert(0,z0) #zm.append(z3) pts = [self._cayley_transform(x) for x in zm] opt = self._options opt['fill']=False #w0 = self._cayley_transform(z0) #w3 = self._cayley_transform(z3) if self._verbose>2: print "pts=",pts self._graphics.add_primitive(BezierPath([[(x.real(),x.imag()) for x in pts ]],opt)) return #print "z0_test=",(p+r*exp(t0*I)) #print "z3_test=",(p+r*exp(t3*I)) #t = (8*zm-4*(z0+z3)).imag()/3/(z3-z0).real() # I have no idea what these points should represent.... #z1 = z0 + t*CC(z0.imag(), (p-z0.real())) #z2 = z3 - t*CC(z3.imag(), (p-z3.real())) wm = [self._cayley_transform(x) for x in zm] pp = self._cayley_transform(CC(p,0)) w1 = self._cayley_transform(z0) w2 = self._cayley_transform(z3) c = self._cayley_transform(CC(p,0)) # center of circle on the unit disk. if self._verbose>2: print "p,r=",p,r print "zm=",zm #print "t=",t #print "tt=",(8*zm-4*(z0+z3)).imag()/3/(z3-z0).real() print "C(c)=",pp print "C(zm)=",wm print "C(z0)=",w1 print "C(z3)=",w2 #print "z2=",z2 r = abs(w1-c) # radius t0 = CC(w0 - pp).argument() t3 = CC(w3 - pp).argument() t = abs(t0-t3) if self._verbose>0: print "adding a:rc ",zm.real(),zm.imag(),r,r,t,t0,t3 self._graphics.add_primitive(Line([w1.real(),w2.real(),wm.real()],[w1.imag(),w2.imag(),wm.imag()],{'thickness':2,'alpha':1, 'rgbcolor':'blue', 'legend_label':""})) self._graphics.add_primitive(Point([w1.real(),w2.real(),wm.real()],[w1.imag(),w2.imag(),wm.imag()],{'size':10,'alpha':1, 'faceted':True, 'rgbcolor':'red', 'legend_label':""}))
def _geodesic_between_two_points_d(x1, y1, x2, y2, z0=I): r""" Geodesic path between two points represented in the unit disc by the map w = (z-I)/(z+I) INPUTS: - ''(x1,y1)'' -- starting point (0<y1<=infinity) - ''(x2,y2)'' -- ending point (0<y2<=infinity) - ''z0'' -- (default I) the point in the upper corresponding to the point 0 in the disc. I.e. the transform is w -> (z-I)/(z+I) OUTPUT: - ''ca'' -- a polygonal approximation of a circular arc centered at c and radius r, starting at t0 and ending at t1 EXAMPLES:: sage: l=_geodesic_between_two_points_d(0.1,0.2,0.0,0.5) """ pi = RR.pi() from sage.plot.plot import line from sage.functions.trig import (cos, sin) # First compute the points if (y1 < 0 or y2 < 0): raise ValueError, "Need points in the upper half-plane! Got y1=%s, y2=%s" % ( y1, y2) if (y1 == infinity): P1 = CC(1) else: P1 = CC((x1 + I * y1 - z0) / (x1 + I * y1 - z0.conjugate())) if (y2 == infinity): P2 = CC(1) else: P2 = CC((x2 + I * y2 - z0) / (x2 + I * y2 - z0.conjugate())) # First find the endpoints of the completed geodesic in D if (x1 == x2): a = CC((x1 - z0) / (x1 - z0.conjugate())) b = CC(1) else: c = RR(y1**2 - y2**2 + x1**2 - x2**2) / RR(2 * (x1 - x2)) r = RR(sqrt(y1**2 + (x1 - c)**2)) a = c - r b = c + r a = CC((a - z0) / (a - z0.conjugate())) b = CC((b - z0) / (b - z0.conjugate())) if (abs(a + b) < 1E-10): # On a diagonal return line([[P1.real(), P1.imag()], [P2.real(), P2.imag()]]) th_a = a.argument() th_b = b.argument() # Compute the center of the circle in the disc model if (min(abs(b - 1), abs(b + 1)) < 1E-10 and min(abs(a - 1), abs(a + 1)) > 1E-10): c = b + I * (1 - b * cos(th_a)) / sin(th_a) elif (min(abs(b - 1), abs(b + 1)) > 1E-10 and min(abs(a - 1), abs(a + 1)) < 1E-10): c = a + I * (1 - a * cos(th_b)) / RR(sin(th_b)) else: cx = (sin(th_b) - sin(th_a)) / sin(th_b - th_a) c = cx + I * (1 - cx * cos(th_b)) / RR(sin(th_b)) # First find the endpoints of the completed geodesic r = abs(c - a) t1 = CC(P1 - c).argument() t2 = CC(P2 - c).argument() #print "t1,t2=",t1,t2 return _circ_arc(t1, t2, c, r)
def _hyperbolic_arc_d(self, z0, z3, first=False): """ Function to construct Bezier path as an approximation to the hyperbolic arc between the complex numbers z0 and z3 in the hyperbolic plane. """ w0 = self._cayley_transform(z0) w3 = self._cayley_transform(z3) if self._verbose > 0: print "in plane z0,z3=", z0, z3 print "in disc: ", w0, w3 npts = self._npts if z0 == infinity or z0 == CC(infinity): zm = [z3 + CC(0, j + 0.5) for j in range(npts - 2)] wm = [self._cayley_transform(x) for x in zm] pts = [w3] pts.extend(wm) pts.append(w0) opt = self._options opt['fill'] = False self._graphics.add_primitive( BezierPath([[(x.real(), x.imag()) for x in pts]], opt)) return if z3 == infinity or z3 == CC(infinity): zm = [z0 + CC(0, j + 0.5) for j in range(npts - 2)] wm = [self._cayley_transform(x) for x in zm] pts = [w0] pts.extend(wm) pts.append(w3) opt = self._options opt['fill'] = False self._graphics.add_primitive( BezierPath([[(x.real(), x.imag()) for x in pts]], opt)) #self._graphics.add_primitive(Line([w1.real(),w2.real()],[w1.imag(),w2.imag()],self._options)) #self.path.append([(0,w0.imag()),CC(0,y), (0,w3.imag())]) return x0 = z0.real() y0 = z0.imag() x3 = z3.real() y3 = z3.imag() if y0 == 0 and y3 == 0: p = (z0.real() + z3.real()) / 2 r = abs(z0 - p) zm = CC(p, r) self._hyperbolic_arc_d(z0, zm, first) self._hyperbolic_arc_d(zm, z3) return else: if abs(x0 - x3) < 1e-10: ## on the same vertical line xmid = (x0 + x3) * 0.5 h = y3 - y0 zm = [CC(xmid, y0 + t * h / (npts - 1)) for t in range(npts)] else: p = RR((x0 + x3) * (x3 - x0) + (y0 + y3) * (y3 - y0)) / (2 * (x3 - x0)) r = RR((p - x0)**2 + y0**2).sqrt() # radius of the circle in H zm = ((z0 + z3) / 2 - p) / abs( (z0 + z3) / 2 - p ) * r + p # midpoint (at least approximately) of geodesic between z0 and z3 t0 = CC(z0 - p).argument() t3 = CC(z3 - p).argument() if self._verbose > 1: print "x0,x3=", x0, x3 print "t0,t3=", t0, t3 print "r=", r print "opt=", self._options if x0 <= x3: zm = [ p + r * CC(0, (t0 + t * (t3 - t0) / (npts - 1))).exp() for t in range(npts) ] else: zm = [ p + r * CC(0, (t0 + t * (t3 - t0) / (npts - 1))).exp() for t in range(npts) ] #print "zm=",zm #zm.insert(0,z0) #zm.append(z3) pts = [self._cayley_transform(x) for x in zm] opt = self._options opt['fill'] = False #w0 = self._cayley_transform(z0) #w3 = self._cayley_transform(z3) if self._verbose > 2: print "pts=", pts self._graphics.add_primitive( BezierPath([[(x.real(), x.imag()) for x in pts]], opt)) return #print "z0_test=",(p+r*exp(t0*I)) #print "z3_test=",(p+r*exp(t3*I)) #t = (8*zm-4*(z0+z3)).imag()/3/(z3-z0).real() # I have no idea what these points should represent.... #z1 = z0 + t*CC(z0.imag(), (p-z0.real())) #z2 = z3 - t*CC(z3.imag(), (p-z3.real())) wm = [self._cayley_transform(x) for x in zm] pp = self._cayley_transform(CC(p, 0)) w1 = self._cayley_transform(z0) w2 = self._cayley_transform(z3) c = self._cayley_transform(CC( p, 0)) # center of circle on the unit disk. if self._verbose > 2: print "p,r=", p, r print "zm=", zm #print "t=",t #print "tt=",(8*zm-4*(z0+z3)).imag()/3/(z3-z0).real() print "C(c)=", pp print "C(zm)=", wm print "C(z0)=", w1 print "C(z3)=", w2 #print "z2=",z2 r = abs(w1 - c) # radius t0 = CC(w0 - pp).argument() t3 = CC(w3 - pp).argument() t = abs(t0 - t3) if self._verbose > 0: print "adding a:rc ", zm.real(), zm.imag(), r, r, t, t0, t3 self._graphics.add_primitive( Line([w1.real(), w2.real(), wm.real()], [w1.imag(), w2.imag(), wm.imag()], { 'thickness': 2, 'alpha': 1, 'rgbcolor': 'blue', 'legend_label': "" })) self._graphics.add_primitive( Point( [w1.real(), w2.real(), wm.real()], [w1.imag(), w2.imag(), wm.imag()], { 'size': 10, 'alpha': 1, 'faceted': True, 'rgbcolor': 'red', 'legend_label': "" }))