Benutzer:Alva2004/Programme/Matfunc2d

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen
#!/usr/bin/python3
'geometrie in der komplexen zahlenebene'
from random import uniform
import cmath
cum = [ 0,0 ]
i   = complex( 0,1 )
fp  = 0
floatfmt = '%1.4f' # format fuer reelle zahlen
#==============================================================================
def realpart( z ):
    'fuer wxmaxima'
    return z.real
#==============================================================================
def imagpart( z ):
    'fuer wxmaxima'
    return z.imag
#==============================================================================
def u( x=1,y='' ):
    if not isinstance( y, str ):
        ans = uniform( x,y )
    else:
        ans = uniform( -x,x )
    return ans
#==============================================================================
class Zahl:
    #--------------------------------------------------------------------------
    def isNumber( self, x ):
        return ( isinstance( x, complex ) or isinstance( x, float )
                 or isinstance( x, int ) )
    #--------------------------------------------------------------------------
#==============================================================================
class Punkt( Zahl ):
    #--------------------------------------------------------------------------
    def __init__( self, x, y=0 ):
        if isinstance( x, Punkt ):
            self.z0 = x.z0
        else:
            self.z0 = complex( x,y )
        self.real = self.z0.real
        self.imag = self.z0.imag
    #--------------------------------------------------------------------------
    def spiegel( p, obj ):
        'punktspiegelung'
        if p.isNumber( obj ):
            obj = Punkt( obj )
        p2 = p + p
        if isinstance( obj, Punkt ):
            ans = p2 - obj # p + ( p - obj )
        elif isinstance( obj, Kreis ):
            ans = Kreis( p2 - obj.z0, obj.r )
        elif isinstance( obj, Gerade ):
            ans = Gerade( p2 - obj.z0, p2 - obj.z1 )
        elif isinstance( obj, Dreieck ):
            ans = Dreieck( p2 - obj.z0, p2 - obj.z1, p2 - obj.z2 )
        elif hasattr( obj, '__len__' ): # liste
            ans = [ p.spiegel( q ) for q in obj ]
        else:
            raise NotImplementedError( 'Punktspiegelung fuer %s'%type( obj )
                                       + 'nicht implementiert' )
        return ans
    #--------------------------------------------------------------------------
    def normalize( self ):
        r = abs( self )
        return Punkt( self.real/r, self.imag/r )
    #--------------------------------------------------------------------------
    def outer( u,v ):
        'u=(a,b), v=(c,d) -> ( ( a*c, a*d ), ( b*c, b*d ) )'
        return Matrix( u.z0.real*v, u.z0.imag*v )
    #--------------------------------------------------------------------------
    def angle( self, b ):
        'gibt den winkel zwischen diesen "vektoren"'
        if self.isNumber( b ):
            b = complex( b )
        elif isinstance( b, Punkt ):
            b = b.z0
        return cmath.phase( b/self.z0 )
    #--------------------------------------------------------------------------
    def dot( a, b ):
        'a.real*b.real + a.imag*b.imag'
        return ( a.conjugate()*b ).real
    #--------------------------------------------------------------------------
    def cross( a, b ):
        '( a x b ).ez = ax*by - ay*bx'
        return ( a.conjugate()*b ).imag
    #--------------------------------------------------------------------------
    def dist( a, b ):
        'abstand'
        return abs( a - b )
    #--------------------------------------------------------------------------
    def p2t( self ):
        'gibt tuple'
        return ( self.real, self.imag )
    #--------------------------------------------------------------------------
    def toVec( self ):
        'gibt mf.Vec'
        return mf.Vec( [ self.real, self.imag ] )
    #--------------------------------------------------------------------------
    def toNpVec( self ):
        'gibt nf.Vec'
        return nf.Vec( [ self.real, self.imag ] )
    #--------------------------------------------------------------------------
    def conjugate( self ):
        return Punkt( self.z0.conjugate() )
    #--------------------------------------------------------------------------
    def __str__( self ):
        'self.z0'
        fmt = 'Punkt( %s,%s )'%( floatfmt, floatfmt )
        return fmt%( self.real, self.imag )
    #--------------------------------------------------------------------------
    def __neg__( self ):
        '-self'
        return Punkt( -self.z0 )
    #--------------------------------------------------------------------------
    def __abs__( self ):
        'abs( self )'
        return abs( self.z0 )
    #--------------------------------------------------------------------------
    def __eq__( a,b ):
        'a==b'
        ans = 0
        if isinstance( b, Punkt ):
            ans = a.z0 == b.z0
        else:
            ans = a.z0 == b
        return ans
    #--------------------------------------------------------------------------
    def __add__( self, z ):
        'self + z'
        if isinstance( z, Punkt ):
            ans = Punkt( self.z0 + z.z0 )
        else:
            ans = Punkt( self.z0 + z )
        return ans
    #--------------------------------------------------------------------------
    def __sub__( self, z ):
        'self - z'
        return self + ( -z )
    #--------------------------------------------------------------------------
    def __mul__( self, z ):
        'self*z'
        if isinstance( z, Punkt ):
            ans = Punkt( self.z0*z.z0 )
        else:
            ans = Punkt( self.z0*z )
        return ans
    #--------------------------------------------------------------------------
    def __div__( self, z ):
        print( 'self//z' )
        return self.__truediv__( z )
    #--------------------------------------------------------------------------
    def __truediv__( self, z ):
        'self/z'
        if isinstance( z, Punkt ):
            ans = Punkt( self.z0/z.z0 )
        else:
            ans = Punkt( self.z0/z )
        return ans
    #--------------------------------------------------------------------------
    def __pow__( self, z ):
        'self**z'
        if isinstance( z, Punkt ):
            ans = Punkt( self.z0**z.z0 )
        else:
            ans = Punkt( self.z0**z )
        return ans
    #--------------------------------------------------------------------------
    def __radd__( self, z ):
        'z + self'
        return self + z
    #--------------------------------------------------------------------------
    def __rsub__( self, z ):
        'z - self'
        return -( self - z )
    #--------------------------------------------------------------------------
    def __rmul__( self, z ):
        'z*self'
        return self*z
    #--------------------------------------------------------------------------
    def __rdiv__( self, z ):
        'z/self'
        return self.__rtruediv__( z )
    #--------------------------------------------------------------------------
    def __rtruediv__( self, z ):
        'z/self'
        if isinstance( z, Punkt ):
            ans = Punkt( z.z0/self.z0 )
        else:
            ans = Punkt( z/self.z0 )
        return ans
    #--------------------------------------------------------------------------
