public EdgeSource(int[] attr_in, Hare.Geometry.Point PtZ0, Hare.Geometry.Point _PtZ, Vector[] _Tangents)
            {
                attr = attr_in;
                Tangent = _Tangents;
                Z_Norm = _PtZ - PtZ0;

                Z_Range = Z_Norm.Length();
                Z_dot = Z_Range * Z_Range;//Hare_math.Dot(Z_Norm, Z_Norm);
                Z_Norm/= Z_Range;
                Z_Range_2 = Z_Range / 2;
                Z_mid = (PtZ0 + _PtZ) / 2;
                Vector Bisector = (Tangent[0] + Tangent[1])/2;
                Bisector.Normalize();
                double BisectAngle = Math.Acos(Hare_math.Dot(Tangent[0], Bisector));
                if (BisectAngle == 0) BisectAngle = 1E-12;
                v = new double[2] { Math.PI / (2 * BisectAngle), Math.PI / (Utilities.Numerics.PiX2 - 2 * BisectAngle) };
                v_4pi = new double[2] { v[0] / (4 * Math.PI), v[1] / (4 * Math.PI) };
                v_2pi = new double[2] { v[0] / (2 * Math.PI), v[1] / (2 * Math.PI) };
                Normal[0] = Hare_math.Cross(_Tangents[0], Z_Norm);
                Normal[1] = Hare_math.Cross(_Tangents[1], Z_Norm*-1);

                if(Hare_math.Dot(Normal[0], Bisector) > 0)
                {
                    Normal[0] *= -1;
                    Normal[1] *= -1;
                }
                
                ////////////////////////////
                //VisCheck//
                Rhino.Geometry.Point3d pt = new Rhino.Geometry.Point3d(Z_mid.x, Z_mid.y, Z_mid.z);
                Rhino.RhinoDoc.ActiveDoc.Objects.AddLine(pt, pt + new Rhino.Geometry.Point3d(Normal[0].x, Normal[0].y, Normal[0].z));
                Rhino.RhinoDoc.ActiveDoc.Objects.AddLine(pt, pt + new Rhino.Geometry.Point3d(Normal[1].x, Normal[1].y, Normal[1].z));
                //Rhino.RhinoDoc.ActiveDoc.Objects.AddLine(pt, pt + new Rhino.Geometry.Point3d(Tangent[0].x, Tangent[0].y, Tangent[0].z));
                //Rhino.RhinoDoc.ActiveDoc.Objects.AddLine(pt, pt + new Rhino.Geometry.Point3d(Tangent[1].x, Tangent[1].y, Tangent[1].z));
                //////Rhino.RhinoDoc.ActiveDoc.Objects.AddPoint(new Rhino.Geometry.Point3d(Z_mid.x, Z_mid.y, Z_mid.z));
            }
            public override BroadRay Directions(int index, int thread, ref Random random)
            {
                double pos = random.NextDouble();
                double subpos = random.NextDouble();
                int i,j;
                for (i = 0; i < Srfs.Count; i++) if (pos > Domains[i] && pos < Domains[i + 1]) break;
                for (j = 0; j < SubDomains[i].Length; j++) if (subpos > SubDomains[i][j] && subpos < SubDomains[i][j+1]) break;

                Point3d P = Utilities.PachTools.HPttoRPt(T[i].Polys[j].GetRandomPoint(random.NextDouble(), random.NextDouble(), 0));
                double Theta = random.NextDouble() * 2 * System.Math.PI;
                double Phi = random.NextDouble() * 2 * System.Math.PI;
                Hare.Geometry.Vector Direction = new Hare.Geometry.Vector(Math.Sin(Theta) * Math.Cos(Phi), Math.Sin(Theta) * Math.Sin(Phi), Math.Cos(Theta));
                double[] phase = new double[8];
                if (ph == Phase_Regime.Random) for(int o = 0; o < 8; o++) phase[o] = random.Next() * 2 * Math.PI;
                else for(int o = 0; o < 8; o++) phase[o] = 0 - Delay * Utilities.Numerics.angularFrequency[o];

                return new BroadRay(Utilities.PachTools.RPttoHPt(P), Direction, random.Next(), thread, DomainPower[i], phase, delay, S_ID);
            }
        public Edge_Curved(ref IEnumerable<Hare.Geometry.Point> SPT, ref IEnumerable<Hare.Geometry.Point> RPT, Environment.Medium_Properties Env_Props, Brep[] B, int[] Brep_Index, Curve i)
            : base(B, i)
        {
            //if (i.IsLinear()) throw new Exception("Curved Edge object called for straight edge.");
            //Rhino.RhinoDoc.ActiveDoc.Objects.AddCurve(i);
            ParentBreps = Brep_Index;
            
            //Get the open wedge angle. This needs the source location, and occlusion info...
            //Assuming tangent angles are always correctly oriented...
            //Vector Z_Dir = PointA - PointB;
            //double length = Z_Dir.Length();
            //Z_Dir.Normalize();
            //double MinAngle = double.PositiveInfinity;
            //Hare.Geometry.Point[] Dpt = new Hare.Geometry.Point[0];

            //Find the secondary source spacing DeltaZ
            /// 1/4 wavelength substituted for now...
            double fs = 88200; //Hz.
            //double DeltaZ = speed_of_sound / (fs * Math.Cos(MinAngle));//TODO: Adjust depending on distance from source to receiver... (nearest, farthest?
           
            /////
            //double El_Ct = Math.Ceiling(i.GetLength() / DeltaZ);
            //DeltaZ = i.GetLength() / El_Ct;
            //List<Point3d> Pts;
            double length = Env_Props.Sound_Speed(i.PointAtStart)/ (8 * fs);
            double total_length = i.GetLength();
            double t;
            
            //for (int j = 1; j < Pts.Length; j++)
            while (true)
            {
                if (!i.LengthParameter(length, out t)) break;
                Plane P;
                i.PerpendicularFrameAt(t, out P);
                Curve[] Csects1, Csects2;
                Point3d[] Psects;

                //double DeltaZ = Env_Props.Sound_Speed(Point3d.Origin) / (4 * fs);
                Rhino.Geometry.Intersect.Intersection.BrepPlane(B[0], P, 0.001, out Csects1, out Psects);
                Rhino.Geometry.Intersect.Intersection.BrepPlane(B[1], P, 0.001, out Csects2, out Psects);
                Vector3d[] Tangents = new Vector3d[2];
                ///Control Start Point of curve
                if ((Csects1[0].PointAtStart.X * P.Origin.X + Csects1[0].PointAtStart.Y * P.Origin.Y + Csects1[0].PointAtStart.Z * P.Origin.Z) < 0.00001) Csects1[0].Reverse();
                if ((Csects2[0].PointAtStart.X * P.Origin.X + Csects2[0].PointAtStart.Y * P.Origin.Y + Csects2[0].PointAtStart.Z * P.Origin.Z) < 0.00001) Csects2[0].Reverse();
                ///Get Tangent Vector
                Tangents[0] = (Csects1[0].PointAtNormalizedLength(0.05) - P.Origin);
                Tangents[0].Unitize();
                Tangents[1] = (Csects2[0].PointAtNormalizedLength(0.05) - P.Origin);
                Tangents[1].Unitize();
                Hare.Geometry.Vector[] HTangents = new Hare.Geometry.Vector[2] { new Hare.Geometry.Vector(Tangents[0].X, Tangents[0].Y, Tangents[0].Z), new Hare.Geometry.Vector(Tangents[1].X, Tangents[1].Y, Tangents[1].Z) };
                ///Get Normal
                double up, vp;
                ComponentIndex CI;
                Point3d outPt;
                Vector3d[] Normals = new Vector3d[2];
                //Point3d CPT = Utilities.PachTools.HPttoRPt(Z_mid);
                B[0].ClosestPoint(P.Origin, out outPt, out CI, out up, out vp, 0.01, out Normals[0]);
                B[1].ClosestPoint(P.Origin, out outPt, out CI, out up, out vp, 0.01, out Normals[1]);
                Hare.Geometry.Vector[] HNormals = new Hare.Geometry.Vector[2] { new Hare.Geometry.Vector(Normals[0].X, Normals[0].Y, Normals[0].Z), new Hare.Geometry.Vector(Normals[1].X, Normals[1].Y, Normals[1].Z) };
                //// Get Vector Tangents.
                //Hare.Geometry.Point Pt1 = new Hare.Geometry.Point(Pts[j-1].X, Pts[j-1].Y, Pts[j-1].Z);
                //Hare.Geometry.Point Pt2 = new Hare.Geometry.Point(Pts[j].X, Pts[j].Y, Pts[j].Z);
                double Delta_Z = Env_Props.Sound_Speed(P.Origin) / (4 * fs);//TODO: Adjust depending on distance from source to receiver... (nearest, farthest?)
                Sources.Add(new EdgeSource(Edge.Rigid, Utilities.PachTools.RPttoHPt(P.Origin), Delta_Z, HTangents));

                length += Delta_Z;
            }
        }
        public Edge_Straight(ref IEnumerable<Hare.Geometry.Point> SPT, ref IEnumerable<Hare.Geometry.Point> RPT, Environment.Medium_Properties Att_Props, Rhino.Geometry.Brep[] Brep, int[] Brep_Index, Curve Be)
            : base(Brep, Be)
        {
            //Rhino.RhinoDoc.ActiveDoc.Objects.Add(Brep[0]);
            //Rhino.RhinoDoc.ActiveDoc.Objects.Add(Brep[1]);
            ParentBreps = Brep_Index;
            //Rhino.RhinoDoc.ActiveDoc.Objects.AddCurve(Be);

            //if (!Brep.Edges[edge_id].IsLinear()) throw new Exception("Straight_Edge object called for curved edge.");
            Rhino.Geometry.Point3d PA = Be.PointAtStart;
            Rhino.Geometry.Point3d PB = Be.PointAtEnd;
            PointA = Utilities.PachTools.RPttoHPt(PA);
            PointB = Utilities.PachTools.RPttoHPt(PB);

            //Get the open wedge angle. This needs the source location, and occlusion info...
            //Assuming tangent angles are always correctly oriented...
            Vector Z_Dir = PointA - PointB;
            double length = Z_Dir.Length();
            Z_Dir.Normalize();
            double MinAngle = double.PositiveInfinity;
            List<Hare.Geometry.Point> Dpt = new List<Hare.Geometry.Point>();

            //Find the secondary source spacing DeltaZ
            Dpt.AddRange(RPT);
            Dpt.AddRange(SPT);

            for (int j = 0; j < Dpt.Count; j++)
            {
                double angle = Math.Abs(Hare_math.Dot(PointA - Dpt[j], Z_Dir));
                if (angle < MinAngle) MinAngle = angle;
                angle = Math.Abs(Hare_math.Dot(PointB - Dpt[j], Z_Dir));
                if (angle < MinAngle) MinAngle = angle;
            }
            double fs = 176400; //Hz.
            double DeltaZ = Att_Props.Sound_Speed(this.PointA) / (fs * MinAngle);//TODO: Adjust depending on distance from source to receiver... (nearest, farthest?)
            
            double El_Ct = Math.Ceiling(length / DeltaZ);
            DeltaZ = length / El_Ct;

            Random r = new Random();

            Plane P;
            Curve[] Csects1;
            Curve[] Csects2;
            Point3d[] Psects;

            //for (;;)
            //{
                double t = r.NextDouble() * (Be.Domain.Max - Be.Domain.Min) + Be.Domain.Min;

                Be.PerpendicularFrameAt(t, out P);

                Rhino.Geometry.Intersect.Intersection.BrepPlane(Brep[0], P, 0.1, out Csects1, out Psects);
                Rhino.Geometry.Intersect.Intersection.BrepPlane(Brep[1], P, 0.1, out Csects2, out Psects);

                //if (Csects1 != null && Csects2 != null && Csects1.Length > 0 && Csects2.Length > 0) break;

                //Rhino.RhinoDoc.ActiveDoc.Objects.Add(Csects1[0]);
                //Rhino.RhinoDoc.ActiveDoc.Objects.Add(Csects2[0]);
            //}

            Vector3d[] Tangents = new Vector3d[2];
            ///Control Start Point of curve
            if ((Csects1[0].PointAtStart.X * P.Origin.X + Csects1[0].PointAtStart.Y * P.Origin.Y + Csects1[0].PointAtStart.Z * P.Origin.Z) < 0.00001) Csects1[0].Reverse();
            if ((Csects2[0].PointAtStart.X * P.Origin.X + Csects2[0].PointAtStart.Y * P.Origin.Y + Csects2[0].PointAtStart.Z * P.Origin.Z) < 0.00001) Csects2[0].Reverse();
            ///Get Tangent Vector
            Tangents[0] = (Csects1[0].PointAtNormalizedLength(0.05) - P.Origin);
            Tangents[0].Unitize();
            Tangents[1] = (Csects2[0].PointAtNormalizedLength(0.05) - P.Origin);
            Tangents[1].Unitize();
            Hare.Geometry.Vector[] HTangents = new Hare.Geometry.Vector[2] { new Hare.Geometry.Vector(Tangents[0].X, Tangents[0].Y, Tangents[0].Z), new Hare.Geometry.Vector(Tangents[1].X, Tangents[1].Y, Tangents[1].Z) };
            ///Get Normal
            double up, vp;
            ComponentIndex CI;
            Point3d outPt;
            Vector3d[] Normals = new Vector3d[2];
            Brep[0].ClosestPoint(P.Origin, out outPt, out CI, out up, out vp, 0.01, out Normals[0]);
            Brep[1].ClosestPoint(P.Origin, out outPt, out CI, out up, out vp, 0.01, out Normals[1]);
            Hare.Geometry.Vector[] HNormals = new Hare.Geometry.Vector[2] { new Hare.Geometry.Vector(Normals[0].X, Normals[0].Y, Normals[0].Z), new Hare.Geometry.Vector(Normals[1].X, Normals[1].Y, Normals[1].Z) };
            Hare.Geometry.Point Pt1 = new Hare.Geometry.Point(PointA.x, PointA.y, PointA.z);

            //TODO - Modify DeltaZ per change in velocity.
            for (int i = 1; i < El_Ct; i++)
            {
                Hare.Geometry.Point Pt2 = PointA - i * Z_Dir * DeltaZ;
                Sources.Add(new EdgeSource(Edge.Rigid, Pt1, Pt2, HTangents));
                //HTangents[1]*= -1;
                //Sources.Add(new EdgeSource(Edge.Rigid, Pt1, Pt2, HTangents));
                Pt1 = Pt2;
            }
        }
                public override BroadRay Directions(int index, int thread, ref Random random, ref Curve Curves, ref double[] DomainPower, ref double Delay, ref Phase_Regime ph, ref int S_ID)
                {
                    double pos = random.NextDouble();
                    int i;

                    Interval t = Curves.Domain;
                    double x = random.NextDouble() * (t[1] - t[0]) + t[0];
                    Point3d P = Curves.PointAt(x);
                    Vector3d f = Curves.TangentAt(x);
                    Vector fore = new Hare.Geometry.Vector(f.X, f.Y, f.Z);

                    double Theta = random.NextDouble() * 2 * System.Math.PI;
                    double Phi = random.NextDouble() * 2 * System.Math.PI;
                    Vector Direction = new Hare.Geometry.Vector(Math.Sin(Theta) * Math.Cos(Phi), Math.Sin(Theta) * Math.Sin(Phi), Math.Cos(Theta));

                    double cosphi = Hare.Geometry.Hare_math.Dot(Direction, fore);
                    double sinphi = Math.Sqrt(1 - cosphi * cosphi);
                    double tanphi =  sinphi/cosphi;
                    double F_r = sinphi * sinphi * Math.Pow((tanphi * tanphi + 1) / (tanphi * tanphi + (1 + tanphi * Math.Tan(delta))), 1.5);

                    double[] power = new double[8];
                    for (int oct = 0; oct < 8; oct++) power[oct] = DomainPower[oct] * reciprocal_velocity * dLinf * F_r;
                    double[] phase = new double[8];
                    if (ph == Phase_Regime.Random) for (int o = 0; o < 8; o++) phase[o] = random.Next() * 2 * Math.PI;
                    else for (int o = 0; o < 8; o++) phase[o] = 0 - Delay * Utilities.Numerics.angularFrequency[o];

                    return new BroadRay(Utilities.PachTools.RPttoHPt(P), Direction, random.Next(), thread, DomainPower, phase, Delay, S_ID);
                }
                public override double[] DirPower(int threadid, int random, Vector Direction, double position, ref Curve Curves, ref double[] DomainPower)
                {
                    X_Event X = new X_Event();
                    double[] RayPower = new double[8];

                    Interval t = Curves.Domain;
                    Point3d P = Curves.PointAt((position/t.Length) + t.Min);
                    Vector3d f = Curves.TangentAt(position);
                    Vector fore = new Hare.Geometry.Vector(f.X, f.Y, f.Z);

                    double cosphi = Hare.Geometry.Hare_math.Dot(Direction, fore);
                    double sinphi = Math.Sqrt(1 - cosphi * cosphi);
                    double tanphi = sinphi / cosphi;
                    double F_r = sinphi * sinphi * Math.Pow((tanphi * tanphi + 1) / (tanphi * tanphi + (1 + tanphi * Math.Tan(delta))), 1.5);

                    for (int oct = 0; oct < 8; oct++)
                    {
                        if (DomainPower[oct] == 0)
                        {
                            RayPower[oct] = 0;
                        }
                        else
                        {
                            RayPower[oct] = DomainPower[oct] * reciprocal_velocity * dLinf * F_r;
                        }
                    }
                    return RayPower;
                }
                public override BroadRay Directions(int index, int thread, ref Random random, ref Curve Curves, ref double[] DomainPower, ref double Delay, ref Phase_Regime ph, ref int S_ID)
                {
                    double pos = random.NextDouble();
                    int i;

                    Interval t = Curves.Domain;
                    double x = random.NextDouble() * (t[1] - t[0]) + t[0];
                    Point3d P = Curves.PointAt(x);

                    double Theta = random.NextDouble() * 2 * System.Math.PI;
                    double Phi = random.NextDouble() * 2 * System.Math.PI;
                    Vector Direction = new Hare.Geometry.Vector(Math.Sin(Theta) * Math.Cos(Phi), Math.Sin(Theta) * Math.Sin(Phi), Math.Cos(Theta));
                    double[] phase = new double[8];
                    if (ph == Phase_Regime.Random) for (int o = 0; o < 8; o++) phase[o] = random.Next() * 2 * Math.PI;
                    else for (int o = 0; o < 8; o++) phase[o] = 0 - Delay * Utilities.Numerics.angularFrequency[o];

                    return new BroadRay(Utilities.PachTools.RPttoHPt(P), Direction, random.Next(), thread, DomainPower, phase, Delay, S_ID);
                }
 public abstract void EdgeFrame_Tangents(Hare.Geometry.Point Origin, Hare.Geometry.Vector Normal, int[] SrfIDs, ref List <double> dist2, List <Vector> Dir, List <int> IDs);