예제 #1
0
        //here we go, thats the method called by vvvv each frame
        //all data handling should be in here
        public void Evaluate(int SpreadMax)
        {
            //if any of the inputs has changed
            //recompute the outputs
            if (
                FInput.PinIsChanged ||
                FRadius.PinIsChanged ||
                FFactor.PinIsChanged ||
                FSpreadCount.PinIsChanged
                )
            {
                List <Vector3D> outVec = new List <Vector3D>();
                double          curXSlice, curYSlice, curZSlice, xPos, yPos, zPos;
                double          tmpSize, currentRadius, currentFactor;
                int             currentBinSize = 0, myIncrement = 0;

                double dlong, l, dz, z, r;                  //part of the formula

                dlong = Math.PI * (3 - Math.Sqrt(5.0));     //part of the formula


                FOutput.SliceCount = 0;

                //loop for maximal spread count
                for (int i = 0; i < SpreadMax; i++)
                {
                    FInput.GetValue3D(i, out curXSlice, out curYSlice, out curZSlice);
                    FRadius.GetValue(i, out currentRadius);
                    FFactor.GetValue(i, out currentFactor);
                    FSpreadCount.GetValue(i, out tmpSize);

                    currentBinSize = (int)Math.Round(tmpSize);                  //use spreadcount as an integer

                    dz = (currentFactor * 2.0) / currentBinSize;                //part of the formula
                    z  = 1.0 - dz / 2.0;                                        //part of the formula
                    l  = 0.0;                                                   //part of the formula

                    //loop for each bin size
                    for (int j = 0; j < currentBinSize; j++)
                    {
                        r    = Math.Sqrt(1.0 - z * z);
                        xPos = Math.Cos(l) * r * currentRadius;
                        yPos = Math.Sin(l) * r * currentRadius;
                        zPos = z * currentRadius;

                        z = z - dz;
                        l = l + dlong;

                        //set output
                        outVec.Add(new Vector3D(xPos + curXSlice, yPos + curYSlice, zPos + curZSlice));
                    }
                    myIncrement += currentBinSize;
                }
                FOutput.SliceCount = outVec.Count;
                for (int i = 0; i < outVec.Count; i++)
                {
                    FOutput.SetValue3D(i, outVec[i].x, outVec[i].y, outVec[i].z);
                }
            }
        }
예제 #2
0
        //here we go, thats the method called by vvvv each frame
        //all data handling should be in here
        public void Evaluate(int SpreadMax)
        {
            /* originally it was
             * int sliceCount = VMath.Binomial(FMyValueInput.SliceCount, 2)*2;
             * but this algorithm is better
             */
            int sliceCount = 0;

            for (int i = 1; i < FMyValueInput.SliceCount; i++)
            {
                sliceCount += i;
            }
            sliceCount *= 2;
            //FHost.Log(TLogType.Debug, "sliceCount = " + sliceCount);

            //if any of the inputs has changed
            //recompute the outputs
            if (FMyValueInput.PinIsChanged)
            {
                FMyValueOutput.SliceCount = sliceCount;

                double x1, y1, z1, x2, y2, z2;
                int    counter = 0;

                //loop for all slices
                for (int i = 0; i < FMyValueInput.SliceCount; i++)
                {
                    //read data from inputs
                    FMyValueInput.GetValue3D(i, out x1, out y1, out z1);

                    for (int j = i + 1; j < FMyValueInput.SliceCount; j++)
                    {
                        FMyValueOutput.SetValue3D(counter, x1, y1, z1);
                        counter++;

                        FMyValueInput.GetValue3D(j, out x2, out y2, out z2);

                        FMyValueOutput.SetValue3D(counter, x2, y2, z2);
                        counter++;
                    }
                }
            }
        }
