public override void Absorb(ref OctaveRay Ray, out double cos_theta, Hare.Geometry.Vector Normal)
            {
                cos_theta = Hare.Geometry.Hare_math.Dot(Ray.direction, Normal);
                int index = 18 - (int)Math.Round(Math.Acos(Math.Abs(cos_theta)) / angle_incr);

                Ray.Intensity *= (1 - Ang_Coef_Oct[Ray.Octave][index]);
            }
            /// <summary>
            /// Creats an octave ray for the specified octave with the percentage of the Broadray's energy specified by the scattering coeficient.
            /// </summary>
            /// <param name="Octave"></param>
            /// <param name="Scattering_Coef"></param>
            /// <returns></returns>
            public OctaveRay SplitRay(int Octave, double E_Mod_Coef)
            {
                OctaveRay O = new OctaveRay(origin, direction, Ray_ID, ThreadID, Energy[Octave] * E_Mod_Coef, phase[Octave], t_sum, Octave, Source_ID, Surf_ID);

                this.Energy[Octave] *= (1 - E_Mod_Coef);
                return(O);
            }
            /// <summary>
            /// Creates an octave ray for the specified octave. After this operation, the Broadray will no longer trace this octave.
            /// </summary>
            /// <param name="Octave"></param>
            /// <returns></returns>
            public OctaveRay SplitRay(int Octave)
            {
                OctaveRay O = new OctaveRay(origin, direction, Ray_ID, ThreadID, Energy[Octave], phase[Octave], t_sum, Octave, Source_ID, Surf_ID);

                this.Energy[Octave] = 0;
                return(O);
            }
            /// <summary>
            /// Creats an octave ray with the percentage of the parent ray's energy specified by the scattering coeficient. Duely modifies the parent ray.
            /// </summary>
            /// <param name="E_Mod_Coef"></param>
            /// <param name="phase_delay"></param>
            /// <returns></returns>
            public OctaveRay SplitRay(double E_Mod_Coef, double phase_delay)
            {
                OctaveRay O = new OctaveRay(origin, direction, Ray_ID, ThreadID, Intensity * E_Mod_Coef, t_sum, Octave, Source_ID, Surf_ID);

                this.Intensity *= (1 - E_Mod_Coef);
                return(O);
            }
 /// <summary>
 /// Creates an octave ray with the percentage of the parent ray's energy specified by the scattering coeficient. Duely modifies the parent ray.
 /// </summary>
 /// <param name="E_Mod_Coef"></param>
 /// <returns></returns>
 public OctaveRay SplitRay( double E_Mod_Coef)
 {
     OctaveRay O = new OctaveRay(origin, direction, Ray_ID, ThreadID, Intensity * E_Mod_Coef, phase, t_sum, Octave, Source_ID, Surf_ID);
     //O.Surf_ID = Surf_ID;
     this.Intensity *= (1 - E_Mod_Coef);
     return O;
 }
            public override void Absorb(ref OctaveRay Ray, out double cos_theta, Hare.Geometry.Vector Normal)
            {
                cos_theta = Hare.Geometry.Hare_math.Dot(Normal, Ray.direction);

                Ray.Intensity *= (Ref[Ray.Octave]);
                Ray.phase     += PD[Ray.Octave];
            }
            public override void Scatter_VeryLate(ref OctaveRay Ray, ref Random rand, Hare.Geometry.Vector Normal, double Cos_Theta)
            {
                if (rand.NextDouble() < Scattering_Coefficient[Ray.Octave, 1])
                {
                    Hare.Geometry.Vector diffx;
                    Hare.Geometry.Vector diffy;
                    Hare.Geometry.Vector diffz;
                    double proj;
                    //Check that the ray and the normal are both on the same side...
                    if (Cos_Theta > 0)
                    {
                        Normal *= -1;
                    }
                    diffz = Normal;
                    diffx = new Hare.Geometry.Vector(0, 0, 1);
                    proj  = Math.Abs(Hare.Geometry.Hare_math.Dot(diffz, diffx));

                    if (0.99 < proj && 1.01 > proj)
                    {
                        diffx = new Hare.Geometry.Vector(1, 0, 0);
                    }
                    diffy = Hare.Geometry.Hare_math.Cross(diffz, diffx);
                    diffx = Hare.Geometry.Hare_math.Cross(diffy, diffz);
                    diffx.Normalize();
                    diffy.Normalize();
                    diffz.Normalize();

                    double u1;
                    double u2;
                    double x;
                    double y;
                    double z;
                    Hare.Geometry.Vector vect;
                    u1 = 2.0 * Math.PI * rand.NextDouble();
                    // random azimuth
                    double Scat_Mod = rand.NextDouble();
                    u2 = Math.Acos(Scat_Mod);
                    // random zenith (elevation)
                    x = Math.Cos(u1) * Math.Sin(u2);
                    y = Math.Sin(u1) * Math.Sin(u2);
                    z = Math.Cos(u2);

                    vect = (diffx * x) + (diffy * y) + (diffz * z);
                    vect.Normalize();

                    //Return the new direction
                    Ray.direction = vect;
                }
                else
                {
                    //Specular Reflection
                    Ray.direction -= Normal * Cos_Theta * 2;
                }
            }
            public override void Absorb(ref OctaveRay Ray, Hare.Geometry.Vector Normal)
            {
                Ray.direction.Normalize();
                int Alt = (int)Math.Floor((Math.Acos(Hare.Geometry.Hare_math.Dot(Ray.direction, new Hare.Geometry.Vector(0, 0, -1))) * Altitude.Length) / (Math.PI / 2));

                if (Alt >= Altitude.Length / 2)
                {
                    Alt = Altitude.Length - 1;
                }
                int Azi = (int)Math.Round((Math.Atan2(Ray.direction.y, Ray.direction.x) * Azimuth.Length) / Math.PI);

                if (Ray.direction.y < 0 && Azi < Azimuth.Length / 2)
                {
                    Azi = Azimuth.Length - Math.Abs(Azi);
                }
                Ray.Intensity *= alpha[Alt][Azi][Ray.Octave];
            }
            /// <summary>
            /// Checks receiver for an intersection with a ray 
            /// </summary>
            /// <param name="Length">The length of the ray at the reflection point before potential intersection</param>
            /// <param name="R">the ray.</param>
            /// <param name="EndPt">The point at which the ray intersects the model after potential receiver intersection.</param>
            public override void CheckRay(OctaveRay R, Hare.Geometry.Point EndPt)
            {
                double Radius = (R.t_sum * C_Sound) * Math.Sqrt(6.28 / (RayCount));
                double Radius2 = Radius * Radius;
                Vector m = R.origin - H_Origin;
                double RayLength = (EndPt - R.origin).Length();
                Vector d = (EndPt - R.origin) / RayLength;
                double b = Hare_math.Dot(m, d);
                double c = Hare_math.Dot(m, m) - (Radius2);
                if (c > 0 && b > 0) return;
                double discr = b * b - c;
                if (discr < 0) return;
                double t1 = -b - Math.Sqrt(discr);
                double t2 = -b + Math.Sqrt(discr);
                double t = (t1 + t2) * .5;

                if (t > 0 && t * t < SqDistance(EndPt, R.origin))
                {
                    double Raydist = t * Inv_C_Sound + R.t_sum;
                    double Ei = R.Intensity * Math.Pow(10,-.1 * Atten[R.Octave] * t) / (Math.PI * Radius2);
                    Recs.Add(Raydist, Ei, R.direction * -1, R.phase,Rho_C, R.Octave);
                }
                return;
            }
            public override void Scatter_VeryLate(ref OctaveRay Ray, ref Random rand, Hare.Geometry.Vector Normal, double Cos_Theta)
            {
                if (rand.NextDouble() < Scattering_Coefficient[Ray.Octave, 1])
                {
                    Hare.Geometry.Vector diffx;
                    Hare.Geometry.Vector diffy;
                    Hare.Geometry.Vector diffz;
                    double proj;
                    //Check that the ray and the normal are both on the same side...
                    if (Cos_Theta > 0) Normal *= -1;
                    diffz = Normal;
                    diffx = new Hare.Geometry.Vector(0, 0, 1);
                    proj = Math.Abs(Hare.Geometry.Hare_math.Dot(diffz, diffx));

                    if (0.99 < proj && 1.01 > proj) diffx = new Hare.Geometry.Vector(1, 0, 0);
                    diffy = Hare.Geometry.Hare_math.Cross(diffz, diffx);
                    diffx = Hare.Geometry.Hare_math.Cross(diffy, diffz);
                    diffx.Normalize();
                    diffy.Normalize();
                    diffz.Normalize();

                    double u1;
                    double u2;
                    double x;
                    double y;
                    double z;
                    Hare.Geometry.Vector vect;
                    u1 = 2.0 * Math.PI * rand.NextDouble();
                    // random azimuth
                    double Scat_Mod = rand.NextDouble();
                    u2 = Math.Acos(Scat_Mod);
                    // random zenith (elevation)
                    x = Math.Cos(u1) * Math.Sin(u2);
                    y = Math.Sin(u1) * Math.Sin(u2);
                    z = Math.Cos(u2);

                    vect = (diffx * x) + (diffy * y) + (diffz * z);
                    vect.Normalize();

                    //Return the new direction
                    Ray.direction = vect;
                }
                else
                {
                    //Specular Reflection
                    Ray.direction -= Normal * Cos_Theta * 2;
                }
            }
 /// <summary>
 /// Checks receiver for an intersection with a ray 
 /// </summary>
 /// <param name="Length">The length of the ray at the reflection point before potential intersection</param>
 /// <param name="R">the ray.</param>
 /// <param name="EndPt">The point at which the ray intersects the model after potential receiver intersection.</param>
 public virtual void CheckRay(OctaveRay R, Hare.Geometry.Point EndPt)
 {
     Vector m = R.origin - H_Origin;
     double b = Hare_math.Dot(m, R.direction);
     double c = Hare_math.Dot(m, m) - Radius2;
     if (c > 0 && b > 0) return;
     double discr = b * b - c;
     if (discr < 0) return;
     double t1 = -b - Math.Sqrt(discr);
     double t2 = -b + Math.Sqrt(discr);
     double tsphere = (t2 - t1) * 0.5;
     double t = (t1 + t2) *.5;
     if (t > 0 && t * t < SqDistance(EndPt, R.origin))
     {
         Vector Dir = R.direction * -1;
         Dir.Normalize();
         double Raydist = t*Inv_C_Sound + R.t_sum;
         Recs.Add(Raydist, R.Intensity * Math.Pow(10,-.1 * Atten[R.Octave] * t) * SizeMod * tsphere, Dir, R.phase, Rho_C, R.Octave);
     }
 }
 public abstract void Absorb(ref OctaveRay Ray, out double cos_theta, double u, double v);
 public abstract void Absorb(ref OctaveRay Ray, out double cos_theta, double u, double v);
 /// <summary>
 /// Creats an octave ray for the specified octave with the percentage of the Broadray's energy specified by the scattering coeficient.
 /// </summary>
 /// <param name="Octave"></param>
 /// <param name="Scattering_Coef"></param>
 /// <returns></returns>
 public OctaveRay SplitRay(int Octave, double E_Mod_Coef)
 {
     OctaveRay O = new OctaveRay(origin, direction, Ray_ID, ThreadID, Energy[Octave] * E_Mod_Coef, phase[Octave],  t_sum, Octave, Source_ID, Surf_ID);
     this.Energy[Octave] *= (1 - E_Mod_Coef);
     return O;
 }
            //private void Construct(List<Rhino.DocObjects.RhinoObject> ObjectList)
            //{
            //    BoundingBox Box = ObjectList[0].Geometry.GetBoundingBox(true);
            //    for (int i = 1; i < ObjectList.Count; i++) Box.Union(ObjectList[i].Geometry.GetBoundingBox(true));

            //    //List<Hare.Geometry.Point[]> FaceList = new List<Hare.Geometry.Point[]>();
            //    //int p = -1;
            //    List<GeometryBase> BList = new List<GeometryBase>();
            //    //List<string> AcousticsData = new List<string>();
                
            //    Brep_ids = new List<int>();

            //    List<Material> Mat_Layer = new List<Material>();
            //    List<Scattering> Scat_Layer = new List<Scattering>();
            //    List<Material> Mat_Obj = new List<Material>();
            //    List<Scattering> Scat_Obj = new List<Scattering>();
            //    List<double[]> Trans_Layer = new List<double[]>();
            //    List<double[]>Trans_Obj = new List<double[]>();
            //    //Organize the geometry into Breps
            //    //Get materials for each layer:
            //    for (int l = 0; l < Rhino.RhinoDoc.ActiveDoc.Layers.Count; l++)
            //    {
            //        Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[l];
            //        string abstype = Layer.GetUserString("ABSType");
            //        if (abstype == "Buildup")
            //        {
            //            string BU = Layer.GetUserString("BuildUp");
            //            string[] BU_split = BU.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            //            List<AbsorptionModels.ABS_Layer> Buildup = new List<AbsorptionModels.ABS_Layer>();
            //            foreach (string swatch in BU_split) Buildup.Add(AbsorptionModels.ABS_Layer.LayerFromCode(swatch));
            //            Mat_Layer.Add(new Environment.Smart_Material(Buildup, 44100, Env_Prop.Rho(0), Env_Prop.Sound_Speed(0), 2));

            //            double[] Abs = new double[8], Scat = new double[8], Trans = new double[8];
            //            Pachyderm_Acoustic.UI.PachydermAc_PlugIn.DecodeAcoustics(Layer.GetUserString("Acoustics"), ref Abs, ref Scat, ref Trans);
            //            ///Other properties are still coefficient based...
            //            Scat_Layer.Add(new Environment.Lambert_Scattering(Scat, SplitRatio));
            //            Trans_Layer.Add(Trans);
            //        }
            //        else
            //        {
            //            string spec = Layer.GetUserString("Acoustics");

            //            if(spec == "")
            //            {
            //                ///Layer is not used. As long as there is no geometry for pachyderm on this layer without object set properties, this is ok.
            //                Mat_Layer.Add(null);
            //                Scat_Layer.Add(null);
            //                Trans_Layer.Add(null);
            //                continue;
            //            }

            //            double[] Abs = new double[8], Scat = new double[8], Trans = new double[8];
            //            Pachyderm_Acoustic.UI.PachydermAc_PlugIn.DecodeAcoustics(spec, ref Abs, ref Scat, ref Trans);
            //            Mat_Layer.Add(new Environment.Basic_Material(Abs, new double[8] { 0, 0, 0, 0, 0, 0, 0, 0 }));
            //            Scat_Layer.Add(new Environment.Lambert_Scattering(Scat, SplitRatio));
            //            Trans_Layer.Add(Trans);
            //        }
            //    }

            //    for (int q = 0; q <= ObjectList.Count - 1; q++)
            //    {
            //        List<Brep> B = new List<Brep>();
            //        if (ObjectList[q].ObjectType == Rhino.DocObjects.ObjectType.Brep)
            //        {
            //            Rhino.DocObjects.BrepObject BObj = ((Rhino.DocObjects.BrepObject)ObjectList[q]);
            //            B.Add(BObj.BrepGeometry.DuplicateBrep());
            //            //string m = ObjectList[q].Geometry.GetUserString("Acoustics_User");
            //            if (ObjectList[q].Geometry.GetUserString("Acoustics_User") == "yes")
            //            {
            //                double[] ABS = new double[8], SCAT = new double[8], TRANS = new double[8];
            //                Pachyderm_Acoustic.UI.PachydermAc_PlugIn.DecodeAcoustics(ObjectList[q].Geometry.GetUserString("Acoustics"), ref ABS, ref SCAT, ref TRANS);
            //                Mat_Obj.Add(new Basic_Material(ABS, new double[]{0,0,0,0,0,0,0,0}));
            //                Scat_Obj.Add(new Lambert_Scattering(SCAT, SplitRatio));
            //                Trans_Obj.Add(TRANS);
            //            }
            //            else
            //            {
            //                //Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[ObjectList[q].Attributes.LayerIndex];
            //                //AcousticsData.Add(Layer.GetUserString("Acoustics"));
            //                Mat_Obj.Add(Mat_Layer[ObjectList[q].Attributes.LayerIndex]);
            //                Scat_Obj.Add(Scat_Layer[ObjectList[q].Attributes.LayerIndex]);
            //                Trans_Obj.Add(Trans_Layer[ObjectList[q].Attributes.LayerIndex]);
            //            }
            //        }
            //        else if (ObjectList[q].ObjectType == Rhino.DocObjects.ObjectType.Extrusion)
            //        {
            //            Rhino.Geometry.Brep BObj = ((Rhino.DocObjects.ExtrusionObject)ObjectList[q]).ExtrusionGeometry.ToBrep();
            //            for (int i = 0; i < BObj.Faces.Count; i++)
            //            {
            //                if (ObjectList[q].Geometry.GetUserString("Acoustics_User") == "yes")
            //                {
            //                    //AcousticsData.Add(ObjectList[q].Geometry.GetUserString("Acoustics"));
            //                    double[] ABS = new double[8], SCAT = new double[8], TRANS = new double[8];
            //                    Pachyderm_Acoustic.UI.PachydermAc_PlugIn.DecodeAcoustics(ObjectList[q].Geometry.GetUserString("Acoustics"), ref ABS, ref SCAT, ref TRANS);
            //                    Mat_Obj.Add(new Basic_Material(ABS, new double[] { 0, 0, 0, 0, 0, 0, 0, 0 }));
            //                    Scat_Obj.Add(new Lambert_Scattering(SCAT, SplitRatio));
            //                    Trans_Obj.Add(TRANS);
            //                }
            //                else
            //                {
            //                    //Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[ObjectList[q].Attributes.LayerIndex];
            //                    //AcousticsData.Add(Layer.GetUserString("Acoustics"));
            //                    //Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[ObjectList[q].Attributes.LayerIndex];
            //                    //AcousticsData.Add(Layer.GetUserString("Acoustics"));
            //                    Mat_Obj.Add(Mat_Layer[ObjectList[q].Attributes.LayerIndex]);
            //                    Scat_Obj.Add(Scat_Layer[ObjectList[q].Attributes.LayerIndex]);
            //                    Trans_Obj.Add(Trans_Layer[ObjectList[q].Attributes.LayerIndex]);
            //                }

            //                //B.Add(BObj.Faces[0].ToBrep());
            //                //for (int i = 1; i < BObj.Faces.Count; i++)
            //                //{
            //                //    if (ObjectList[q].Geometry.GetUserString("Acoustics_User") == "yes")
            //                //    {
            //                //        AcousticsData.Add(ObjectList[q].Geometry.GetUserString("Acoustics"));
            //                //    }
            //                //    else
            //                //    {
            //                //        Rhino.DocObjects.Layer Layer = Rhino.RhinoDoc.ActiveDoc.Layers[ObjectList[q].Attributes.LayerIndex];
            //                //        AcousticsData.Add(Layer.GetUserString("Acoustics"));
            //                //    }
            //                B.Add(BObj.Faces[i].ToBrep());
            //            }
            //        }
            //        else
            //        {
            //            continue;
            //        }
            //        BList.AddRange(B);
            //    }

            //    ////////////////////////////////////////
            //    Topo = new Hare.Geometry.Topology[1];
            //    Topo[0] = new Topology(Utilities.PachTools.RPttoHPt(Box.Min), Utilities.PachTools.RPttoHPt(Box.Max));
            //    ////////////////////////////////////////
            //    for (int q = 0; q < BList.Count; q++)
            //    {
            //        BrepList.Add((Brep)BList[q]);

            //        //Material Abs = null ;
            //        //Scattering Scat = null;

            //        //double[] Transparency = new double[8];
            //        double[] Transmission = new double[8];
                    
            //        //double[] Scat = new double[8];
            //        //if (!string.IsNullOrEmpty(AcousticsData[q]))
            //        //if (Mat_Obj[q] != null)
            //        //{
            //        //    //double[] Absorption = new double[8];
            //        //    //double[] phase = new double[8];
            //        //    //double[] Scattering = new double[8];
            //        //    ////double[,] Scattering = new double[8, 3];
            //        //    //double[] Reflection = new double[8];
            //        //    //UI.PachydermAc_PlugIn.DecodeAcoustics(AcousticsData[q], ref Absorption, ref Scattering, ref Transparency);
            //        //    Abs = Mat_Obj[q];
            //        //    Scat = Scat_Obj[q];
            //        //    Transmission = Trans_Obj[q];
            //        //}
            //        //else
            //        if ((Mat_Obj[q] == null) || (Scat_Obj[q] == null) || (Trans_Obj[q] == null))
            //        {
            //            if (!Custom_Method)
            //            {
            //                Status = System.Windows.Forms.MessageBox.Show("A material is not specified correctly. Please assign absorption and scattering to all layers in the model.", "Materials Error", System.Windows.Forms.MessageBoxButtons.OK);
            //                Complete = false;
            //                return;
            //            }
            //            ///Materails do not need to be specified, as it will not be used for an acoustical simulation... (hopefully...)
            //        }

            //        //for (int i = 0; i < 8; i++)
            //        //{
            //        //    Reflection[i] = (1 - Absorption[i]);
            //        //    Transmission[i] = Transparency[i];
            //        //    Scattering[i, 1] = Scat[i];
            //        //    double Mod = ((Scattering[i, 1] < (1 - Scattering[i, 1])) ? (Scattering[i, 1] * SplitRatio / 2) : ((1 - Scattering[i, 1]) * SplitRatio / 2));
            //        //    Scattering[i, 0] = Scattering[i, 1] - Mod;
            //        //    Scattering[i, 2] = Scattering[i, 1] + Mod;
            //        //    phase[i] = 0;
            //        //}
                    
            //        Mesh[] meshes;
            //        MeshingParameters mp = new MeshingParameters();
            //        mp.MinimumEdgeLength = 0.1;
            //        mp.SimplePlanes = true;
            //        meshes = Rhino.Geometry.Mesh.CreateFromBrep((Brep)BList[q],mp);
            //        if (meshes == null) throw new Exception("Problem with meshes");

            //        for (int t = 0; t < meshes.Length; t++)
            //        {
            //            if (meshes[t].Faces.Count < 1)
            //            {
            //                Status = System.Windows.Forms.MessageBox.Show("A surface in the model does not generate a rendermesh. This surface will not be represented in the simulation. It is recommended that you cancel this simulation and repair the affected surface. It can be located in shaded view by finding the surface which generates boundary and isoparm lines, but does not generate a fill. It can sometimes be repaired by running the command 'ShrinkTrimmedSurface'. If this does not work, it will have to be replaced by some means which would generate a proper surface.", "Surface without Rendermesh", System.Windows.Forms.MessageBoxButtons.OKCancel);
            //                if (Status == System.Windows.Forms.DialogResult.Cancel)
            //                {
            //                    Complete = false;
            //                    return;
            //                }
            //                continue;
            //            }
                     
            //            for (int u = 0; u < meshes[t].Faces.Count; u++)
            //            {
            //                Hare.Geometry.Point[] P;
            //                if (meshes[t].Faces[u].IsQuad)
            //                {
            //                    P = new Hare.Geometry.Point[4];
            //                    Point3f FP = meshes[t].Vertices[meshes[t].Faces[u][0]];
            //                    P[0] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z);
            //                    FP = meshes[t].Vertices[meshes[t].Faces[u][1]];
            //                    P[1] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z);
            //                    FP = meshes[t].Vertices[meshes[t].Faces[u][2]];
            //                    P[2] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z);
            //                    FP = meshes[t].Vertices[meshes[t].Faces[u][3]];
            //                    P[3] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z);
            //                }
            //                else
            //                {
            //                    P = new Hare.Geometry.Point[3];
            //                    Point3f FP = meshes[t].Vertices[meshes[t].Faces[u][0]];
            //                    P[0] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z);
            //                    FP = meshes[t].Vertices[meshes[t].Faces[u][1]];
            //                    P[1] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z);
            //                    FP = meshes[t].Vertices[meshes[t].Faces[u][2]];
            //                    P[2] = new Hare.Geometry.Point(FP.X, FP.Y, FP.Z);
            //                }

            //                //ReflectionData.Add(Reflection);
            //                AbsorptionData.Add(Mat_Obj[q]);
            //                ScatteringData.Add(Scat_Obj[q]);
            //                TransmissionData.Add(Trans_Obj[q]);
            //                //PhaseData.Add(phase);

            //                bool Trans = false;
            //                for (int t_oct = 0; t_oct < 8; t_oct++)
            //                {
            //                    if (Transmission[t_oct] > 0)
            //                    {
            //                        Trans = true;
            //                        break;
            //                    }
            //                }
            //                Transmissive.Add(Trans);
            //                if (BrepList[q].Faces[t].IsPlanar())
            //                {
            //                    Topo[0].Add_Polygon(P);
            //                    Brep_ids.Add(q);
            //                }
            //                else
            //                {
            //                    Topo[0].Add_Polygon(new Hare.Geometry.Point[3] { P[0], P[1], P[2] });
            //                    Brep_ids.Add(q);
            //                    //ReflectionData.Add(Reflection);
            //                    AbsorptionData.Add(Mat_Obj[q]);
            //                    ScatteringData.Add(Scat_Obj[q]);
            //                    TransmissionData.Add(Trans_Obj[q]);
            //                    Transmissive.Add(Trans);
            //                    //PhaseData.Add(phase);
            //                    if (P.Length > 3) Topo[0].Add_Polygon(new Hare.Geometry.Point[3] { P[0], P[2], P[3] });
            //                }
            //            }
            //        }
            //    }
                
            //    //Set up a system to find random points on planes.//
            //    Plane_Area = new double[Topo[0].Plane_Members.Length];
            //    PolyPlaneFract = new double[Topo[0].Plane_Members.Length][];

            //    for (int q = 0; q < Topo[0].Plane_Members.Length; q++)
            //    {
            //        foreach (int t in Topo[0].Plane_Members[q])
            //        {
            //            Plane_Area[q] += Topo[0].Polygon_Area(t);
            //        }
            //    }

            //    //////////////////////////
            //    for (int i = 0; i < Topo[0].planeList.Count; i++)
            //        for (int j = 0; j < Topo[0].Plane_Members[i].Count; j++)
            //        {
            //            Point3d pt= Utilities.PachTools.HPttoRPt(Topo[0].Polygon_Centroid(Topo[0].Plane_Members[i][j]));
            //            string n = Topo[0].Polys[Topo[0].Plane_Members[i][j]].Plane_ID.ToString();
            //        }
            //    //////////////////////////

            //    for (int q = 0; q < Topo[0].Plane_Members.Length; q++)
            //    {
            //        PolyPlaneFract[q] = new double[Topo[0].Plane_Members[q].Count];
            //        PolyPlaneFract[q][0] = Topo[0].Polygon_Area(Topo[0].Plane_Members[q][0]) / Plane_Area[q];
            //        for (int t = 1; t < Topo[0].Plane_Members[q].Count; t++)
            //        {
            //            PolyPlaneFract[q][t] += PolyPlaneFract[q][t - 1] + Topo[0].Polygon_Area(Topo[0].Plane_Members[q][t]) / Plane_Area[q];
            //        }
            //    }
            //    Valid = true;

            //    Utilities.PachTools.Plot_Hare_Topology(Topo[0]);
            //}

            public override void Absorb(ref OctaveRay Ray, out double cos_theta, double u, double v)
            {
                AbsorptionData[Ray.Surf_ID].Absorb(ref Ray, out cos_theta, Normal(Ray.Surf_ID, u, v));
            }
            public override void Scatter_Late(ref OctaveRay Ray, ref Queue <OctaveRay> Rays, ref Random rand, Hare.Geometry.Vector Normal, double Cos_Theta)
            {
                double scat_sel = rand.NextDouble();

                if (scat_sel > Scattering_Coefficient[Ray.Octave, 2])
                {
                    // Specular Reflection
                    Ray.direction -= Normal * Cos_Theta * 2;
                    return;
                }
                else if (scat_sel > Scattering_Coefficient[Ray.Octave, 0])
                {
                    //Only for a certain portion of high benefit cases--
                    //// a. Create new source for scattered energy (E * Scattering).
                    //// b. Modify E (E * 1 - Scattering).
                    //Create a new ray...
                    OctaveRay tr = Ray.SplitRay(1 - Scattering_Coefficient[Ray.Octave, 1]);
                    // this is the specular reflection. Save it for later.
                    tr.direction -= Normal * Cos_Theta * 2;

                    if (tr.t_sum == 0)
                    {
                        Rhino.RhinoApp.Write("Something's up!");
                    }

                    Rays.Enqueue(tr);
                }

                //If we are here, the original ray needs a scattered direction:
                Hare.Geometry.Vector diffx;
                Hare.Geometry.Vector diffy;
                Hare.Geometry.Vector diffz;
                double proj;

                //Check that the ray and the normal are both on the same side...
                if (Cos_Theta > 0)
                {
                    Normal *= -1;
                }
                diffz = Normal;
                diffx = new Hare.Geometry.Vector(0, 0, 1);
                proj  = Math.Abs(Hare.Geometry.Hare_math.Dot(diffz, diffx));

                if (0.99 < proj && 1.01 > proj)
                {
                    diffx = new Hare.Geometry.Vector(1, 0, 0);
                }
                diffy = Hare.Geometry.Hare_math.Cross(diffz, diffx);
                diffx = Hare.Geometry.Hare_math.Cross(diffy, diffz);
                diffx.Normalize();
                diffy.Normalize();
                diffz.Normalize();

                double u1;
                double u2;
                double x;
                double y;
                double z;

                Hare.Geometry.Vector vect;
                u1 = 2.0 * Math.PI * rand.NextDouble();
                // random azimuth
                double Scat_Mod = rand.NextDouble();

                u2 = Math.Acos(Scat_Mod);
                // random zenith (elevation)
                x = Math.Cos(u1) * Math.Sin(u2);
                y = Math.Sin(u1) * Math.Sin(u2);
                z = Math.Cos(u2);

                vect = (diffx * x) + (diffy * y) + (diffz * z);
                vect.Normalize();

                //Return the new direction
                Ray.direction = vect;
            }
 public override void Absorb(ref OctaveRay Ray, Hare.Geometry.Vector Normal)
 {
     Ray.Intensity *= (Ref[Ray.Octave]);
     Ray.phase     += PD[Ray.Octave];
 }
 public override void Scatter_Late(ref OctaveRay Ray, ref Queue <OctaveRay> Rays, ref Random rand, double cos_theta, double u, double v)
 {
     return;
 }
 public override void Absorb(ref OctaveRay Ray, out double cos_theta, double u, double v)
 {
     cos_theta = 0;
 }
            /// <summary>
            /// Calculates the direction of a specular reflection.
            /// </summary>
            /// <param name="RayDirect"></param>
            /// <param name="u"></param>
            /// <param name="v"></param>
            /// <param name="x"></param>
            public virtual void ReflectRay(ref OctaveRay RayDirect, ref double u, ref double v, ref int x)
            {
                Vector local_N = Normal(x, u, v);

                RayDirect.direction -= local_N * Hare_math.Dot(RayDirect.direction, local_N) * 2;
            }
 public abstract void Scatter_Simple(ref OctaveRay Ray, ref Random rand, double cos_theta, double u, double v);
 public abstract void Scatter_Late(ref OctaveRay Ray, ref Queue <OctaveRay> Rays, ref Random rand, double cos_theta, double u, double v);