#==============================================================================
class Matrix( Zahl ):
    '''zwei komplexe zahlen als 2x2 matrix.
    ( z0.real z0.imag )
    ( z1.real z1.imag )
    eigensystem nur fuer symmetrische matrizen moeglich.
    '''
    #--------------------------------------------------------------------------
    def __init__( self, a, b=0 ):
        if isinstance( a, Punkt ) or self.isNumber( a ):
            self.z0 = Punkt( a )
            self.z1 = Punkt( b )
        elif isinstance( a, Matrix ): # kopie
            self.z0 = Punkt( a.z0 )
            self.z1 = Punkt( a.z1 ) # c+i*d
    #--------------------------------------------------------------------------
    def sym( self ):
        'symmetrischer anteil'
        s  = 0.5*( self.z0.imag + self.z1.real )
        return Matrix( Punkt( self.z0.real, s ), Punkt( s, self.z1.imag ) )
    #--------------------------------------------------------------------------
    def inv( self ):
        'inverse'
        d = i/self.det()
        return Matrix( -d*self.z1, d*self.z0 ).tr()
    #--------------------------------------------------------------------------
    def mmul( self, M ):
        'matrizenprodukt'
        if isinstance( M, Matrix ):
            # self.z0=a+i*b=r, self.z1=c+i*d=s, M.z0=e+i*g=u, M.z1=f+i*h=v
            N   = M.tr()
            ans = Matrix( Punkt( self.z0.dot( N.z0 ),
                                 self.z0.dot( N.z1 ) ),
                          Punkt( self.z1.dot( N.z0 ),
                                 self.z1.dot( N.z1 ) ) )
        elif isinstance( M, Punkt ):
            ans = Punkt( self.z0.dot( M ), self.z1.dot( M ) )
        else:
            raise NotImplementedError( 'mmul fuer Matrix %s not implemented'%
                                       type( M ) )
        return ans
    #--------------------------------------------------------------------------
    def eig(self):
        '''eigensystem ( ew, ev )
        | a b |(u)=(a*u+b*v)=l*(u) -> b*v = (l-a)*u
        | c d |(v) (c*u+d*v)   (v) -> c*u = (l-d)*v
        0 = l**2 - sp*l + det = l**2 - sp*l + 0.25*sp**2 - 0.25*sp**2 + det
        ( l - 0.5*sp )**2 = 0.25*sp**2 - det
        '''
        ( sp, det ) = ( self.spur(), self.det() )
        if 0.25*sp**2 < det:
            raise ValueError( 'eig nur fuer symmetrische matrizen moeglich' )
        w  = cmath.sqrt( 0.25*sp**2 - det ).real
        ( l1, l2 ) = ew = ( 0.5*sp + w, 0.5*sp - w )
        ev = []
        ( a, b, c, d ) = ( self.z0.real, self.z0.imag,
                           self.z1.real, self.z1.imag )
        for l in ( l1, l2 ):
            if abs( b ) > abs( c ):
                ev.append( Punkt( b, l - a ).normalize() )
            else:
                ev.append( Punkt( l - d, c ).normalize() )
        return ( ew, ev )
    #--------------------------------------------------------------------------
    def tr( self ):
        'transponierte'
        return Matrix( Punkt( self.z0.real, self.z1.real ),
                       Punkt( self.z0.imag, self.z1.imag ) )
    #--------------------------------------------------------------------------
    def spur( self ):
        'spur'
        return self.z0.real + self.z1.imag
    #--------------------------------------------------------------------------
    def det( self ):
        'determinante'
        return self.z0.cross( self.z1 )
    #--------------------------------------------------------------------------
    def toSquare( self ):
        'gibt mf.Vec'
        return mf.Square( [ self.z0.toVec(), self.z1.toVec() ] )
    #--------------------------------------------------------------------------
    def toNpTensor( self ):
        'gibt nf.Vec'
        return nf.Tensor( [ self.z0.toNpVec(), self.z1.toNpVec() ] )
    #--------------------------------------------------------------------------
    def __str__( self ):
        'self.z0,b'
        fmt = 'Matrix( [ [ %s,%s ], [ %s,%s ] ] )'%tuple( 4*[ floatfmt ] )
        return fmt%( self.z0.real, self.z0.imag, self.z1.real, self.z1.imag )
    #--------------------------------------------------------------------------
    def __neg__( self ):
        '-self'
        return Matrix( -self.z0, -self.z1 )
    #--------------------------------------------------------------------------
    def __eq__( a,b ):
        'a==b'
        ans = 0
        if isinstance( b, Matrix ):
            ans = a.z0 == b.z0 and a.z1 == b.z1
        return ans
    #--------------------------------------------------------------------------
    def __add__( a, b ):
        'a + b'
        return Matrix( a.z0 + b.z0, a.z1 + b.z1 )
    #--------------------------------------------------------------------------
    def __sub__( a, b ):
        'a - b'
        return Matrix( a.z0 - b.z0, a.z1 - b.z1 )
    #--------------------------------------------------------------------------
    def __mul__( a, b ):
        'a*b'
        return Matrix( b*a.z0, b*a.z1 )
    #--------------------------------------------------------------------------
    def __div__( a, b ):
        'a/b'
        return self*( 1./z )
    #--------------------------------------------------------------------------
    def __rmul__( a, b ):
        'b*a'
        return a*b
    #--------------------------------------------------------------------------
#==============================================================================
class Eye( Matrix ):
    'einheitsmatrix'
    #--------------------------------------------------------------------------
    def __init__( self ):
        Matrix.__init__( self, Punkt( 1,0 ), Punkt( 0,1 ) )
    #--------------------------------------------------------------------------