예제 #3
0
파일: Trilerp.cs 프로젝트: vnmone/vvvv-sdk
        //here we go, thats the method called by vvvv each frame
        //all data handling should be in here
        public void Evaluate(int SpreadMax)
        {
            //if any of the inputs has changed
            //recompute the outputs
            if (FPositionInput.PinIsChanged || FVectorSizeInput.PinIsChanged ||
                FV010Input.PinIsChanged || FV110Input.PinIsChanged || FV100Input.PinIsChanged || FV000Input.PinIsChanged ||
                FV011Input.PinIsChanged || FV111Input.PinIsChanged || FV101Input.PinIsChanged || FV001Input.PinIsChanged)
            {
                //get vector size
                double vs;
                FVectorSizeInput.GetValue(0, out vs);
                int vectorSize = (int)vs;

                SpreadMax = Math.Max(SpreadMax, FPositionInput.SliceCount * vectorSize);

                //first set slicecounts for all outputs
                //the incoming int SpreadMax is the maximum slicecount of all input pins, which is a good default
                FPositionOutput.SliceCount = SpreadMax;


                //the variables to fill with the input data
                Vector3D vectorSlice;
                double   V010Slice;
                double   V110Slice;
                double   V100Slice;
                double   V000Slice;
                double   V011Slice;
                double   V111Slice;
                double   V101Slice;
                double   V001Slice;

                //loop for all slices
                for (int i = 0; i < SpreadMax; i++)
                {
                    //read data from inputs
                    FPositionInput.GetValue3D(i / vectorSize, out vectorSlice.x, out vectorSlice.y, out vectorSlice.z);
                    FV010Input.GetValue(i, out V010Slice);
                    FV110Input.GetValue(i, out V110Slice);
                    FV100Input.GetValue(i, out V100Slice);
                    FV000Input.GetValue(i, out V000Slice);
                    FV011Input.GetValue(i, out V011Slice);
                    FV111Input.GetValue(i, out V111Slice);
                    FV101Input.GetValue(i, out V101Slice);
                    FV001Input.GetValue(i, out V001Slice);

                    //function per slice
                    V000Slice = VMath.Trilerp(vectorSlice, V010Slice, V110Slice, V100Slice, V000Slice,
                                              V011Slice, V111Slice, V101Slice, V001Slice);

                    //write data to outputs
                    FPositionOutput.SetValue(i, V000Slice);
                }
            }
        }
예제 #4
0
        //here we go, thats the method called by vvvv each frame
        //all data handling should be in here
        public void Evaluate(int SpreadMax)
        {
            //if any of the inputs has changed
            //recompute the outputs
            if (FPinInVertices.PinIsChanged || FPinInCenter.PinIsChanged || FPinInRadius.PinIsChanged)
            {
                /*
                 * FHost.Log(TLogType.Debug, "FPinInVertices.SliceCount " + FPinInVertices.SliceCount);
                 * FHost.Log(TLogType.Debug, "FPinInCenter.SliceCount " + FPinInCenter.SliceCount);
                 * FHost.Log(TLogType.Debug, "FPinInRadius.SliceCount " + FPinInRadius.SliceCount);
                 */
                FPinOutVertices.SliceCount = FPinInVertices.SliceCount * FPinInCenter.SliceCount * FPinInRadius.SliceCount;
                int    index = 0;
                double pointX, pointY, pointZ;
                double radius;
                double centerX, centerY, centerZ;
                double inversionFactor;

                //loop for all slices
                for (int i = 0; i < FPinInVertices.SliceCount; i++)
                {
                    FPinInVertices.GetValue3D(i, out pointX, out pointY, out pointZ);
                    for (int j = 0; j < FPinInCenter.SliceCount; j++)
                    {
                        FPinInCenter.GetValue3D(j, out centerX, out centerY, out centerZ);
                        pointX -= centerX;
                        pointY -= centerY;
                        pointZ -= centerZ;

                        for (int k = 0; k < FPinInRadius.SliceCount; k++)
                        {
                            FPinInRadius.GetValue(k, out radius);
                            inversionFactor = radius * radius / (pointX * pointX + pointY * pointY + pointZ * pointZ);
                            pointX         *= inversionFactor;
                            pointY         *= inversionFactor;
                            pointZ         *= inversionFactor;

                            pointX += centerX;
                            pointY += centerY;
                            pointZ += centerZ;

                            FPinOutVertices.SetValue3D(index, pointX, pointY, pointZ);
                            index++;
                        }
                    }
                }
            }
        }