Esempio n. 23
0
        /// <summary>
        /// Called by each thread from the begin method.
        /// </summary>
        /// <param name="i">the object is type "Calc_Params" which holds all the necessary information to run a portion of the simulation.</param>
        public void Calculate(object i)
        {
            ///Homogeneous media only...
            Calc_Params Params = (Calc_Params)i;
            Random      Rnd    = new Random(Params.RandomSeed);

            _st = DateTime.Now;
            Point             Origin = Source.H_Origin();
            int               Dir_ID = Params.StartIndex;
            List <Point>      Start;
            List <double>     leg;
            List <int>        code;
            Queue <OctaveRay> Rays = new Queue <OctaveRay>();
            BroadRay          R;
            int               order;

            double Threshold_Power_1 = 0;

            double[] Threshold_Power_2 = new double[8];
            double[] Threshold_Power_3 = new double[8];
            for (_currentRay[Params.ThreadID] = 0; _currentRay[Params.ThreadID] < Params.EndIndex - Params.StartIndex; _currentRay[Params.ThreadID]++)
            {
                R = Source.Directions(_currentRay[Params.ThreadID] + Params.StartIndex, Params.ThreadID, ref Rnd, _octaves);
                for (int oct = 0; oct < 8; oct++)
                {
                    R.Energy[oct] /= Raycount;
                }
                for (int j = 0; j < 8; j++)
                {
                    _eInit[Params.ThreadID] += R.Energy[j];
                }
                Threshold_Power_1 = R.Energy[h_oct] * 1E-2;
                foreach (int o in _octaves)
                {
                    Threshold_Power_2[o] = R.Energy[o] * 1E-4;  //Cease splitting at 0.0001 sound intensity, or 40 dB down.
                    Threshold_Power_3[o] = R.Energy[o] * 1E-10; //Finish 16 digits (double Precision) under 60 dB of decay.
                }
                order = 0;
                double u = 0, v = 0;
                do
                {
                    R.Ray_ID = Rnd.Next();
                    if (!Params.Room.shoot(R, out u, out v, out R.Surf_ID, out Start, out leg, out code))
                    {
                        //Ray is lost... move on...
                        for (int j = 0; j < 8; j++)
                        {
                            _lost[Params.ThreadID] += R.Energy[j];
                        }
                        goto Do_Scattered;
                    }

                    if (order > IS_Order)
                    {
                        //Specular ray order exceeds order of image source calculation. Start logging specular part.
                        RecMain.CheckBroadbandRay(R, Start[0]);
                    }
                    R.Energy[0] *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[0] * leg[0]);
                    R.Energy[1] *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[1] * leg[0]);
                    R.Energy[2] *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[2] * leg[0]);
                    R.Energy[3] *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[3] * leg[0]);
                    R.Energy[4] *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[4] * leg[0]);
                    R.Energy[5] *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[5] * leg[0]);
                    R.Energy[6] *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[6] * leg[0]);
                    R.Energy[7] *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[7] * leg[0]);
                    R.AddLeg(leg[0] / Room.Sound_speed(code[0]));
                    R.origin = Start[0];

                    order++;

                    ///////////////////////////////////////////////////////////////
                    //The Split Case : Specular and Diffuse Explicit
                    ///Standard Energy Conservation Routine-
                    // 1. Multiply by Reflection energy. (1 - Absorption)
                    double cos_theta;
                    Room.Absorb(ref R, out cos_theta, u, v);
                    // 2. Apply Transmission (if any).
                    //// a. Create new source for transmitted energy (E * Transmission).
                    //// b. Modify E (E * 1 - Transmission).
                    foreach (int oct in _octaves)
                    {
                        if (Params.Room.TransmissionValue[R.Surf_ID][oct] > 0.0)
                        {
                            Rays.Enqueue(R.SplitRay(oct, Params.Room.TransmissionValue[R.Surf_ID][oct]));
                        }
                    }
                    //3. Apply Scattering
                    Room.Scatter_Early(ref R, ref Rays, ref Rnd, cos_theta, u, v);
                    ///////////////////////////////////////////////////////////////

                    //Utilities.PachTools.Ray_Acoustics.SpecularReflection(ref R.direction, ref Room, ref _u[Params.ThreadID], ref _v[Params.ThreadID], ref R.Surf_ID);
                } while (R.Energy[h_oct] > Threshold_Power_1);

                foreach (int o in _octaves)
                {
                    Rays.Enqueue(R.SplitRay(o));                        //Split all rays into individual octaves.
                }
