1 /*****************************************************************************
4 * This module implements hypercomplex Julia fractals.
6 * This file was written by Pascal Massimino.
8 * from Persistence of Vision(tm) Ray Tracer
9 * Copyright 1996,1999 Persistence of Vision Team
10 *---------------------------------------------------------------------------
11 * NOTICE: This source code file is provided so that users may experiment
12 * with enhancements to POV-Ray and to port the software to platforms other
13 * than those supported by the POV-Ray Team. There are strict rules under
14 * which you are permitted to use this file. The rules are in the file
15 * named POVLEGAL.DOC which should be distributed with this file.
16 * If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
17 * Team Coordinator by email to team-coord@povray.org or visit us on the web at
18 * http://www.povray.org. The latest version of POV-Ray may be found at this site.
20 * This program is based on the popular DKB raytracer version 2.12.
21 * DKBTrace was originally written by David K. Buck.
22 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
24 *****************************************************************************/
36 /*****************************************************************************
37 * Local preprocessor defines
38 ******************************************************************************/
40 #ifndef Fractal_Tolerance
41 #define Fractal_Tolerance 1e-8
45 #define HMult(xr,yr,zr,wr,x1,y1,z1,w1,x2,y2,z2,w2) \
46 (xr) = (x1) * (x2) - (y1) * (y2) - (z1) * (z2) + (w1) * (w2); \
47 (yr) = (y1) * (x2) + (x1) * (y2) - (w1) * (z2) - (z1) * (w2); \
48 (zr) = (z1) * (x2) - (w1) * (y2) + (x1) * (z2) - (y1) * (w2); \
49 (wr) = (w1) * (x2) + (z1) * (y2) + (y1) * (z2) + (x1) * (w2);
51 #define HSqr(xr,yr,zr,wr,x,y,z,w) \
52 (xr) = (x) * (x) - (y) * (y) - (z) * (z) + (w) * (w) ; \
53 (yr) = 2.0 * ( (x) * (y) - (z) * (w) ); \
54 (zr) = 2.0 * ( (z) * (x) - (w) * (y) ); \
55 (wr) = 2.0 * ( (w) * (x) + (z) * (y) );
59 /*****************************************************************************
61 ******************************************************************************/
65 /*****************************************************************************
67 ******************************************************************************/
69 static int HReciprocal (DBL
* xr
, DBL
* yr
, DBL
* zr
, DBL
* wr
, DBL x
, DBL y
, DBL z
, DBL w
);
70 static void HFunc (DBL
* xr
, DBL
* yr
, DBL
* zr
, DBL
* wr
, DBL x
, DBL y
, DBL z
, DBL w
, FRACTAL
*f
);
74 /*****************************************************************************
76 ******************************************************************************/
78 static CMPLX exponent
= {0,0};
80 /******** Computations with Hypercomplexes **********/
84 /*****************************************************************************
102 ******************************************************************************/
104 static int HReciprocal(DBL
*xr
, DBL
*yr
, DBL
*zr
, DBL
*wr
, DBL x
, DBL y
, DBL z
, DBL w
)
106 DBL det
, mod
, xt_minus_yz
;
108 det
= ((x
- w
) * (x
- w
) + (y
+ z
) * (y
+ z
)) * ((x
+ w
) * (x
+ w
) + (y
- z
) * (y
- z
));
115 mod
= (x
* x
+ y
* y
+ z
* z
+ w
* w
);
117 xt_minus_yz
= x
* w
- y
* z
;
119 *xr
= (x
* mod
- 2 * w
* xt_minus_yz
) / det
;
120 *yr
= (-y
* mod
- 2 * z
* xt_minus_yz
) / det
;
121 *zr
= (-z
* mod
- 2 * y
* xt_minus_yz
) / det
;
122 *wr
= (w
* mod
- 2 * x
* xt_minus_yz
) / det
;
129 /*****************************************************************************
133 * INPUT 4D Hypercomplex number, pointer to fractal object
135 * OUTPUT calculates the 4D generalization of fractal->Complex_Function
144 * Hypercomplex numbers allow generalization of any complex->complex
145 * function in a uniform way. This function implements a general
146 * unary 4D function based on the corresponding complex function.
149 * Generalized to use Complex_Function() TW
151 ******************************************************************************/
153 static void HFunc(DBL
*xr
, DBL
*yr
, DBL
*zr
, DBL
*wr
, DBL x
, DBL y
, DBL z
, DBL w
, FRACTAL
*f
)
157 /* convert to duplex form */
163 if(f
->Sub_Type
== PWR_STYPE
)
165 exponent
= f
->exponent
;
168 /* apply function to each part */
169 Complex_Function(&ra
, &a
, f
);
170 Complex_Function(&rb
, &b
, f
);
173 *xr
= .5 * (ra
.x
+ rb
.x
);
174 *yr
= .5 * (ra
.y
+ rb
.y
);
175 *zr
= .5 * (ra
.y
- rb
.y
);
176 *wr
= .5 * (rb
.x
- ra
.x
);
181 /*****************************************************************************
199 ******************************************************************************/
201 /*------------------ z2 Iteration method ------------------*/
203 int Iteration_HCompl(VECTOR IPoint
, FRACTAL
*HCompl
)
210 x
= Sx
[0] = IPoint
[X
];
211 y
= Sy
[0] = IPoint
[Y
];
212 z
= Sz
[0] = IPoint
[Z
];
213 w
= Sw
[0] = (HCompl
->SliceDist
216 - HCompl
->Slice
[Z
]*z
)/HCompl
->Slice
[T
];
218 Exit_Value
= HCompl
->Exit_Value
;
220 for (i
= 1; i
<= HCompl
->n
; ++i
)
225 if ((xw
+ yz
) > Exit_Value
)
230 Sx
[i
] = xw
- yz
+ HCompl
->Julia_Parm
[X
];
231 Sy
[i
] = 2.0 * (x
* y
- z
* w
) + HCompl
->Julia_Parm
[Y
];
232 Sz
[i
] = 2.0 * (x
* z
- w
* y
) + HCompl
->Julia_Parm
[Z
];
233 Sw
[i
] = 2.0 * (x
* w
+ y
* z
) + HCompl
->Julia_Parm
[T
];
247 /*****************************************************************************
265 ******************************************************************************/
267 int D_Iteration_HCompl(VECTOR IPoint
, FRACTAL
*HCompl
, DBL
*Dist
)
271 DBL Exit_Value
, F_Value
, Step
;
275 x
= Sx
[0] = IPoint
[X
];
276 y
= Sy
[0] = IPoint
[Y
];
277 z
= Sz
[0] = IPoint
[Z
];
278 w
= Sw
[0] = (HCompl
->SliceDist
281 - HCompl
->Slice
[Z
]*z
)/HCompl
->Slice
[T
];
283 Exit_Value
= HCompl
->Exit_Value
;
285 for (i
= 1; i
<= HCompl
->n
; ++i
)
290 if ((F_Value
= xw
+ yz
) > Exit_Value
)
292 Normal_Calc_HCompl(H_Normal
, i
- 1, HCompl
);
294 VDot(Step
, H_Normal
, Direction
);
296 if (Step
< -Fractal_Tolerance
)
300 if ((F_Value
> Precision
* Step
) && (F_Value
< 30 * Precision
* Step
))
302 *Dist
= F_Value
/ Step
;
313 Sx
[i
] = xw
- yz
+ HCompl
->Julia_Parm
[X
];
314 Sy
[i
] = 2.0 * (x
* y
- z
* w
) + HCompl
->Julia_Parm
[Y
];
315 Sz
[i
] = 2.0 * (x
* z
- w
* y
) + HCompl
->Julia_Parm
[Z
];
316 Sw
[i
] = 2.0 * (x
* w
+ y
* z
) + HCompl
->Julia_Parm
[T
];
332 /*****************************************************************************
350 ******************************************************************************/
352 void Normal_Calc_HCompl(VECTOR Result
, int N_Max
, FRACTAL
*fractal
)
361 * Algebraic properties of hypercomplexes allows simplifications in
372 for (i
= 1; i
< N_Max
; ++i
)
376 * For a map z->f(z), f depending on c, one must perform here :
378 * (x,y,z,w) * df/dz(Sx[i],Sy[i],Sz[i],Sw[i]) -> (x,y,z,w) ,
383 /******************* Case z->z^2+c *****************/
385 /* the df/dz part needs no work */
387 HMult(xx
, yy
, zz
, ww
, Sx
[i
], Sy
[i
], Sz
[i
], Sw
[i
], x
, y
, z
, w
);
397 n1
= Sx
[N_Max
] * Pow
;
398 n2
= Sy
[N_Max
] * Pow
;
399 n3
= Sz
[N_Max
] * Pow
;
400 n4
= Sw
[N_Max
] * Pow
;
402 Result
[X
] = x
* n1
+ y
* n2
+ z
* n3
+ w
* n4
;
403 Result
[Y
] = -y
* n1
+ x
* n2
- w
* n3
+ z
* n4
;
404 Result
[Z
] = -z
* n1
- w
* n2
+ x
* n3
+ y
* n4
;
409 /*****************************************************************************
427 ******************************************************************************/
429 int F_Bound_HCompl(RAY
*Ray
, FRACTAL
*Fractal
, DBL
*Depth_Min
, DBL
*Depth_Max
)
431 return (Intersect_Sphere(Ray
, Fractal
->Center
, Fractal
->Radius_Squared
, Depth_Min
, Depth_Max
));
434 /****************************************************************/
435 /*--------------------------- z3 -------------------------------*/
436 /****************************************************************/
440 /*****************************************************************************
458 ******************************************************************************/
460 int Iteration_HCompl_z3(VECTOR IPoint
, FRACTAL
*HCompl
)
463 DBL Norm
, xx
, yy
, zz
, ww
;
467 x
= Sx
[0] = IPoint
[X
];
468 y
= Sy
[0] = IPoint
[Y
];
469 z
= Sz
[0] = IPoint
[Z
];
470 w
= Sw
[0] = (HCompl
->SliceDist
473 - HCompl
->Slice
[Z
]*z
)/HCompl
->Slice
[T
];
475 Exit_Value
= HCompl
->Exit_Value
;
477 for (i
= 1; i
<= HCompl
->n
; ++i
)
479 Norm
= x
* x
+ y
* y
+ z
* z
+ w
* w
;
481 /* is this test correct ? */
482 if (Norm
> Exit_Value
)
487 /*************** Case: z->z^2+c *********************/
488 HSqr(xx
, yy
, zz
, ww
, x
, y
, z
, w
);
490 x
= Sx
[i
] = xx
+ HCompl
->Julia_Parm
[X
];
491 y
= Sy
[i
] = yy
+ HCompl
->Julia_Parm
[Y
];
492 z
= Sz
[i
] = zz
+ HCompl
->Julia_Parm
[Z
];
493 w
= Sw
[i
] = ww
+ HCompl
->Julia_Parm
[T
];
502 /*****************************************************************************
520 ******************************************************************************/
522 int D_Iteration_HCompl_z3(VECTOR IPoint
, FRACTAL
*HCompl
, DBL
*Dist
)
526 DBL Exit_Value
, F_Value
, Step
;
530 x
= Sx
[0] = IPoint
[X
];
531 y
= Sy
[0] = IPoint
[Y
];
532 z
= Sz
[0] = IPoint
[Z
];
533 w
= Sw
[0] = (HCompl
->SliceDist
536 - HCompl
->Slice
[Z
]*z
)/HCompl
->Slice
[T
];
538 Exit_Value
= HCompl
->Exit_Value
;
540 for (i
= 1; i
<= HCompl
->n
; ++i
)
542 F_Value
= x
* x
+ y
* y
+ z
* z
+ w
* w
;
544 if (F_Value
> Exit_Value
)
546 Normal_Calc_HCompl_z3(H_Normal
, i
- 1, HCompl
);
548 VDot(Step
, H_Normal
, Direction
);
550 if (Step
< -Fractal_Tolerance
)
554 if ((F_Value
> Precision
* Step
) && (F_Value
< 30 * Precision
* Step
))
556 *Dist
= F_Value
/ Step
;
567 /*************** Case: z->z^2+c *********************/
569 HSqr(xx
, yy
, zz
, ww
, x
, y
, z
, w
);
571 x
= Sx
[i
] = xx
+ HCompl
->Julia_Parm
[X
];
572 y
= Sy
[i
] = yy
+ HCompl
->Julia_Parm
[Y
];
573 z
= Sz
[i
] = zz
+ HCompl
->Julia_Parm
[Z
];
574 w
= Sw
[i
] = ww
+ HCompl
->Julia_Parm
[T
];
584 /*****************************************************************************
602 ******************************************************************************/
604 void Normal_Calc_HCompl_z3(VECTOR Result
, int N_Max
, FRACTAL
*fractal
)
612 * Algebraic properties of hypercomplexes allows simplifications in
621 for (i
= 1; i
< N_Max
; ++i
)
624 * For a map z->f(z), f depending on c, one must perform here :
626 * (x,y,z,w) * df/dz(Sx[i],Sy[i],Sz[i],Sw[i]) -> (x,y,z,w) ,
631 /******************* Case z->z^2+c *****************/
633 /* the df/dz part needs no work */
635 HMult(xx
, yy
, zz
, ww
, Sx
[i
], Sy
[i
], Sz
[i
], Sw
[i
], x
, y
, z
, w
);
648 Result
[X
] = x
* n1
+ y
* n2
+ z
* n3
+ w
* n4
;
649 Result
[Y
] = -y
* n1
+ x
* n2
- w
* n3
+ z
* n4
;
650 Result
[Z
] = -z
* n1
- w
* n2
+ x
* n3
+ y
* n4
;
655 /*****************************************************************************
673 ******************************************************************************/
675 int F_Bound_HCompl_z3(RAY
*Ray
, FRACTAL
*Fractal
, DBL
*Depth_Min
, DBL
*Depth_Max
)
677 return F_Bound_HCompl(Ray
, Fractal
, Depth_Min
, Depth_Max
);
680 /*--------------------------- Inv -------------------------------*/
683 /*****************************************************************************
701 ******************************************************************************/
703 int Iteration_HCompl_Reciprocal(VECTOR IPoint
, FRACTAL
*HCompl
)
706 DBL Norm
, xx
, yy
, zz
, ww
;
710 x
= Sx
[0] = IPoint
[X
];
711 y
= Sy
[0] = IPoint
[Y
];
712 z
= Sz
[0] = IPoint
[Z
];
713 w
= Sw
[0] = (HCompl
->SliceDist
716 - HCompl
->Slice
[Z
]*z
)/HCompl
->Slice
[T
];
718 Exit_Value
= HCompl
->Exit_Value
;
720 for (i
= 1; i
<= HCompl
->n
; ++i
)
722 Norm
= x
* x
+ y
* y
+ z
* z
+ w
* w
;
724 if (Norm
> Exit_Value
)
729 HReciprocal(&xx
, &yy
, &zz
, &ww
, x
, y
, z
, w
);
731 x
= Sx
[i
] = xx
+ HCompl
->Julia_Parm
[X
];
732 y
= Sy
[i
] = yy
+ HCompl
->Julia_Parm
[Y
];
733 z
= Sz
[i
] = zz
+ HCompl
->Julia_Parm
[Z
];
734 w
= Sw
[i
] = ww
+ HCompl
->Julia_Parm
[T
];
743 /*****************************************************************************
761 ******************************************************************************/
763 int D_Iteration_HCompl_Reciprocal(VECTOR IPoint
, FRACTAL
*HCompl
, DBL
*Dist
)
767 DBL Exit_Value
, F_Value
, Step
;
771 x
= Sx
[0] = IPoint
[X
];
772 y
= Sy
[0] = IPoint
[Y
];
773 z
= Sz
[0] = IPoint
[Z
];
774 w
= Sw
[0] = (HCompl
->SliceDist
777 - HCompl
->Slice
[Z
]*z
)/HCompl
->Slice
[T
];
779 Exit_Value
= HCompl
->Exit_Value
;
781 for (i
= 1; i
<= HCompl
->n
; ++i
)
783 F_Value
= x
* x
+ y
* y
+ z
* z
+ w
* w
;
785 if (F_Value
> Exit_Value
)
787 Normal_Calc_HCompl_Reciprocal(H_Normal
, i
- 1, HCompl
);
789 VDot(Step
, H_Normal
, Direction
);
791 if (Step
< -Fractal_Tolerance
)
795 if ((F_Value
> Precision
* Step
) && F_Value
< (30 * Precision
* Step
))
797 *Dist
= F_Value
/ Step
;
808 HReciprocal(&xx
, &yy
, &zz
, &ww
, x
, y
, z
, w
);
810 x
= Sx
[i
] = xx
+ HCompl
->Julia_Parm
[X
];
811 y
= Sy
[i
] = yy
+ HCompl
->Julia_Parm
[Y
];
812 z
= Sz
[i
] = zz
+ HCompl
->Julia_Parm
[Z
];
813 w
= Sw
[i
] = ww
+ HCompl
->Julia_Parm
[T
];
824 /*****************************************************************************
842 ******************************************************************************/
844 void Normal_Calc_HCompl_Reciprocal(VECTOR Result
, int N_Max
, FRACTAL
*fractal
)
850 DBL xxx
, yyy
, zzz
, www
;
853 * Algebraic properties of hypercomplexes allows simplifications in
862 for (i
= 1; i
< N_Max
; ++i
)
864 /******************* Case: z->1/z+c *****************/
866 HReciprocal(&xx
, &yy
, &zz
, &ww
, Sx
[i
], Sy
[i
], Sz
[i
], Sw
[i
]);
868 HSqr(xxx
, yyy
, zzz
, www
, xx
, yy
, zz
, ww
);
870 HMult(xx
, yy
, zz
, ww
, x
, y
, z
, w
, -xxx
, -yyy
, -zzz
, -www
);
883 Result
[X
] = x
* n1
+ y
* n2
+ z
* n3
+ w
* n4
;
884 Result
[Y
] = -y
* n1
+ x
* n2
- w
* n3
+ z
* n4
;
885 Result
[Z
] = -z
* n1
- w
* n2
+ x
* n3
+ y
* n4
;
890 /*****************************************************************************
908 ******************************************************************************/
910 int F_Bound_HCompl_Reciprocal(RAY
*Ray
, FRACTAL
*Fractal
, DBL
*Depth_Min
, DBL
*Depth_Max
)
912 return F_Bound_HCompl(Ray
, Fractal
, Depth_Min
, Depth_Max
);
915 /*--------------------------- Func -------------------------------*/
918 /*****************************************************************************
936 ******************************************************************************/
938 int Iteration_HCompl_Func(VECTOR IPoint
, FRACTAL
*HCompl
)
941 DBL Norm
, xx
, yy
, zz
, ww
;
945 x
= Sx
[0] = IPoint
[X
];
946 y
= Sy
[0] = IPoint
[Y
];
947 z
= Sz
[0] = IPoint
[Y
];
948 w
= Sw
[0] = (HCompl
->SliceDist
951 - HCompl
->Slice
[Z
]*z
)/HCompl
->Slice
[T
];
953 Exit_Value
= HCompl
->Exit_Value
;
955 for (i
= 1; i
<= HCompl
->n
; ++i
)
957 Norm
= x
* x
+ y
* y
+ z
* z
+ w
* w
;
959 if (Norm
> Exit_Value
)
964 HFunc(&xx
, &yy
, &zz
, &ww
, x
, y
, z
, w
, HCompl
);
966 x
= Sx
[i
] = xx
+ HCompl
->Julia_Parm
[X
];
967 y
= Sy
[i
] = yy
+ HCompl
->Julia_Parm
[Y
];
968 z
= Sz
[i
] = zz
+ HCompl
->Julia_Parm
[Z
];
969 w
= Sw
[i
] = ww
+ HCompl
->Julia_Parm
[T
];
978 /*****************************************************************************
996 ******************************************************************************/
998 int D_Iteration_HCompl_Func(VECTOR IPoint
, FRACTAL
*HCompl
, DBL
*Dist
)
1002 DBL Exit_Value
, F_Value
, Step
;
1006 x
= Sx
[0] = IPoint
[X
];
1007 y
= Sy
[0] = IPoint
[Y
];
1008 z
= Sz
[0] = IPoint
[Z
];
1009 w
= Sw
[0] = (HCompl
->SliceDist
1010 - HCompl
->Slice
[X
]*x
1011 - HCompl
->Slice
[Y
]*y
1012 - HCompl
->Slice
[Z
]*z
)/HCompl
->Slice
[T
];
1014 Exit_Value
= HCompl
->Exit_Value
;
1016 for (i
= 1; i
<= HCompl
->n
; ++i
)
1018 F_Value
= x
* x
+ y
* y
+ z
* z
+ w
* w
;
1020 if (F_Value
> Exit_Value
)
1022 Normal_Calc_HCompl_Func(H_Normal
, i
- 1, HCompl
);
1024 VDot(Step
, H_Normal
, Direction
);
1026 if (Step
< -Fractal_Tolerance
)
1030 if ((F_Value
> Precision
* Step
) && F_Value
< (30 * Precision
* Step
))
1032 *Dist
= F_Value
/ Step
;
1043 HFunc(&xx
, &yy
, &zz
, &ww
, x
, y
, z
, w
, HCompl
);
1045 x
= Sx
[i
] = xx
+ HCompl
->Julia_Parm
[X
];
1046 y
= Sy
[i
] = yy
+ HCompl
->Julia_Parm
[Y
];
1047 z
= Sz
[i
] = zz
+ HCompl
->Julia_Parm
[Z
];
1048 w
= Sw
[i
] = ww
+ HCompl
->Julia_Parm
[T
];
1059 /*****************************************************************************
1077 ******************************************************************************/
1079 void Normal_Calc_HCompl_Func(VECTOR Result
, int N_Max
, FRACTAL
*fractal
)
1085 DBL xxx
, yyy
, zzz
, www
;
1088 * Algebraic properties of hypercomplexes allows simplifications in
1097 for (i
= 1; i
< N_Max
; ++i
)
1099 /**************** Case: z-> f(z)+c ************************/
1101 HFunc(&xx
, &yy
, &zz
, &ww
, Sx
[i
], Sy
[i
], Sz
[i
], Sw
[i
], fractal
);
1103 HMult(xxx
, yyy
, zzz
, www
, xx
, yy
, zz
, ww
, x
, y
, z
, w
);
1116 Result
[X
] = x
* n1
+ y
* n2
+ z
* n3
+ w
* n4
;
1117 Result
[Y
] = -y
* n1
+ x
* n2
- w
* n3
+ z
* n4
;
1118 Result
[Z
] = -z
* n1
- w
* n2
+ x
* n3
+ y
* n4
;
1123 /*****************************************************************************
1141 ******************************************************************************/
1143 int F_Bound_HCompl_Func(RAY
*Ray
, FRACTAL
*Fractal
, DBL
*Depth_Min
, DBL
*Depth_Max
)
1145 return F_Bound_HCompl(Ray
, Fractal
, Depth_Min
, Depth_Max
);
1148 /*****************************************************************************
1150 * FUNCTION Complex transcental functions
1152 * INPUT pointer to source complex number
1162 * DESCRIPTION Calculate common functions on complexes
1163 * Since our purpose is fractals, error checking is lax.
1167 ******************************************************************************/
1169 void Complex_Mult (CMPLX
*target
, CMPLX
*source1
, CMPLX
*source2
)
1172 tmpx
= source1
->x
* source2
->x
- source1
->y
* source2
->y
;
1173 target
->y
= source1
->x
* source2
->y
+ source1
->y
* source2
->x
;
1177 void Complex_Div (CMPLX
*target
, CMPLX
*source1
, CMPLX
*source2
)
1179 DBL mod
,tmpx
,yxmod
,yymod
;
1180 mod
= Sqr(source2
->x
) + Sqr(source2
->y
);
1183 yxmod
= source2
->x
/mod
;
1184 yymod
= - source2
->y
/mod
;
1185 tmpx
= source1
->x
* yxmod
- source1
->y
* yymod
;
1186 target
->y
= source1
->x
* yymod
+ source1
->y
* yxmod
;
1188 } /* End Complex_Mult() */
1190 void Complex_Exp (CMPLX
*target
, CMPLX
*source
)
1193 expx
= exp(source
->x
);
1194 target
->x
= expx
* cos(source
->y
);
1195 target
->y
= expx
* sin(source
->y
);
1196 } /* End Complex_Exp() */
1198 void Complex_Sin (CMPLX
*target
, CMPLX
*source
)
1200 target
->x
= sin(source
->x
) * cosh(source
->y
);
1201 target
->y
= cos(source
->x
) * sinh(source
->y
);
1202 } /* End Complex_Sin() */
1204 void Complex_Sinh (CMPLX
*target
, CMPLX
*source
)
1206 target
->x
= sinh(source
->x
) * cos(source
->y
);
1207 target
->y
= cosh(source
->x
) * sin(source
->y
);
1208 } /* End Complex_Sinh() */
1211 void Complex_Cos (CMPLX
*target
, CMPLX
*source
)
1213 target
->x
= cos(source
->x
) * cosh(source
->y
);
1214 target
->y
= -sin(source
->x
) * sinh(source
->y
);
1215 } /* End Complex_Cos() */
1217 void Complex_Cosh (CMPLX
*target
, CMPLX
*source
)
1219 target
->x
= cosh(source
->x
) * cos(source
->y
);
1220 target
->y
= sinh(source
->x
) * sin(source
->y
);
1221 } /* End Complex_Cosh() */
1224 void Complex_Log (CMPLX
*target
, CMPLX
*source
)
1227 mod
= sqrt(source
->x
* source
->x
+ source
->y
* source
->y
);
1229 zy
= atan2(source
->y
,source
->x
);
1233 } /* End Complex_Log() */
1235 void Complex_Sqrt(CMPLX
*target
, CMPLX
*source
)
1240 if(source
->x
== 0.0 && source
->y
== 0.0)
1242 target
->x
= target
->y
= 0.0;
1246 mag
= sqrt(sqrt(Sqr(source
->x
) + Sqr(source
->y
)));
1247 theta
= atan2(source
->y
, source
->x
) / 2;
1248 target
->y
= mag
* sin(theta
);
1249 target
->x
= mag
* cos(theta
);
1251 } /* End Complex_Sqrt() */
1253 /* rz=Arcsin(z)=-i*Log{i*z+sqrt(1-z*z)} */
1254 void Complex_ASin(CMPLX
*target
, CMPLX
*source
)
1256 CMPLX tempz1
,tempz2
;
1258 Complex_Mult(&tempz1
, source
, source
);
1259 tempz1
.x
= 1 - tempz1
.x
; tempz1
.y
= -tempz1
.y
;
1260 Complex_Sqrt( &tempz1
, &tempz1
);
1262 tempz2
.x
= -source
->y
; tempz2
.y
= source
->x
;
1263 tempz1
.x
+= tempz2
.x
; tempz1
.y
+= tempz2
.y
;
1265 Complex_Log( &tempz1
, &tempz1
);
1266 target
->x
= tempz1
.y
; target
->y
= -tempz1
.x
;
1267 } /* End Complex_ASin() */
1270 void Complex_ACos(CMPLX
*target
, CMPLX
*source
)
1274 Complex_Mult(&temp
, source
, source
);
1276 Complex_Sqrt(&temp
, &temp
);
1278 temp
.x
+= source
->x
; temp
.y
+= source
->y
;
1280 Complex_Log(&temp
, &temp
);
1281 target
->x
= temp
.y
; target
->y
= -temp
.x
;
1282 } /* End Complex_ACos() */
1284 void Complex_ASinh(CMPLX
*target
, CMPLX
*source
)
1288 Complex_Mult (&temp
, source
, source
);
1290 Complex_Sqrt (&temp
, &temp
);
1291 temp
.x
+= source
->x
; temp
.y
+= source
->y
;
1292 Complex_Log(target
, &temp
);
1293 } /* End Complex_ASinh */
1295 /* rz=Arccosh(z)=Log(z+sqrt(z*z-1)} */
1296 void Complex_ACosh (CMPLX
*target
, CMPLX
*source
)
1299 Complex_Mult(&tempz
, source
, source
);
1301 Complex_Sqrt (&tempz
, &tempz
);
1302 tempz
.x
= source
->x
+ tempz
.x
; tempz
.y
= source
->y
+ tempz
.y
;
1303 Complex_Log (target
, &tempz
);
1304 } /* End Complex_ACosh() */
1306 /* rz=Arctanh(z)=1/2*Log{(1+z)/(1-z)} */
1307 void Complex_ATanh(CMPLX
*target
, CMPLX
*source
)
1309 CMPLX temp0
,temp1
,temp2
;
1311 if( source
->x
== 0.0)
1314 target
->y
= atan( source
->y
);
1319 if( fabs(source
->x
) == 1.0 && source
->y
== 0.0)
1323 else if( fabs( source
->x
) < 1.0 && source
->y
== 0.0)
1325 target
->x
= log((1+source
->x
)/(1-source
->x
))/2;
1331 temp0
.x
= 1 + source
->x
; temp0
.y
= source
->y
;
1332 temp1
.x
= 1 - source
->x
; temp1
.y
= -source
->y
;
1333 Complex_Div(&temp2
, &temp0
, &temp1
);
1334 Complex_Log(&temp2
, &temp2
);
1335 target
->x
= .5 * temp2
.x
; target
->y
= .5 * temp2
.y
;
1339 } /* End Complex_ATanh() */
1341 /* rz=Arctan(z)=i/2*Log{(1-i*z)/(1+i*z)} */
1342 void Complex_ATan(CMPLX
*target
, CMPLX
*source
)
1344 CMPLX temp0
,temp1
,temp2
,temp3
;
1345 if( source
->x
== 0.0 && source
->y
== 0.0)
1346 target
->x
= target
->y
= 0;
1347 else if( source
->x
!= 0.0 && source
->y
== 0.0){
1348 target
->x
= atan(source
->x
);
1351 else if( source
->x
== 0.0 && source
->y
!= 0.0){
1352 temp0
.x
= source
->y
; temp0
.y
= 0.0;
1353 Complex_ATanh(&temp0
, &temp0
);
1354 target
->x
= -temp0
.y
; target
->y
= temp0
.x
;
1356 else if( source
->x
!= 0.0 && source
->y
!= 0.0)
1358 temp0
.x
= -source
->y
; temp0
.y
= source
->x
;
1359 temp1
.x
= 1 - temp0
.x
; temp1
.y
= -temp0
.y
;
1360 temp2
.x
= 1 + temp0
.x
; temp2
.y
= temp0
.y
;
1362 Complex_Div(&temp3
, &temp1
, &temp2
);
1363 Complex_Log(&temp3
, &temp3
);
1364 target
->x
= -temp3
.y
* .5; target
->y
= .5 * temp3
.x
;
1366 } /* End Complex_ATanz() */
1368 void Complex_Tan(CMPLX
*target
, CMPLX
*source
)
1370 DBL x
, y
, sinx
, cosx
, sinhy
, coshy
, denom
;
1373 sinx
= sin(x
); cosx
= cos(x
);
1374 sinhy
= sinh(y
); coshy
= cosh(y
);
1375 denom
= cosx
+ coshy
;
1378 target
->x
= sinx
/denom
;
1379 target
->y
= sinhy
/denom
;
1380 } /* End Complex_Tan() */
1382 void Complex_Tanh(CMPLX
*target
, CMPLX
*source
)
1384 DBL x
, y
, siny
, cosy
, sinhx
, coshx
, denom
;
1387 siny
= sin(y
); cosy
= cos(y
);
1388 sinhx
= sinh(x
); coshx
= cosh(x
);
1389 denom
= coshx
+ cosy
;
1392 target
->x
= sinhx
/denom
;
1393 target
->y
= siny
/denom
;
1394 } /* End Complex_Tanh() */
1397 void Complex_Power (CMPLX
*target
, CMPLX
*source1
, CMPLX
*source2
)
1402 if(source1
->x
== 0 && source1
->y
== 0)
1404 target
->x
= target
->y
= 0.0;
1408 Complex_Log (&cLog
, source1
);
1409 Complex_Mult (&t
, &cLog
, source2
);
1415 target
->x
= e2x
* cos(t
.y
);
1416 target
->y
= e2x
* sin(t
.y
);
1420 void Complex_Pwr (CMPLX
*target
, CMPLX
*source
)
1422 Complex_Power(target
, source
, &exponent
);
1426 void Complex_Pwr (CMPLX
*target
, CMPLX
*source
)
1428 /* the sqr dunction for testing */
1429 Complex_Mult(target
, source
, source
);