예제 #5
0
        //here we go, thats the method called by vvvv each frame
        //all data handling should be in here
        public void Evaluate(int SpreadMax)
        {
            //if any of the inputs has changed
            //recompute the outputs
            if (FPositionInput.PinIsChanged || FOctavesInput.PinIsChanged ||
                FFrequencyInput.PinIsChanged || FPersistanceInput.PinIsChanged)
            {
                //first set slicecounts for all outputs
                //the incoming int SpreadMax is the maximum slicecount of all input pins, which is a good default
                FOutput.SliceCount = SpreadMax;

                double octaves, freq, pers;
                FOctavesInput.GetValue(0, out octaves);
                FFrequencyInput.GetValue(0, out freq);
                FPersistanceInput.GetValue(0, out pers);

                //the variable to fill with the input position
                Vector3D pos;

                //loop for all slices
                for (int i = 0; i < SpreadMax; i++)
                {
                    //read position from inputs
                    FPositionInput.GetValue3D(i, out pos.x, out pos.y, out pos.z);

                    //noise function per slice
                    double noiseVal = 0;

                    for (int o = 0; o <= (int)octaves; o++)
                    {
                        double comul = Math.Pow(freq, o);
                        noiseVal += SimplexNoise.noise(pos.x * comul, pos.y * comul, pos.z * comul) * Math.Pow(pers, o);
                    }

                    //write data to outputs
                    FOutput.SetValue(i, noiseVal);
                }
            }
        }