Do_Scattered:

                if (Rays.Count > 0)
                {
                    do
                    {
                        OctaveRay OR = Rays.Dequeue();
                        _rayTotal[Params.ThreadID]++;
                        do
                        {
                            OR.Ray_ID = Rnd.Next();
                            if (!Params.Room.shoot(OR, out u, out v, out OR.Surf_ID, out Start, out leg, out code))
                            {
                                _lost[Params.ThreadID] += OR.Intensity;
                                goto Do_Scattered;
                            }
                            RecMain.CheckRay(OR, Start[0]);

                            OR.Intensity *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[OR.Octave] * leg[0]);
                            OR.AddLeg(leg[0] / Room.Sound_speed(code[0]));
                            OR.origin = Start[0];

                            ///Standard Energy Conservation Routine-
                            // 1. Multiply by Reflection energy. (1 - Absorption)
                            double cos_theta;
                            Room.Absorb(ref OR, out cos_theta, u, v);

                            // 2. Apply Transmission (if any).
                            if (Params.Room.TransmissionValue[OR.Surf_ID][OR.Octave] > 0.0)
                            {
                                //_rayTotal[Params.ThreadID]++;
                                //// a. Create new source for transmitted energy (E * Transmission).
                                //// b. Modify E (E * 1 - Transmission).
                                if (Rnd.NextDouble() < Params.Room.TransmissionValue[OR.Surf_ID][OR.Octave])
                                {
                                    OR.direction *= -1;
                                    Utilities.PachTools.Ray_Acoustics.SpecularReflection(ref OR.direction, ref Room, ref _u[OR.ThreadID], ref _v[OR.ThreadID], ref OR.Surf_ID);
                                }
                            }

                            // 3. Apply Scattering.
                            Room.Scatter_Late(ref OR, ref Rays, ref Rnd, cos_theta, u, v);
                        }while (OR.t_sum < COTime && OR.Intensity > Threshold_Power_2[OR.Octave]);

                        do
                        {
                            OR.Ray_ID = Rnd.Next();
                            if (!Params.Room.shoot(OR, out u, out v, out OR.Surf_ID, out Start, out leg, out code))
                            {
                                _lost[OR.ThreadID] += OR.Intensity;
                                goto Do_Scattered;
                            }

                            RecMain.CheckRay(OR, Start[0]);
                            //OctChecks.Enqueue(new object[] { OR.Clone(), new Hare.Geometry.Point(Start[0].x, Start[0].y, Start[0].z) });
                            OR.Intensity *= Math.Pow(10, -.1 * Room.Attenuation(code[0])[OR.Octave] * leg[0]);
                            OR.AddLeg(leg[0] / Room.Sound_speed(code[0]));
                            OR.origin = Start[0];

                            ///Standard Energy Conservation Routine-
                            // 1. Multiply by Reflection energy. (1 - Absorption)
                            double cos_theta;
                            Room.Absorb(ref OR, out cos_theta, u, v);

                            // 2. Apply Transmission (if any).
                            if (Params.Room.TransmissionValue[OR.Surf_ID][OR.Octave] > 0.0)
                            {
                                //// a. Create new source for transmitted energy (E * Transmission).
                                //// b. Modify E (E * 1 - Transmission).
                                if (Rnd.NextDouble() < Params.Room.TransmissionValue[OR.Surf_ID][OR.Octave])
                                {
                                    OR.direction *= -1;
                                    Utilities.PachTools.Ray_Acoustics.SpecularReflection(ref OR.direction, ref Params.Room, ref _u[OR.ThreadID], ref _v[OR.ThreadID], ref OR.Surf_ID);
                                }
                            }

                            // 3. Apply Scattering.
                            Room.Scatter_Simple(ref OR, ref Rnd, cos_theta, u, v);
                        }while (OR.t_sum < COTime && OR.Intensity > Threshold_Power_3[OR.Octave]);
                    }while (Rays.Count > 0);
                }
            }
            _ts = DateTime.Now - _st;
        }
 public abstract void Scatter_Simple(ref OctaveRay Ray, ref Random rand, double cos_theta, double u, double v);
 /// <summary>
 /// Creates an octave ray for the specified octave. After this operation, the Broadray will no longer trace this octave.
 /// </summary>
 /// <param name="Octave"></param>
 /// <returns></returns>
 public OctaveRay SplitRay(int Octave)
 {
     OctaveRay O = new OctaveRay(origin, direction, Ray_ID, ThreadID, Energy[Octave], phase[Octave], t_sum, Octave, Source_ID, Surf_ID);
     this.Energy[Octave] = 0;
     return O;
 }
            public override void Absorb(ref OctaveRay Ray, out double cos_theta, Hare.Geometry.Vector Normal)
            {
                cos_theta = Hare.Geometry.Hare_math.Dot(Normal, Ray.direction);

                Ray.Intensity *= (Ref[Ray.Octave]);
                Ray.phase += PD[Ray.Octave];
            }
 /// <summary>
 /// this method checks all receivers in the bank for intersections with a single octave ray.
 /// </summary>
 /// <param name="Length">the distance traveled by the ray up to the reflection prior to potential receiver intersection</param>
 /// <param name="R">the single octave band ray</param>
 /// <param name="EndPt">the point of intersection with the room after the potential receiver intersection</param>
 public virtual void CheckRay(OctaveRay R, Hare.Geometry.Point EndPt)
 {
     foreach (Spherical_Receiver S in Rec_List) {S.CheckRay(R,EndPt);};
 }
 public abstract void Absorb(ref OctaveRay Ray, Hare.Geometry.Vector Normal);
 public override void Scatter_Simple(ref OctaveRay Ray, ref Random rand, double cos_theta, double u, double v)
 {
     ScatteringData[Ray.Surf_ID].Scatter_VeryLate(ref Ray, ref rand, Normal(Ray.Surf_ID, u, v), cos_theta);
 }
            public override void Absorb(ref OctaveRay Ray, out double cos_theta, Hare.Geometry.Vector Normal)
            {
                cos_theta = Hare.Geometry.Hare_math.Dot(Ray.direction, Normal);
                int index = 18 - (int)Math.Round(Math.Acos(Math.Abs(cos_theta)) / angle_incr);

                Ray.Intensity *= (1 - Ang_Coef_Oct[Ray.Octave][index]);
            }
 public abstract void Scatter_Late(ref OctaveRay Ray, ref Queue<OctaveRay> Rays, ref Random rand, double cos_theta, double u, double v);
 public override void Scatter_Simple(ref OctaveRay Ray, ref Random rand, double cos_theta, double u, double v)
 {
     return;
 }
 public override void Absorb(ref OctaveRay Ray, Hare.Geometry.Vector Normal)
 {
     Ray.Intensity *= (Ref[Ray.Octave]);
     Ray.phase += PD[Ray.Octave];
 }
 public abstract void Absorb(ref OctaveRay Ray, Hare.Geometry.Vector Normal);
 public override void Absorb(ref OctaveRay Ray, out double cos_theta, Hare.Geometry.Vector Normal)
 {
     Ray.direction.Normalize();
     cos_theta = Math.Acos(Hare.Geometry.Hare_math.Dot(Ray.direction, new Hare.Geometry.Vector(0, 0, -1)));
     int Alt = (int)Math.Floor((cos_theta * Altitude.Length) / (Math.PI / 2));
     if (Alt >= Altitude.Length / 2) Alt = Altitude.Length - 1;
     int Azi = (int)Math.Round((Math.Atan2(Ray.direction.y, Ray.direction.x) * Azimuth.Length) / Math.PI / 2);
     if (Ray.direction.y < 0 && Azi < Azimuth.Length / 2) Azi = Azimuth.Length - Math.Abs(Azi);
     if (Azi == Azimuth.Length) Azi = 0;
     Ray.Intensity *= alpha[Alt][Azi][Ray.Octave];
 }
 public abstract void Absorb(ref OctaveRay Ray, out double cos_theta, Hare.Geometry.Vector Normal);
 public abstract void Absorb(ref OctaveRay Ray, out double cos_theta, Hare.Geometry.Vector Normal);
 public abstract void Scatter_VeryLate(ref OctaveRay Ray, ref Random rand, Hare.Geometry.Vector Normal, double Cos_Theta);
 public abstract void Scatter_VeryLate(ref OctaveRay Ray, ref Random rand, Hare.Geometry.Vector Normal, double Cos_Theta);
            //public override void Standardize_Normals()
            //{
            //    base.Standardize_Normals();

            //    Brep[] Polyhedra = Rhino.Geometry.Brep.JoinBreps(this.BrepList, Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance);
            //    BoundingBox Box = Polyhedra[0].GetBoundingBox(true);
            //    for (int i = 1; i < Polyhedra.Length; i++)
            //    {
            //        Box.Union(Polyhedra[i].GetBoundingBox(true));
            //    }
            //    Point3d Src = Box.Center;

            //    foreach (Brep B in BrepList)
            //    {
            //        for (int j = 0; j < B.Faces.Count; j++)
            //        {
            //            AreaMassProperties A = AreaMassProperties.Compute(B.Faces[0]);
            //            Vector3d Dir = (A.Centroid - Src);
            //            Dir.Unitize();
            //            LineCurve L = new LineCurve(Src, A.Centroid + Dir * double.Epsilon);

            //            Curve[] C;
            //            Point3d[] IPts;

            //            Rhino.Geometry.Ray3d R = new Ray3d(Src, Dir);

            //            for (int i = 0; i < Polyhedra.Length; i++)
            //            {
            //                Rhino.Geometry.Intersect.Intersection.CurveBrep(L, Polyhedra[i], 0.001, out C, out IPts);

            //            }
            //        }
            //    }
            //}

            public override void Absorb(ref OctaveRay Ray, out double cos_theta, double u, double v)
            {
                AbsorptionData[Ray.Surf_ID].Absorb(ref Ray, out cos_theta, Normal(Ray.Surf_ID, u, v));
            }
            public override void Scatter_Late(ref OctaveRay Ray, ref Queue<OctaveRay> Rays, ref Random rand, Hare.Geometry.Vector Normal, double Cos_Theta)
            {
                double scat_sel = rand.NextDouble();
                if (scat_sel > Scattering_Coefficient[Ray.Octave, 2])
                {
                    // Specular Reflection
                    Ray.direction -= Normal * Cos_Theta * 2;
                    return;
                }
                else if (scat_sel > Scattering_Coefficient[Ray.Octave, 0])
                {
                    //Only for a certain portion of high benefit cases--
                    //// a. Create new source for scattered energy (E * Scattering).
                    //// b. Modify E (E * 1 - Scattering).
                    //Create a new ray...
                    OctaveRay tr = Ray.SplitRay(1 - Scattering_Coefficient[Ray.Octave,1]);
                    // this is the specular reflection. Save it for later.
                    tr.direction -= Normal * Cos_Theta * 2;

                    if (tr.t_sum == 0)
                    {
                        Rhino.RhinoApp.Write("Something's up!");
                    }

                    Rays.Enqueue(tr);
                }

                //If we are here, the original ray needs a scattered direction:
                Hare.Geometry.Vector diffx;
                Hare.Geometry.Vector diffy;
                Hare.Geometry.Vector diffz;
                double proj;
                //Check that the ray and the normal are both on the same side...
                if (Cos_Theta > 0) Normal *= -1;
                diffz = Normal;
                diffx = new Hare.Geometry.Vector(0, 0, 1);
                proj = Math.Abs(Hare.Geometry.Hare_math.Dot(diffz, diffx));

                if (0.99 < proj && 1.01 > proj) diffx = new Hare.Geometry.Vector(1, 0, 0);
                diffy = Hare.Geometry.Hare_math.Cross(diffz, diffx);
                diffx = Hare.Geometry.Hare_math.Cross(diffy, diffz);
                diffx.Normalize();
                diffy.Normalize();
                diffz.Normalize();

                double u1;
                double u2;
                double x;
                double y;
                double z;
                Hare.Geometry.Vector vect;
                u1 = 2.0 * Math.PI * rand.NextDouble();
                // random azimuth
                double Scat_Mod = rand.NextDouble();
                u2 = Math.Acos(Scat_Mod);
                // random zenith (elevation)
                x = Math.Cos(u1) * Math.Sin(u2);
                y = Math.Sin(u1) * Math.Sin(u2);
                z = Math.Cos(u2);

                vect = (diffx * x) + (diffy * y) + (diffz * z);
                vect.Normalize();

                //Return the new direction
                Ray.direction = vect;
            }
 /// <summary>
 /// Checks receiver for an intersection with a ray 
 /// </summary>
 /// <param name="R">the ray.</param>
 /// <param name="endPt">The point at which the ray intersects the model after potential receiver intersection.</param>
 public override void CheckRay(OctaveRay R, Hare.Geometry.Point endPt)
 {
     Vector m = R.origin - H_Origin;
     double b = Hare_math.Dot(m, R.direction);
     double c = Hare_math.Dot(m, m) - Radius2;
     if (c > 0 && b > 0) return;
     double discr = b * b - c;
     if (discr < 0) return;
     double t1 = -b - Math.Sqrt(discr);
     double t2 = -b + Math.Sqrt(discr);
     double t = (t1 + t2) / 2;
     if (t > 0 && t * t < SqDistance(endPt, R.origin))
     {
         double raydist = t/C_Sound + R.t_sum;
         Recs.Add(raydist-Direct_Time, R.Intensity * Math.Pow(10,-.1 * Atten[R.Octave] * raydist) * SizeMod, R.direction * -1, R.phase, Rho_C, R.Octave);// / (1.33333333333333 * Math.PI * Min_Radius2 * Min_Radius), EndPt - R.origin, R.Octave);//R.Scat_Mod * 
     }
 }
            public override void Scatter_Early(ref BroadRay Ray, ref Queue <OctaveRay> Rays, ref Random rand, Hare.Geometry.Vector Normal, double Cos_Theta)
            {
                double roughness_chance = rand.NextDouble();

                if (Cos_Theta > 0)
                {
                    Normal    *= -1;
                    Cos_Theta *= -1;
                }

                foreach (int oct in Ray.Octaves)
                {
                    // 3. Apply Scattering.
                    //// a. Create new source for scattered energy (E * Scattering).
                    //// b. Modify E (E * 1 - Scattering).
                    OctaveRay R = Ray.SplitRay(oct, Scattering_Coefficient[oct, 1]);

                    Hare.Geometry.Vector diffx;
                    Hare.Geometry.Vector diffy;
                    Hare.Geometry.Vector diffz;
                    double proj;
                    //Check that the ray and the normal are both on the same side...
                    diffz = Normal;
                    diffx = new Hare.Geometry.Vector(0, 0, 1);
                    proj  = Math.Abs(Hare.Geometry.Hare_math.Dot(diffz, diffx));

                    if (0.99 < proj && 1.01 > proj)
                    {
                        diffx = new Hare.Geometry.Vector(1, 0, 0);
                    }
                    diffy = Hare.Geometry.Hare_math.Cross(diffz, diffx);
                    diffx = Hare.Geometry.Hare_math.Cross(diffy, diffz);
                    diffx.Normalize();
                    diffy.Normalize();
                    diffz.Normalize();

                    double u1;
                    double u2;
                    double x;
                    double y;
                    double z;
                    Hare.Geometry.Vector vect;
                    u1 = 2.0 * Math.PI * rand.NextDouble();
                    // random azimuth
                    double Scat_Mod = rand.NextDouble();
                    u2 = Math.Acos(Scat_Mod);
                    // random zenith (elevation)
                    x = Math.Cos(u1) * Math.Sin(u2);
                    y = Math.Sin(u1) * Math.Sin(u2);
                    z = Math.Cos(u2);

                    vect = (diffx * x) + (diffy * y) + (diffz * z);
                    vect.Normalize();

                    //Return the new direction
                    R.direction = vect;

                    if (R.t_sum == 0)
                    {
                        Rhino.RhinoApp.Write("Something's up!");
                    }

                    Rays.Enqueue(R);
                }
                Ray.direction -= Normal * Cos_Theta * 2;
            }
 /// <summary>
 /// Checks receivers for intersections with a single octave ray (specular only). Records detections. Use after shooting a ray, but before adding the distance of ray travel to the total of distance traveled.
 /// </summary>
 /// <param name="R">a single octave ray.</param>
 /// <param name="Sumlength">the length of the ray before detection. Adds on the distance from the last reflection to the receiver.</param>
 /// <param name="EndPt">The point of the d</param>
 /// <param name="X">The current voxel index 'X'</param>
 /// <param name="Y">The current voxel index 'Y'</param>
 /// <param name="Z">The current voxel index 'Z'</param>
 private void CheckReceivers_Octave(OctaveRay R, Hare.Geometry.Point EndPt, int X, int Y, int Z)
 {
     //PachTools.AddBox(Voxels[X, Y, 0].Min(), Voxels[X, Y, 0].Max());//Debug tool...
     for (int i = 0; i < Voxel_Inv[X, Y, Z].Count; i++)
     {
         if (!(Rec_List[Voxel_Inv[X, Y, Z][i]].Ray_ID[R.ThreadID] == R.Ray_ID))
         {
             Rec_List[Voxel_Inv[X, Y, Z][i]].CheckRay(R, EndPt);
             //    //Debug Code
             //    ///////////////////////////////////////////////////////////////////
             //    //OnSphere sphere = new OnSphere(Rec_List[Voxel_Inv[X, Y, Z][i]].Origin,Rec_List[Voxel_Inv[X, Y, Z][i]].Radius);
             //    //OnRevSurface sphere_srf = sphere.RevSurfaceForm();
             //    //MRhinoSurfaceObject sphere_obj = new MRhinoSurfaceObject();
             //    //sphere_obj.SetSurface(sphere_srf);
             //    //RhUtil.RhinoApp().ActiveDoc().AddObject(sphere_obj);
             //    ///////////////////////////////////////////////////////////////////
             //}
             Rec_List[Voxel_Inv[X, Y, Z][i]].Ray_ID[R.ThreadID] = R.Ray_ID;
         }
     }
 }
 public override void Scatter_Simple(ref OctaveRay Ray, ref Random rand, double cos_theta, double u, double v)
 {
     ScatteringData[Ray.Surf_ID].Scatter_VeryLate(ref Ray, ref rand, Normal(Ray.Surf_ID, u, v), cos_theta);
 }
            /// <summary>
            /// Checks receivers for intersections with a single octave ray (specular only). Records detections. Use after shooting a ray, but before adding the distance of ray travel to the total of distance traveled.
            /// </summary>
            /// <param name="R">a broadband ray.</param>
            /// <param name="Sumlength">the length of the ray before detection. Adds on the distance from the last reflection to the receiver.</param>
            /// <param name="EndPt">The point of the d</param>
            public override void CheckRay(OctaveRay R, Hare.Geometry.Point EndPt)
            {
                //R.ThreadID = this.Get_shotID();
                int X, Y, Z, Xend, Yend, Zend;
                //Identify whether the Origin is inside the voxel grid...
                //double Sumlength = R.t_sum;

                if (!OBox.IsPointInBox(R.origin))
                {
                    double t0 = 0;
                    if (!OBox.Intersect(R, ref t0, ref R.origin)) return;
                    //Sumlength += t0;
                }

                //Identify which voxel the Origin point is located in...

                //Identify where the ray enters the voxel grid...
                X = (int)Math.Floor((R.origin.x - OBox.Min_PT.x) / VoxelDims.x);
                Y = (int)Math.Floor((R.origin.y - OBox.Min_PT.y) / VoxelDims.y);
                Z = (int)Math.Floor((R.origin.z - OBox.Min_PT.z) / VoxelDims.z);

                Xend = (int)Math.Floor((EndPt.x - OBox.Min_PT.x) / VoxelDims.x);
                Yend = (int)Math.Floor((EndPt.y - OBox.Min_PT.y) / VoxelDims.y);
                Zend = (int)Math.Floor((EndPt.z - OBox.Min_PT.z) / VoxelDims.z);

                double tDeltaX, tDeltaY, tDeltaZ;
                double tMaxX = 0, tMaxY = 0, tMaxZ = 0;

                int stepX, stepY, stepZ, OutX, OutY, OutZ;

                if (X < 0) X = 0;
                if (X >= VoxelCtX) X = VoxelCtX - 1;
                if (Y < 0) Y = 0;
                if (Y >= VoxelCtY) Y = VoxelCtY - 1;
                if (Z < 0) Z = 0;
                if (Z >= VoxelCtZ) Z = VoxelCtZ - 1;

                if (R.direction.x < 0)
                {
                    OutX = -1;
                    stepX = -1;
                    tMaxX = (Voxels[X, Y, Z].Min_PT.x - R.origin.x) / R.direction.x;
                    tDeltaX = VoxelDims.x / R.direction.x * stepX;
                }
                else
                {
                    OutX = VoxelCtX;
                    stepX = 1;
                    tMaxX = (Voxels[X, Y, Z].Max_PT.x - R.origin.x) / R.direction.x;
                    tDeltaX = VoxelDims.x / R.direction.x * stepX;
                }

                if (R.direction.y < 0)
                {
                    OutY = -1;
                    stepY = -1;
                    tMaxY = (Voxels[X, Y, Z].Min_PT.y - R.origin.y) / R.direction.y;
                    tDeltaY = VoxelDims.y / R.direction.y * stepY;
                }
                else
                {
                    OutY = VoxelCtY;
                    stepY = 1;
                    tMaxY = (Voxels[X, Y, Z].Max_PT.y - R.origin.y) / R.direction.y;
                    tDeltaY = VoxelDims.y / R.direction.y * stepY;
                }

                if (R.direction.z < 0)
                {
                    OutZ = -1;
                    stepZ = -1;
                    tMaxZ = (Voxels[X, Y, Z].Min_PT.z - R.origin.z) / R.direction.z;
                    tDeltaZ = VoxelDims.z / R.direction.z * stepZ;
                }
                else
                {
                    OutZ = VoxelCtZ;
                    stepZ = 1;
                    tMaxZ = (Voxels[X, Y, Z].Max_PT.z - R.origin.z) / R.direction.z;
                    tDeltaZ = VoxelDims.z / R.direction.z * stepZ;
                }

                do
                {
                    //CheckReceivers_Octave(R, Sumlength, EndPt, X, Y, Z);
                    CheckReceivers_Octave(R, EndPt, X, Y, Z);

                    if (tMaxX < tMaxY)
                    {
                        if (tMaxX < tMaxZ)
                        {
                            X += stepX;
                            if (X < 0 || X >= VoxelCtX)
                                return; /* outside grid */
                            tMaxX = tMaxX + tDeltaX;
                        }
                        else
                        {
                            Z += stepZ;
                            if (Z < 0 || Z >= VoxelCtZ)
                                return; /* outside grid */
                            tMaxZ = tMaxZ + tDeltaZ;
                        }
                    }

                    else
                    {
                        if (tMaxY < tMaxZ)
                        {
                            Y += stepY;
                            if (Y < 0 || Y >= VoxelCtY)
                                return; /* outside grid */
                            tMaxY = tMaxY + tDeltaY;
                        }
                        else
                        {
                            Z += stepZ;
                            if (Z < 0 || Z >= VoxelCtZ)
                                return; /* outside grid */
                            tMaxZ = tMaxZ + tDeltaZ;
                        }
                    }
                } while (X != Xend && Y != Yend && Z != Zend);
            }