#==============================================================================
class Geometrie( Zahl ):
    'geometrisches objekt mit einem referenzpunkt z0'
    #--------------------------------------------------------------------------
    def __init__( self, z0 ):
        self.z0 = Punkt( z0 )
    #--------------------------------------------------------------------------
#==============================================================================
class Gerade( Geometrie ):
    'berechnungen mit geraden'
    #--------------------------------------------------------------------------
    def __init__( self, a, b, *punkte ):
        if len( punkte ) > 0:
            g = self.regression( [ a, b ] + list( punkte ) )
            ( a,b ) = ( g.z0, g.z1 )
            self.e  = g.e
        else:
            self.e  = ( a - b )/abs( a - b )
        Geometrie.__init__( self, a )
        self.z1 = Punkt( b )
    #--------------------------------------------------------------------------
    def copy( g ):
        'gibt eine kopie dieser geraden'
        return Gerade( self.z0, self.z1 )
    #--------------------------------------------------------------------------
    def regression( self, p ):
        'regression durch mehr als 2 punkte in 2d'
        # minimiert sum( [ |e.cross( pj - s )|**2 for pj in p ] )
        # siehe /home/austausch/doku/wissen/mathe/regression
        o = Punkt( 0 )
        O = o.outer( o )
        p = [ Punkt( pj ) for pj in p ]
        N = len( p )
        sump = sum( p, o )
        sumd = sum( [ pj.dot( pj ) for pj in p ] )
        sumo = sum( [ pj.outer( pj ) for pj in p ], O )
        s    = sump/N
        T    = sumd*Eye() - sumo + sump.outer( s )
        ( ew, ev ) = T.eig()
        n = ev[ 0 ]
        if ew[ 1 ] < ew[ 0 ]:
            n = ev[ 1 ]
        return Gerade( s, s+n )
    #--------------------------------------------------------------------------
    def trimm( g, a=0, b='' ):
        'trimmt diese gerade auf den abschnitt z0-a:z0+b'
        if isinstance( b, str ):
            b = a
        ( g.z0, g.z1 ) = ( g.z0 - a*g.e, g.z0 + b*g.e )
    #--------------------------------------------------------------------------
    def fussPunkt( g, p ):
        """projiziert p auf g
        p = g.z0 + z*g.e -> z = ( p - g.z0 )/g.e = a + i*b -> p' = g.z0 + a*g.e
        """
        z = ( p - g.z0 )/g.e
        return Punkt( g.z0 + z.real*g.e )
    #--------------------------------------------------------------------------
    def schnittPunkt( a, b ):
        'gibt den schnittpunkt der geraden a und b'
        ans = []
        q   = a.e.cross( b.e )
        if q != 0: # nicht parallel
            ans = [ Punkt( a.z0 + b.e.cross( a.z0 - b.z0 )/q*a.e ) ]
        return ans
    #--------------------------------------------------------------------------
    def dist( g, z=0 ):
        'Berechnet den Abstand von z zu dieser Geraden'
        return abs( g.e.cross( z - g.z0 ) )
    #--------------------------------------------------------------------------
    def angle( a, b ):
        'gibt den winkel zwischen diesen geraden'
        return a.e.angle( b.e )
    #--------------------------------------------------------------------------
    def winkelhalbierenden( self, b ):
        'gibt die winkelhalbierenden der geraden a und b'
        z = self.schnittPunkt( b )[ 0 ]
        g = Gerade( z, Punkt( z + self.e + b.e ) )
        return ( g, g.senkrechteDurch( z ) )
    #--------------------------------------------------------------------------
    def paralleleDurch( self, p ):
        'gibt die parallele zu dieser geraden durch p'
        return Gerade( p, p + self.e )
    #--------------------------------------------------------------------------
    def senkrechteDurch( self, p ):
        'gibt die senkrechte zu dieser geraden durch p'
        return Gerade( p, p + i*self.e )
    #--------------------------------------------------------------------------
    def spiegel( g, obj ):
        'geradenspiegelung an dieser geraden'
        if g.isNumber( obj ):
            obj = Punkt( obj )
        if isinstance( obj, Punkt ):
            # obj = g.z0 + a*g.e + b*i*g.e = g.z0 + (a+i*b)*g.e->
            ans = g.z0 + ( obj - g.z0 ).conjugate()*g.e**2
        elif isinstance( obj, Gerade ):
            ans = Gerade( g.spiegel( obj.z0 ), g.spiegel( obj.z1 ) )
        elif isinstance( obj, Kreis ):
            ans = Kreis( g.spiegel( obj.z0 ), obj.r )
        elif isinstance( obj, Dreieck ):
            ans = Dreieck( g.spiegel( obj.z0 ), g.spiegel( obj.z1 ),
                           g.spiegel( obj.z2 ) )
        elif hasattr( obj, '__len__' ): # liste
            ans = [ g.spiegel( p ) for p in obj ]
        else:
            raise NotImplementedError( 'Geradenspiegelung fuer %s'%type( obj )
                                       + 'nicht implementiert' )
        #print( 'spiegel %s -> %s'%( obj, ans ) )
        return ans
    #--------------------------------------------------------------------------
    def __str__( self ):
        fmt = 'Gerade( ( %s,%s ), ( %s,%s ) )'%tuple( 4*[ floatfmt ] )
        return fmt%( self.z0.real, self.z0.imag,
                     ( self.z0+self.e ).real, ( self.z0+self.e ).imag )
    #--------------------------------------------------------------------------