예제 #6
0
        public void Evaluate(int SpreadMax)
        {
            //calc input spreadcount
            int inputSpreadCount = SpreadMax;

            //create or delete systems
            int diff = inputSpreadCount - FParticleSystemsList.Count;

            if (diff > 0)
            {
                for (int i = 0; i < diff; i++)
                {
                    FParticleSystemsList.Add(new ParticleSystem());
                }
            }
            else if (diff < 0)
            {
                for (int i = 0; i < -diff; i++)
                {
                    FParticleSystemsList.RemoveAt(FParticleSystemsList.Count - 1 - i);
                }
            }

            //update 3D parameters
            int slice;

            if (FInitPositionsIn.PinIsChanged ||
                FVelDirectionIn.PinIsChanged ||
                FVelDeviationIn.PinIsChanged ||
                FAccDirectionIn.PinIsChanged ||
                FAccDeviationIn.PinIsChanged)
            {
                for (slice = 0; slice < inputSpreadCount; slice++)
                {
                    ParticleSystem ps = (ParticleSystem)FParticleSystemsList[slice];

                    double x, y, z;

                    //update origins
                    FInitPositionsIn.GetValue3D(slice, out x, out y, out z);
                    ps.origin = new Vector3D(x, y, z);

                    //update directions
                    FVelDirectionIn.GetValue3D(slice, out x, out y, out z);
                    ps.direction = new Vector3D(x, y, z);

                    //update deviation
                    FVelDeviationIn.GetValue3D(slice, out x, out y, out z);
                    ps.deviation = new Vector3D(x, y, z);

                    //update acceleration deviation
                    FAccDirectionIn.GetValue3D(slice, out x, out y, out z);
                    ps.accDirection = new Vector3D(x, y, z);

                    //update acceleration deviation
                    FAccDeviationIn.GetValue3D(slice, out x, out y, out z);
                    ps.accDeviation = new Vector3D(x, y, z);
                }
            }

            //update single parameters
            if (FMassIn.PinIsChanged ||
                FMassDeviationIn.PinIsChanged ||
                FLifetimeIn.PinIsChanged ||
                FLifetimeDeviationIn.PinIsChanged ||
                FIsInfluencedIn.PinIsChanged ||
                FInfluenceIn.PinIsChanged ||
                FInfluenceAmountIn.PinIsChanged ||
                FdtIn.PinIsChanged)
            {
                for (slice = 0; slice < inputSpreadCount; slice++)
                {
                    ParticleSystem ps = (ParticleSystem)FParticleSystemsList[slice];

                    double mass, massDeviation;
                    double lifetimeIn, lifetimeDeviation;
                    double isInfluenced, influenceAmount, influences;
                    double dt;

                    FMassIn.GetValue(slice, out mass);
                    FMassDeviationIn.GetValue(slice, out massDeviation);
                    FLifetimeIn.GetValue(slice, out lifetimeIn);
                    FLifetimeDeviationIn.GetValue(slice, out lifetimeDeviation);
                    FIsInfluencedIn.GetValue(slice, out isInfluenced);
                    FInfluenceAmountIn.GetValue(slice, out influenceAmount);
                    FInfluenceIn.GetValue(slice, out influences);
                    FdtIn.GetValue(slice, out dt);

                    ps.mass              = mass;
                    ps.massDeviation     = massDeviation;
                    ps.lifetime          = lifetimeIn;
                    ps.lifetimeDeviation = lifetimeDeviation;
                    ps.influences        = (influences >= 0.5);
                    ps.isInfluenced      = (isInfluenced >= 0.5);
                    ps.influenceAmount   = influenceAmount;
                    ps.dt = dt;
                }
            }

            //force calculation
            UpdateForce();


            // Cycle through all particle systems, run them and get particle counts
            FSpreadCountsOut.SliceCount = FParticleSystemsList.Count;
            int outcount = 0;

            slice = 0;
            for (slice = 0; slice < inputSpreadCount; slice++)
            {
                ParticleSystem ps = (ParticleSystem)FParticleSystemsList[slice];

                //add new particle ?
                double emit;
                FEmitIn.GetValue(slice, out emit);

                if (emit >= 0.5)
                {
                    ps.addParticle();
                }

                //update system
                double time;
                FHost.GetCurrentTime(out time);
                ps.run(0.1);
                FLastTime = time;

                //check particle count
                outcount += ps.particles.Count;
                FSpreadCountsOut.SetValue(slice, ps.particles.Count);
            }


            //write output to pins
            FPosOut.SliceCount     = outcount;
            FAgeOut.SliceCount     = outcount;
            FHeadingOut.SliceCount = outcount;

            slice = 0;
            for (int i = 0; i < inputSpreadCount; i++)
            {
                ParticleSystem ps     = (ParticleSystem)FParticleSystemsList[i];
                int            pcount = ps.particles.Count;

                for (int j = 0; j < pcount; j++)
                {
                    Particle p = (Particle)ps.particles[j];

                    FPosOut.SetValue3D(slice, p.loc.x, p.loc.y, p.loc.z);
                    FHeadingOut.SetValue3D(slice, p.vel.x, p.vel.y, p.vel.z);
                    FAgeOut.SetValue(slice, 1 - p.age());
                    slice++;
                }
            }
        }
예제 #7
0
파일: IKSolver.cs 프로젝트: vnmone/vvvv-sdk
        //here we go, thats the method called by vvvv each frame
        //all data handling should be in here
        public void Evaluate(int SpreadMax)
        {
            //if any of the inputs has changed
            //recompute the outputs
            bool recalculate            = false;
            bool chainRangeChanged      = false;
            bool recalculateOrientation = false;

            if (FChainStart.PinIsChanged)
            {
                FChainStart.GetString(0, out chainStart);
                recalculate       = true;
                chainRangeChanged = true;
            }

            if (FChainEnd.PinIsChanged)
            {
                FChainEnd.GetString(0, out chainEnd);
                recalculate       = true;
                chainRangeChanged = true;
            }

            object currInterface;

            if (FPoseInput.PinIsChanged || chainRangeChanged)
            {
                if (FPoseInput.IsConnected)
                {
                    FPoseInput.GetUpstreamInterface(out currInterface);
                    Skeleton s = (Skeleton)currInterface;
                    if (outputSkeleton == null || !s.Uid.Equals(outputSkeleton.Uid))
                    {
                        outputSkeleton = (Skeleton)((Skeleton)currInterface).DeepCopy();
                        outputSkeleton.BuildJointTable();
                        workingSkeleton = (Skeleton)outputSkeleton.DeepCopy();
                        workingSkeleton.BuildJointTable();
                        chainRangeChanged = true;
                    }
                    else
                    {
                        foreach (KeyValuePair <string, IJoint> pair in s.JointTable)
                        {
                            if (!jointChain.Exists(delegate(IJoint j) { return(j.Name == pair.Key); }))
                            {
                                outputSkeleton.JointTable[pair.Key].BaseTransform       = pair.Value.BaseTransform;
                                outputSkeleton.JointTable[pair.Key].AnimationTransform  = pair.Value.AnimationTransform;
                                workingSkeleton.JointTable[pair.Key].BaseTransform      = pair.Value.BaseTransform;
                                workingSkeleton.JointTable[pair.Key].AnimationTransform = pair.Value.AnimationTransform;
                            }
                            outputSkeleton.JointTable[pair.Key].Constraints  = pair.Value.Constraints;
                            workingSkeleton.JointTable[pair.Key].Constraints = pair.Value.Constraints;
                        }
                    }
                    workingSkeleton.CalculateCombinedTransforms();
                    recalculate = true;
                }
                else
                {
                    outputSkeleton = null;
                }
            }

            if (FVelocityInput.PinIsChanged)
            {
                double x;
                FVelocityInput.GetValue(0, out x);
                iterationsPerFrame = (int)(x * 10);
            }

            if (iterationsPerFrame > 0)
            {
                if (FTargetInput.PinIsChanged)
                {
                    targetPosW = new Vector3D();
                    FTargetInput.GetValue3D(0, out targetPosW.x, out targetPosW.y, out targetPosW.z);
                    recalculate = true;
                }

                if (FEpsilonInput.PinIsChanged)
                {
                    FEpsilonInput.GetValue(0, out epsilon);
                    recalculate = true;
                }

                if (FPoleTargetInput.PinIsChanged || FEnablePoleTargetInput.PinIsChanged)
                {
                    double x;
                    FEnablePoleTargetInput.GetValue(0, out x);
                    enablePoleTarget = x > 0.0;
                    poleTargetW      = new Vector3D();
                    FPoleTargetInput.GetValue3D(0, out poleTargetW.x, out poleTargetW.y, out poleTargetW.z);
                    recalculateOrientation = true;
                }

                if (chainRangeChanged && outputSkeleton != null)
                {
                    initRotations();
                }

                double delta = VMath.Dist(endPosW, targetPosW);
                if ((delta > epsilon || recalculate) && outputSkeleton != null && !string.IsNullOrEmpty(chainStart) && !string.IsNullOrEmpty(chainEnd))
                {
                    List <Vector2D> constraints = new List <Vector2D>();
                    for (int i = 0; i < iterationsPerFrame; i++)
                    {
                        for (int j = 0; j < 3; j++)
                        {
                            IJoint currJoint = workingSkeleton.JointTable[chainEnd];
                            endPosW = currJoint.CombinedTransform * new Vector3D(0);
                            while (currJoint.Name != chainStart)
                            {
                                currJoint = currJoint.Parent;
                                Vector3D rotationAxis = new Vector3D(0, 0, 0);
                                rotationAxis[j] = 1;
                                double   torque = calculateTorque(currJoint, rotationAxis);
                                Vector3D rot    = rotations[currJoint.Name];
                                if ((rot[j] + torque) < currJoint.Constraints[j].x * 2 * Math.PI || (rot[j] + torque) > currJoint.Constraints[j].y * 2 * Math.PI)
                                {
                                    torque = 0;
                                }
                                Matrix4x4 newTransform = VMath.Rotate(torque * rotationAxis.x, torque * rotationAxis.y, torque * rotationAxis.z) * currJoint.AnimationTransform;
                                Vector3D  testVec      = newTransform * new Vector3D(0);
                                if (!Double.IsInfinity(testVec.x) && !Double.IsNaN(testVec.x))                         // an evil bug fix, to avoid n.def. values in animation transform matrix. the actual reason, why this would happen has not been found yet.
                                {
                                    rot[j] += torque;
                                    rotations[currJoint.Name]    = rot;
                                    currJoint.AnimationTransform = newTransform;
                                    outputSkeleton.JointTable[currJoint.Name].AnimationTransform = currJoint.AnimationTransform;
                                }
                            }
                        }
                        try
                        {
                            Matrix4x4 pre;
                            if (workingSkeleton.JointTable[chainStart].Parent != null)
                            {
                                pre = workingSkeleton.JointTable[chainStart].Parent.CombinedTransform;
                            }
                            else
                            {
                                pre = VMath.IdentityMatrix;
                            }
                            ((JointInfo)workingSkeleton.JointTable[chainStart]).CalculateCombinedTransforms(pre);
                        }
                        catch (Exception)
                        {
                            workingSkeleton.CalculateCombinedTransforms();
                        }
                    }


                    FPoseOutput.MarkPinAsChanged();
                }

                if ((recalculate || recalculateOrientation) && enablePoleTarget && outputSkeleton != null && !string.IsNullOrEmpty(chainStart) && !string.IsNullOrEmpty(chainEnd))
                {
                    endPosW = workingSkeleton.JointTable[chainEnd].CombinedTransform * new Vector3D(0);
                    Vector3D poleTargetLocal = VMath.Inverse(workingSkeleton.JointTable[chainStart].CombinedTransform) * poleTargetW;
                    Vector3D t = VMath.Inverse(workingSkeleton.JointTable[chainStart].CombinedTransform) * endPosW;                                                                                  // endpoint in local coords
                    Vector3D a = VMath.Inverse(workingSkeleton.JointTable[chainStart].CombinedTransform) * (workingSkeleton.JointTable[chainStart].Children[0].CombinedTransform * new Vector3D(0)); // next child in local coords
                    Vector3D x = t * ((a.x * t.x + a.y * t.y + a.z * t.z) / Math.Pow(VMath.Dist(new Vector3D(0), t), 2));
                    Vector3D y = t * ((poleTargetLocal.x * t.x + poleTargetLocal.y * t.y + poleTargetLocal.z * t.z) / Math.Pow(VMath.Dist(new Vector3D(0), t), 2));

                    Vector3D c     = poleTargetLocal - y;
                    Vector3D b     = a - x;
                    double   angle = vectorAngle(b, c);
                    Vector3D n     = new Vector3D();
                    n.x = c.y * b.z - c.z * b.y;
                    n.y = c.z * b.x - c.x * b.z;
                    n.z = c.x * b.y - c.y * b.x;
                    n   = n / VMath.Dist(new Vector3D(0), n);
                    FDebugOutput.SetValue(0, angle);
                    chainRotation = RotateAroundAxis(angle, n);

                    FPoseOutput.MarkPinAsChanged();
                }
                if (!enablePoleTarget)
                {
                    chainRotation = VMath.IdentityMatrix;
                }

                outputSkeleton.JointTable[chainStart].AnimationTransform = chainRotation * outputSkeleton.JointTable[chainStart].AnimationTransform;
            }

            FPoseOutput.SetInterface(outputSkeleton);
        }