#==============================================================================
class Dreieck( Geometrie ):
    'Berechnungen eines Dreiecks'
    #--------------------------------------------------------------------------
    def __init__( self, z0, z1, z2 ):
        Geometrie.__init__( self, z0 )
        self.z1 = Punkt( z1 )
        self.z2 = Punkt( z2 )
    #--------------------------------------------------------------------------
    def inhalt( d ):
        'gibt den flaecheninhalt'
        return 0.5*abs( ( d.z1 - d.z0 ).cross( d.z2 - d.z1 ) )
    #--------------------------------------------------------------------------
    def umkreis( self ):
        'gibt den Umkreis dieses Dreiecks'
        ( A, B, C ) = ( self.z0, self.z1, self.z2 )
        ( a,b,c ) = [ X.dot( X ) for X in ( A, B, C ) ]
        d = 2*( A.cross( B ) + B.cross( C ) + C.cross( A ) )
        m = i/d*( ( b - c )*A + ( c - a )*B + ( a - b )*C )
        r = abs( A - m )
        return Kreis( m,r )
    #--------------------------------------------------------------------------
    def inkreis( self ):
        'gibt den Inkreis dieses Dreiecks'
        ( A, B, C ) = ( self.z0, self.z1, self.z2 )
        a = abs( B - C )
        b = abs( C - A )
        c = abs( A - B )
        s = a + b + c
        m = ( a*A + b*B + c*C )/s
        s *= 0.5
        r = cmath.sqrt( ( s - a )*( s - b )*( s - c )/s )
        return Kreis( m,r )
    #--------------------------------------------------------------------------
    def schwerpunkt( self ):
        'gibt den schwerpunkt dieses dreiecks'
        return ( self.z0 + self.z1 + self.z2 )/3.
    #--------------------------------------------------------------------------
    def hoehenschnittpunkt( self ):
        'gibt den hoehenschnittpunkt dieses dreiecks'
        ( A,B,C ) = ( self.z0, self.z1, self.z2 )
        d = A.cross( B ) + B.cross( C ) + C.cross( A )
        return i/d*( A.dot( B - C )*A + B.dot( C - A )*B + C.dot( A - B )*C )
    #--------------------------------------------------------------------------
    def baryPunkt( self, m1, m2, m3 ):
        'gibt den punkt mit baryzentrischen Koordinaten m1, m2, m3'
        return ( m1*self.z0 + m2*self.z1 + m3*self.z2 )/( m1 + m2 + m3 )
   #--------------------------------------------------------------------------
    def baryKoord( self, z ):
        'gibt die normierten baryzentrischen Koordinaten von z'
        d  = ( self.z1 - self.z0 ).cross( self.z2 - self.z1 )
        m1 = ( self.z1 - z ).cross( self.z2 - z )/d
        m2 = ( self.z2 - z ).cross( self.z0 - z )/d
        return ( m1, m2, 1 - m1 - m2 ) # summe = 1
    #--------------------------------------------------------------------------
    def trilinPunkt( self, t1, t2, t3 ):
        'gibt den punkt mit trilinearen Koordinaten t1, t2, t3'
        ( a,b,c ) = ( abs( self.z1-self.z2 ), abs( self.z2-self.z0 ),
                      abs( self.z0-self.z1 ) )
        ( m1, m2, m3 ) = ( a*t1, b*t2, c*t3 )
        return ( m1*self.z0 + m2*self.z1 + m3*self.z2 )/( m1 + m2 + m3 )
   #--------------------------------------------------------------------------
    def trilinKoord( self, z ):
        'gibt die normierten trilinearen koordinaten von z'
        ( a,b,c ) = ( abs( self.z1-self.z2 ), abs( self.z2-self.z0 ),
                      abs( self.z0-self.z1 ) )
        dBC = ( self.z2 - self.z1 ).cross( z - self.z1 )/a
        dCA = ( self.z0 - self.z2 ).cross( z - self.z2 )/b
        dAB = ( self.z1 - self.z0 ).cross( z - self.z0 )/c
        d   = dAB + dBC + dCA
        return ( dBC/d, dCA/d, dAB/d ) # summe = 1
    #--------------------------------------------------------------------------
    def enthaelt( self, z ):
        'prueft, ob z in diesem dreieck liegt'
        return all( [  x>=0 for x in self.baryKoord( z ) ] )
    #--------------------------------------------------------------------------
#==============================================================================
class Polygon:
    #--------------------------------------------------------------------------
    def __init__( self, *points ):
        self.points = points
        self.nump   = len( points )
        rev = list( reversed( points ) )
        if ( abs( self.innenwinkelsumme( points ) )
             > abs( self.innenwinkelsumme( rev ) ) ):
             self.points = rev
    #--------------------------------------------------------------------------
    def innenwinkelsumme( self, points=[] ):
        if len( points ) == 0:
            points = self.points
        ( z0, z1 ) = points[ -2: ]
        w = 0.
        for z2 in points:
            w += ( z2 - z1 ).angle( z0 - z1 )%( 2*cmath.pi )
            z0 = z1
            z1 = z2
        return w
    #--------------------------------------------------------------------------
    def inhalt( self ):
        'gibt den flaecheninhalt dieses polygons'
        z0 = self.points[ -1 ]
        A  = 0.
        for z1 in self.points:
            A += z0.cross( z1 )
            z0 = z1
        return 0.5*A
    #--------------------------------------------------------------------------
    def schwerpunkt( self, k=0 ):
        'findet schwerpunkt fuer konvexe polygone'
        ps = self.points[ k: ] + self.points[ :k ]
        ( p0, p1 ) = ps[ :2 ]
        s = ages = 0.
        for p2 in ps[ 2: ]:
            d = Dreieck( p0, p1, p2 )
            a = d.inhalt()
            s = s + d.schwerpunkt()*a
            ages += a
            p1 = p2
        return s/ages
    #--------------------------------------------------------------------------