예제 #8
0
        //here we go, thats the method called by vvvv each frame
        //all data handling should be in here
        public void Evaluate(int SpreadMax)
        {
            //if any of the inputs has changed
            //recompute the outputs

            FP1.SliceCount            = SpreadMax;
            FP2.SliceCount            = SpreadMax;
            FIntersections.SliceCount = SpreadMax;

            for (int i = 0; i < SpreadMax; i++)
            {
                double Ax, Ay, Az;
                double Bx, By, Bz;
                double Cx, Cy, Cz;

                FA.GetValue3D(0, out Ax, out Ay, out Az);
                FB.GetValue3D(0, out Bx, out By, out Bz);
                FC.GetValue3D(0, out Cx, out Cy, out Cz);

                double r_a, r_b, r_c;

                FRA.GetValue(i, out r_a);
                FRB.GetValue(i, out r_b);
                FRC.GetValue(i, out r_c);

                double P1x = 0, P1y = 0, P1z = 0;
                double P2x = 0, P2y = 0, P2z = 0;

                double Asquare = Math.Pow(Ax, 2) + Math.Pow(Ay, 2) + Math.Pow(Az, 2);
                double Bsquare = Math.Pow(Bx, 2) + Math.Pow(By, 2) + Math.Pow(Bz, 2);
                double Csquare = Math.Pow(Cx, 2) + Math.Pow(Cy, 2) + Math.Pow(Cz, 2);

                double ABx = Bx - Ax;
                double ABy = By - Ay;
                double ABz = Bz - Az;

                double ACx = Cx - Ax;
                double ACy = Cy - Ay;
                double ACz = Cz - Az;

                double m = (Math.Pow(r_a, 2) - Math.Pow(r_b, 2) - Asquare + Bsquare) * ACz;
                double n = (Math.Pow(r_a, 2) - Math.Pow(r_c, 2) - Asquare + Csquare) * ABz;
                double o = ABy * ACz - ACy * ABz;
                double q = ACx * ABz - ABx * ACz;

                double v = (Math.Pow(r_a, 2) - Math.Pow(r_b, 2) - Asquare + Bsquare) / (2 * ABz) - Az;
                double w = (1 + Math.Pow(ABy, 2) / Math.Pow(ABz, 2));

                double r = ABx / ABz;
                double s = ABy / ABz;

                double t = Math.Pow(Ax, 2) + Math.Pow(Ay, 2) + Math.Pow(v, 2) - Math.Pow(r_a, 2);
                double a = (m - n) / (2 * o);
                double b = q / o;

                //(1+r^2+b^2*w+2brs)P.x^2 + (2abw+2ars-2A.x-2rv-2b(A.y + sv))P.x + w*a^2 - 2a(A.y + sv) + t = 0

                int solutions;
                QuadraticEquation(1 + Math.Pow(r, 2) + Math.Pow(b, 2) * w + 2 * b * r * s,
                                  2 * a * b * w + 2 * a * r * s - 2 * Ax - 2 * r * v - 2 * b * (Ay + s * v),
                                  w * Math.Pow(a, 2) - 2 * a * (Ay + s * v) + t,
                                  out P1x, out P2x, out solutions);

                FIntersections.SetValue(i, solutions);

                P1y = P1x * b + a;
                //P.z = (r_a^2 - r_b^2 - 2*P.x*AB.x - 2*P.y*AB.y - |A|^2 + |B|^2) / (2*AB.z)
                P1z = (Math.Pow(r_a, 2) - Math.Pow(r_b, 2) - 2 * P1x * ABx - 2 * P1y * ABy - Asquare + Bsquare) / (2 * ABz);

                P2y = P2x * b + a;
                P2z = (Math.Pow(r_a, 2) - Math.Pow(r_b, 2) - 2 * P2x * ABx - 2 * P2y * ABy - Asquare + Bsquare) / (2 * ABz);

                FP1.SetValue3D(i, P1x, P1y, P1z);
                FP2.SetValue3D(i, P2x, P2y, P2z);
            }
        }