#==============================================================================
class Kreis( Geometrie ):
    'Berechnungen eines Kreis'
    #--------------------------------------------------------------------------
    def __init__( self, m, r ):
        'kreis um m mit radius |r|'
        Geometrie.__init__( self, m )
        self.r = abs( r )
    #--------------------------------------------------------------------------
    def inhalt( k ):
        'gibt den flaecheninhalt'
        return cmath.pi*self.r**2
    #--------------------------------------------------------------------------
    def project( k, p ):
        'projiziert p auf k'
        return k.z0 + k.r/abs( p - k.z0 )*( p - k.z0 )
    #--------------------------------------------------------------------------
    def schnittPunkteGerade( k, g ):
        'gibt 0,1 oder 2 Schnittpunkte der Geraden g mit diesem Kreis k.'
        ans = ()
        d   = g.z0 - k.z0
        p   = g.e.dot( d )
        q   = p**2 - abs( d )**2 + k.r**2
        if q > 0:
            w   = cmath.sqrt( q )
            ans = ( g.z0 - ( w + p )*g.e, g.z0 + ( w - p )*g.e )
        elif abs( q ) < 1.e-9*k.r: # w=0
            ans = ( g.z0 - p*g.e, )
        return [ Punkt( p ) for p in ans ]
    #--------------------------------------------------------------------------
    def schnittPunkteKreis( k1, k2 ):
        'gibt 0,1 oder 2 schnittpunkte von Kreis k1 und k2'
        ans = ()
        g   = k2.z0 - k1.z0
        ga  = abs( g )
        sx  = 0.5*( ( k1.r**2 - k2.r**2 )/ga**2 + 1 )
        sy  = k1.r**2/ga**2 - sx**2
        if sy > 0:
            sy  = cmath.sqrt( sy ).real
            s   = complex( sx,sy )
            sq  = s.conjugate()
            ans = ( ( k1.z0 + s*g ), ( k1.z0 + sq*g ) )
        elif abs( sy ) < 1.e-9*k1.r: # sy=0
            ans = ( ( k1.z0 + sx*g ), )
        return [ Punkt( p ) for p in ans ]
    #--------------------------------------------------------------------------
    def tangenteIn( self, P ):
        'gibt die tangente in P'
        return Gerade( P, P + i*( P - self.z0 ) )
    #--------------------------------------------------------------------------
    def tangentenDurch( self, P ):
        'gibt 0,1 oder 2 tangenten an diesen kreis durch p'
        ans = []
        d   = abs( P - self.z0 )
        if d > self.r:
            k = Kreis( 0.5*( self.z0 + P ), 0.5*abs( self.z0 - P ) )
            ( T1, T2 ) = self.schnittPunkteKreis( k )
            ans = [ Gerade( T1, T1 + i*( T1 - self.z0 ) ),
                    Gerade( T2, T2 + i*( T2 - self.z0 ) ) ]
        elif d == self.r:
            ans = [ Gerade( P, P + i*( P - self.z0 ) ) ]
        return ans
    #--------------------------------------------------------------------------
    def tangentenAussen( K,k ):
        '''die aeusseren tangenten mit kreis k
        ges e: M+R*e+l*i*e-r*e=M+(R-r+i*l)*e=m, l**2+(R-r)**2=|M-m|**2
        oder   M-R*e+l*i*e+r*e=M+(r-R+i*l)*e=m
        '''
        ( M, R, m, r ) = ( K.z0, K.r, k.z0, k.r )
        l  = cmath.sqrt( ( M - m ).dot( M - m ) - ( R - r )**2 )
        e1 = ( m - M )/complex( R - r, l )
        t1 = Gerade( M + R*e1, m + r*e1 )
        e2 = ( m - M )/complex( r - R, l )
        t2 = Gerade( M - R*e2, m - r*e2 )
        return ( t1, t2 )
    #--------------------------------------------------------------------------
    def tangentenInnen( K,k ):
        '''die inneren tangenten mit kreis k
        ges e: M+R*e+l*i*e+r*e=M+(R+r+i*l)*e=m, l**2+(R+r)**2=|M-m|**2
        oder   M+R*e-l*i*e+r*e=M+(r+R-i*l)*e=m
        '''
        ( M, R, m, r ) = ( K.z0, K.r, k.z0, k.r )
        ans = []
        l   = ( M - m ).dot( M - m ) - ( R + r )**2
        if l >= 0:
            l  = cmath.sqrt( l )
            e1 = ( m - M )/complex( R + r, l )
            t1 = Gerade( M + R*e1, m - r*e1 )
            e2 = ( m - M )/complex( R + r, -l )
            t2 = Gerade( M + R*e2, m - r*e2 )
            ans = ( t1, t2 )
            cumtest( cum, 'e12', ( 1,1 ), ( abs( e1 ), abs( e2 ) ), fp )
        return ans
    #--------------------------------------------------------------------------
    def optKreis( self, P ):
        'minimiert sum( [ ( ( Pj - M ).dot( Pj - M ) - r**2 )**2 ] )'
        N = len( P )
        o = Punkt( 0,0 )
        a = sum( P, o )
        z = 2./N*a
        b = sum( [ Pj.dot( Pj ) for Pj in P ] )/N
        c = sum( [ Pj.dot( Pj )*Pj for Pj in P ], o )
        A = 2*sum( [ Pj.outer( Pj ) for Pj in P ], a.outer( -0.5*z ) )
        M = A.inv().mmul( c - b*a )
        r = cmath.sqrt( b + M.dot( M - z ) )
        return Kreis( M, r )
    #--------------------------------------------------------------------------
    def spiegel( self, obj, tol=1.e-6 ):
        'kreisspiegelung an diesem kreis'
        if self.isNumber( obj ):
            obj = Punkt( obj )
        if isinstance( obj, Punkt ):
            ans = self.z0 + self.r**2/( obj - self.z0 ).conjugate()
        elif isinstance( obj, Gerade ):
            if abs( obj.dist( self.z0 ) ) < tol*self.r: # gerade durch O
                ans = obj.copy( )
            else: # abb auf kreis durch ursprung
                p   = obj.fussPunkt( self.z0 ) # C'
                ps  = self.z0 + self.r**2/( p - self.z0 ).conjugate() # C
                ans = Kreis( 0.5*( self.z0 + ps ), 0.5*abs( self.z0 - ps ) )
        elif isinstance( obj, Kreis ):
            g = obj.z0 - self.z0
            if abs( abs( g ) - obj.r ) < tol*self.r: # durch O -> Gerade
                p   = self.z0 + 2*g
                ps  = self.z0 + self.r**2/( p - self.z0 ).conjugate()
                ans = Gerade( ps, ps + i*g )
            else: # abb auf kreis
                s   = self.r**2/( abs( g )**2 - obj.r**2 )
                ans = Kreis( self.z0 + s*g, abs( s )*obj.r )
        elif hasattr( obj, '__len__' ): # liste
            ans = [ self.spiegel( p ) for p in obj ]
        else:
            raise NotImplementedError( 'Kreisspiegelung fuer %s'%type( obj )
                                       + 'nicht implementiert' )
        #print( 'spiegel %s -> %s'%( obj, ans ) )
        return ans
    #--------------------------------------------------------------------------
    def __str__( self ):
        fmt = 'Kreis( ( %s,%s ), %s )'%tuple( 3*[ floatfmt ] )
        return fmt%( self.z0.real, self.z0.imag, self.r )
    #--------------------------------------------------------------------------
#==============================================================================
class Test:
    'testet routinen'
    #--------------------------------------------------------------------------
    def __init__( self ):
        global uniform, mf, nf, cumtest
        from random import uniform
        import matfunc2 as mf, numpyfunc as nf
        cumtest = nf.cumtest
#        self.punkt()
#        self.angle()
#        self.schnittPunkt()
#        self.dist()
#        self.winkelhalbierende()
        self.dreieck()
#        self.kreis()
#        self.matrix()
#        self.spiegelung()
        print( 'Test: %d/%d richtig'%tuple( cum ) )
        cumtest( cum, '', 0,0, fout=fp )
    #--------------------------------------------------------------------------
    def punkt( self ):
        ( p,q ) = [ Punkt( u(),u() ) for j in 'ab' ]
        ( j,r,c ) = ( 4, 4., 4.+0j )
        cumtest( cum, '+', Punkt( p.z0 + q.z0 ).p2t(), ( p + q ).p2t(),
                 fout=fp )
        cumtest( cum, '-', Punkt( p.z0 - q.z0 ).p2t(), ( p - q ).p2t(),
                 fout=fp )
        cumtest( cum, '*', Punkt( p.z0 * q.z0 ).p2t(), ( p * q ).p2t(),
                 fout=fp )
        cumtest( cum, '/', Punkt( p.z0 / q.z0 ).p2t(), ( p / q ).p2t(),
                 fout=fp )
        for z in ( c,r,j ):
            cumtest( cum, 'r+', Punkt( z + p.z0 ).p2t(), ( z + p ).p2t(),
                 fout=fp )
            cumtest( cum, 'l+', Punkt( p.z0 + z ).p2t(), ( p + z ).p2t(),
                 fout=fp )
            cumtest( cum, 'r-', Punkt( z - p.z0 ).p2t(), ( z - p ).p2t(),
                 fout=fp )
            cumtest( cum, 'l-', Punkt( p.z0 - z ).p2t(), ( p - z ).p2t(),
                 fout=fp )
            cumtest( cum, 'r*', Punkt( z * p.z0 ).p2t(), ( z * p ).p2t(),
                 fout=fp )
            cumtest( cum, 'l*', Punkt( p.z0 * z ).p2t(), ( p * z ).p2t(),
                 fout=fp )
            cumtest( cum, 'r/?', Punkt( z / p.z0 ).p2t(), ( z / p ).p2t(),
                 fout=fp )
            cumtest( cum, 'l/', Punkt( p.z0 / z ).p2t(), ( p / z ).p2t(),
                 fout=fp )
    #--------------------------------------------------------------------------
    def matrix( self ):
        ( a,b,c,d,e,f,g,h,w,x,y,z ) = [ u() for j in 12*'a' ]
        mz = Matrix( Punkt( a, b ),  # r
                     Punkt( c, d ) ) # s
        cumtest( cum, 'objs', 11*( True, ), (
            isinstance( complex( c,d )*Punkt( a,b ), Punkt ),
            isinstance( Punkt( a,b )*complex( c,d ), Punkt ),
            isinstance( Punkt( a,b ) + Punkt( c,d ), Punkt ),
            isinstance( Punkt( a,b ).outer( Punkt( c,d ) ), Matrix ),
            isinstance( complex( c,d )*mz, Matrix ),
            isinstance( mz*complex( c,d ), Matrix ),
            isinstance( mz.mmul( mz ), Matrix ),
            isinstance( ( complex( c,d )*mz ).z0, Punkt ),
            isinstance( ( mz*complex( c,d ) ).z0, Punkt ),
            isinstance( ( complex( c,d )*mz ).z1, Punkt ),
            isinstance( ( mz*complex( c,d ) ).z1, Punkt )
            ), fout=fp )
        mm = mz.toSquare()
        cumtest( cum, 'mz2mm', mf.Square( [ [ a,b ],[ c,d ] ] ), mm, fout=fp )
        cumtest( cum, 'mt2mt', mz.tr().toSquare(), mm.tr(), fout=fp )
        nz = Matrix( Punkt( e, f ),  # u
                     Punkt( g, h ) ) # v
        nm = mf.Square( [ [ e,f ],[ g,h ] ] )
        cumtest( cum, 'nz2nm', nz.toSquare(), nm, fout=fp )
        vm = mf.Vec( [ x,y ] )
        cumtest( cum, 'mm.vm', ( a*x + b*y, c*x + d*y ), mm.mmul( vm ),
                 fout=fp )
        cumtest( cum, 'mm.nm', ( [ b*g + a*e, b*h + a*f],
                                 [ d*g + c*e, d*h + c*f ] ), mm.mmul( nm ),
                 fout=fp )
        vz = Punkt( x,y )
        cumtest( cum, 'a o bmf', 2*( ( ( a*c, a*d ), ( b*c, b*d ) ), ), (
            mf.Vec( [ a,b ] ).outer( mf.Vec( [ c,d ] ) ),
            Punkt( a,b ).outer( Punkt( c,d ) ).toSquare() ), fout=fp )
        #nz = Square(
        cumtest( cum, 'mz.vz', Punkt( a*x + b*y, c*x + d*y ).z0,
                 mz.mmul( vz ).z0, fout=fp )
        cumtest( cum, 'mz.nz', mz.mmul( nz ).toSquare(), mm.mmul( nm ),
                 fout=fp )
        cumtest( cum, 'spur', mm.spur(), mz.spur(), fout=fp )
        cumtest( cum, 'det', mm.det(), mz.det(), fout=fp )
        mz1 = mz.inv()
        e   = mz.mmul( mz1 )
        cumtest( cum, 'inv', Eye().toSquare(), e.toSquare(), fout=fp )
        c = Punkt( u(), 0 )
        l = c #Punkt( c )
        dum1 = ( mz - Eye()*l ).toSquare()
        dum2 = mm - c.z0*mf.eye( 3 )
        cumtest( cum, 'm-lE', dum1, dum2,
                 fout=fp )
        cumtest( cum, 'char', ( mz - Eye()*l ).det(),
                 Punkt( l**2 - mz.spur()*l + mz.det() ).z0, fout=fp )
        mz = mz.sym()
        mm = mz.toSquare()
        ( ( l1,l2 ), ( v1,v2 ) ) = mz.eig()
        cumtest( cum, 'det1', 0, ( mz - l1*Eye() ).det(), fout=fp )
        cumtest( cum, 'det2', 0,
                 ( mz - l2*Matrix( Punkt( 1,0 ), Punkt( 0,1 ) ) ).det(),
                 fout=fp )
        cumtest( cum, 'l1', Punkt( l1*v1 ).z0, mz.mmul( v1 ).z0, fout=fp )
        cumtest( cum, 'l2', Punkt( l2*v2 ).z0, mz.mmul( v2 ).z0, fout=fp )
    #--------------------------------------------------------------------------
    def kreis( self ):
        m1 = Punkt( u(), u() )
        ( r1, r2 ) = [ abs( u() ), abs( u() ) ]
        g = Punkt( u(), u() ).normalize()
        m2 = m1 + cmath.sqrt( r1**2 + r2**2 )*g
        k1 = Kreis( m1, r1 )
        k2 = Kreis( m2, r2 )
        p  = Punkt( u(), u() )
        p  = k1.z0 + u()*k1.r*p/abs( p )
        for z in k1.schnittPunkteGerade( Gerade( p, Punkt( u(), u() ) ) ):
            cumtest( cum, 'k^g', k1.r, abs( z - k1.z0 ), fout=fp )
        ( z1, z2 ) = k1.schnittPunkteKreis( k2 )
        m = Punkt( 0.5*( z1 + z2 ) )
        for z in ( z1, z2 ):
            cumtest( cum, 'k^k1', k1.r, abs( z - k1.z0 ), fout=fp )
            cumtest( cum, 'k^k2', k2.r, abs( z - k2.z0 ), fout=fp )
            cumtest( cum, 'm', k1.r**2, m.dist( z )**2 + m.dist( k1.z0 )**2,
                     fout=fp )
            cumtest( cum, 'm', k2.r**2, m.dist( z )**2 + m.dist( k2.z0 )**2,
                     fout=fp )
        P  = [ Punkt( u(), u() ) for j in 10*'a' ]
        k  = k1.optKreis( P )
        km = nf.Kreis().optKreis( [ Pj.toNpVec() for Pj in P ] )
        cumtest( cum, 'opt', ( k.z0.real, k.z0.imag, k.r ),
                 ( km.x0[ 0 ], km.x0[ 1 ], km.r ), fout=fp )
        ( P0, P1 ) = P[ :2 ]
        ( v0, v1 ) = ( P0.toNpVec(), P1.toNpVec() )
        g   = Gerade( P0, P1 )
        gv  = nf.Gerade( v0, v1 )
        k0  = Kreis( P0, 3. )
        k1  = Kreis( P1, 3. )
        kn0 = nf.Kreis( v0, 3. )
        kn1 = nf.Kreis( v1, 3. )
        cumtest( cum, 'spP', kn0.spiegel( v1 ), k0.spiegel( P1 ).p2t(),
                 fout=fp )
        cumtest( cum, 'spK', kn0.spiegel( kn1 ).x0, k0.spiegel( k1 ).z0.p2t(),
                 fout=fp )
        cumtest( cum, 'spG', kn0.spiegel( gv ).x0, k0.spiegel( g ).z0.p2t(),
                 fout=fp )
        ( M, R, m, r ) = ( complex( u(),u() ), abs( u() ),
                           complex( u(),u() ), abs( u() ) )
        K = Kreis( M,R )
        k = Kreis( m,r )
        ( t1, t2 ) = K.tangentenAussen( k )
        cumtest( cum, 'tout', ( R, R, r, r ), (
            t1.dist( M ), t2.dist( M ), t1.dist( m ), t2.dist( m ) ), fp )
        while abs( m - M ) < R + r:
            m += m - M
        k = Kreis( m, r )
        ( t1, t2 ) = K.tangentenInnen( k )
        cumtest( cum, 'tin', ( R, R, r, r ), (
            t1.dist( M ), t2.dist( M ), t1.dist( m ), t2.dist( m ) ), fp )
    #--------------------------------------------------------------------------
    def dreieck( self ):
        e = ( za, zb, zc ) = [ Punkt( u(), u() ) for j in 'abc' ]
        ( va, vb, vc ) = [ p.toNpVec() for p in ( za, zb, zc ) ]
        d = Dreieck( za, zb, zc )
        ( a,b,c ) = ( abs( zb - zc ), abs( za - zc ), abs( za - zb ) )
        cumtest( cum, 'inhalt', 3*( d.inhalt(), ), (
                 0.5*abs( ( za-zc ).cross( zb-za ) ),
                 0.5*abs( ( zb-za ).cross( zc-zb ) ),
                 0.5*abs( ( zc-zb ).cross( za-zc ) ) ), fp )
        ku = d.umkreis()
        cumtest( cum, 'umkreis', 3*( ku.r, ), [ abs( z - ku.z0 ) for z in e ],
                 fp )
        ki = d.inkreis()
        cumtest( cum, 'inkreis', 3*( ki.r, ), (
            Gerade( za, zb ).dist( ki.z0 ), Gerade( zb, zc ).dist( ki.z0 ),
            Gerade( zc, za ).dist( ki.z0 ) ), fp )
        S = d.schwerpunkt()
        cumtest( cum, 'S', ( 0,0,0 ), (
            Gerade( za,0.5*(zb + zc ) ).dist( S ),
            Gerade( zb,0.5*(zc + za ) ).dist( S ),
            Gerade( zc,0.5*(za + zb ) ).dist( S ) ), fp )
        H = d.hoehenschnittpunkt()
        cumtest( cum, 'H', ( 0,0,0 ), (
            Gerade( zb,zc ).senkrechteDurch( za ).dist( H ),
            Gerade( zc,za ).senkrechteDurch( zb ).dist( H ),
            Gerade( za,zb ).senkrechteDurch( zc ).dist( H ) ), fp )
        cumtest( cum, 'barya', ( 1,0,0 ), d.baryKoord( za ), fp )
        cumtest( cum, 'baryb', ( 0,1,0 ), d.baryKoord( zb ), fp )
        cumtest( cum, 'baryc', ( 0,0,1 ), d.baryKoord( zc ), fp )
        z = Punkt( u(), u() )
        ( ba, bb, bc ) = bcoord = d.baryKoord( z )
        cumtest( cum, 'bary', z.p2t(), d.baryPunkt( *bcoord ).p2t(), fp )
        cumtest( cum, 'trilina', ( 1,0,0 ), d.trilinKoord( za ), fp )
        cumtest( cum, 'trilinb', ( 0,1,0 ), d.trilinKoord( zb ), fp )
        cumtest( cum, 'trilinc', ( 0,0,1 ), d.trilinKoord( zc ), fp )
        ( ta, tb, tc ) = tcoord = d.trilinKoord( z )
        cumtest( cum, 'tribary', 2*( ta*a/ba, ), ( tb*b/bb, tc*c/bc ), fp )
        cumtest( cum, 'trilin', z.p2t(), d.trilinPunkt( *tcoord ).p2t(), fp )
        cumtest( cum, 'norm', ( 1,1 ), ( sum( bcoord ), sum( tcoord ) ), fp )
        P = 0.5*(za + zb )
        g = P - zc
        print( d.trilinKoord( S ), d.trilinKoord( H ),
               all( [ x>=0 for x in d.baryKoord( P-1.001*g ) ] ) )
    #--------------------------------------------------------------------------
    def angle( self ):
        ( za, zb ) = [ Punkt( u(), u() ) for j in 'ab' ]
        ( va, vb ) = [ p.toNpVec() for p in ( za, zb ) ]
        a = za.angle( zb )
        b = va.angle( vb )
        cumtest( cum, 'angle', 0, min( abs( cmath.pi - a - b ),
                                       abs( a - b ) ), fout=fp )
    #--------------------------------------------------------------------------
    def schnittPunkt( self ):
        ( za, zb, zc, zd ) = [ Punkt( u(), u() ) for j in 'abcd' ]
        ( va, vb, vc, vd ) = [ p.toNpVec() for p in ( za, zb, zc, zd ) ]
        zab = Gerade( za, zb )
        zcd = Gerade( zc, zd )
        zp = zab.schnittPunkt( zcd )[ 0 ]
        vp = nf.Gerade( va, vb ).schnittPunkt( nf.Gerade( vc, vd ) )
        cumtest( cum, 'spkt', zp.toNpVec(), vp, fout=0 )
    #--------------------------------------------------------------------------
    def dist( self ):
        ( za, zb, z ) = [ Punkt( u(), u() ) for j in 'abc' ]
        ( va, vb, v ) = [ p.toNpVec() for p in ( za, zb, z ) ]
        cumtest( cum, 'distP', za.dist( zb ), va.dist( vb ), fout=fp )
        cumtest( cum, 'dist', abs( nf.Gerade( va, vb ).dist( v ) ),
                 abs( Gerade( za, zb ).dist( z ) ), fout=fp )
    #--------------------------------------------------------------------------
    def winkelhalbierende( self ):
        ( za, zb, zc, zd ) = [ Punkt( u(), u() ) for j in 'abcd' ]
        ( va, vb, vc, vd ) = [ p.toNpVec() for p in ( za, zb, zc, zd ) ]
        zab = Gerade( za, zb )
        zcd = Gerade( zc, zd )
        zp = zab.winkelhalbierende( zcd )
        vp = nf.Gerade( va, vb ).winkelhalbierende( nf.Gerade( vc, vd ) )
        cumtest( cum, 'whz', zp.z0.toNpVec(), vp.x0, fout=fp )
        cumtest( cum, 'whg', zp.e.toNpVec(), vp.g, fout=fp )
    #--------------------------------------------------------------------------
    def spiegelung( self ):
        ( za, zb, zc, zd ) = [ Punkt( u(), u() ) for j in 'abcd' ]
        # punkt
        zb2 = za.spiegel( zb )
        cumtest( cum, 'punkt', 1*( 0, ), ( za.dist( 0.5*( zb + zb2 ) ),
                 ), fout=fp )
        # gerade y=a*x+b
        ( a, b ) = ( zd.real, zd.imag )
        g  = Gerade( 0,1 )
        h  = Gerade( i*b, complex( 1,a+b ) )
        h1 = g.spiegel( h )
        hs =  Gerade( -i*b, complex( 1,-a-b ) )
        cumtest( cum, 'waagerecht', 2*( 0, ), (
            hs.dist( h1.z0 ), hs.dist( h1.z1 ) ), fout=fp )
        g  = Gerade( 0,i )
        h1 = g.spiegel( h )
        hs =  Gerade( i*b, complex( -1,a+b ) )
        cumtest( cum, 'senkrecht', 2*( 0, ), (
            hs.dist( h1.z0 ), hs.dist( h1.z1 ) ), fout=fp )
        zab = Gerade( za, zb )
        zc2 = zab.spiegel( zc )
        zcc = Gerade( zc, zc2 )
        cumtest( cum, 'gerade', 5*( 0, ), (
            zab.dist( 0.5*( zc + zc2 ) ), zab.e.dot( zc2 - zc ),
            zab.e.dot( zcc.e ), hs.dist( h1.z0 ), hs.dist( h1.z1 )
            ), fout=fp )
    #--------------------------------------------------------------------------
#==============================================================================
if __name__ == '__main__':
    Test()