public LineReport(double time, XYDoubleLocation nearLoc, XYDoubleLocation farLoc,
            double distance, double length)
        {
            // Closure must still be checked before creating the LineReport!
            double k1 = distance - length;
            double k2 = distance;
            double dx = farLoc.X - nearLoc.X;
            double dy = farLoc.Y - nearLoc.Y;

            double theta = Math.Atan2(dy, dx);

            double inner = k1 * Math.Cos(theta);
            double innerX = nearLoc.X;
            double innerY;
            double outer = k2 * Math.Cos(theta);
            double outerX = farLoc.X;
            double outerY;

            if (!double.IsInfinity(dy / dx))
            {
                double m = dy / dx;
                innerX = inner + nearLoc.X;
                innerY = m * inner + nearLoc.Y;
                outerX = outer + nearLoc.X;
                outerY = m * outer + nearLoc.Y;
            }
            else
            {
                innerY = Math.Sign(dy) * k1 + nearLoc.Y;
                outerY = Math.Sign(dy) * k2 + nearLoc.Y;
            }

            XYDoubleLocation outerLoc;
            XYDoubleLocation innerLoc = new XYDoubleLocation(innerX, innerY);
            if ((Math.Abs(outerX - nearLoc.X) > Math.Abs(dx))
                || (Math.Abs(outerY - nearLoc.Y) > Math.Abs(dy)))
                outerLoc = farLoc;
            else outerLoc = new XYDoubleLocation(outerX, outerY);
            innerLoc.SetField(nearLoc.Field);
            outerLoc.SetField(nearLoc.Field);

            if ((Math.Abs(innerX - nearLoc.X) > Math.Abs(dx))
                || (Math.Abs(innerY - nearLoc.Y) > Math.Abs(dy)))
                innerLoc = outerLoc; // This occurs if the line has already intersected the neighbor

            this.loc1 = innerLoc;
            this.loc2 = outerLoc;
            this.time = time;
        }
        // Any non-Normal Location can be constructed using a Normal and a Field.
        public XYDoubleLocation(NormalLocation normLoc, XYDoubleLocation[] field)
        {
            // (Note that this constructor would be much more complex for something like Lat/Long)
            if (!SetField(field))  // First, set the field and verify it.
            {
                throw (new Exception("Invalid Field in XYDoubleLocation"));
            }
            else
            {
                // Next, measure the size of the field in the X and Y locations
                XYDoubleLocation[] tempField = (XYDoubleLocation[])this.Field;
                double dX = tempField[1].X - tempField[0].X;
                double dY = tempField[1].Y - tempField[0].Y;

                // Transform the magnitude of the Normal
                double X = dX * normLoc.X;
                double Y = dY * normLoc.Y;

                // Transform the translation of the Normal
                this.x = X + tempField[0].X;
                this.y = Y + tempField[0].Y;
            }
        }
        private void btn_RunSim_Click(object sender, EventArgs e)
        {
            isSimPaused = false;
            if (isSimRunning)
                return;
            disableConfiguration();

            label_Info.Text = "Configuring Simulation.";
            label_Info.Refresh();
            System.Threading.Thread.Sleep(250);
            // ********** VERIFY CONFIGURATION **********
            // This could be moved to click/change events
            // and the Begin button disabled until config
            // is validated.
            bool valid = true;

            if (selected_IApplicationEventGenerator.ForeColor == Color.Red)
                valid = false;
            if (selected_IDeployer.ForeColor == Color.Red)
                valid = false;
            if (selected_ILocation.ForeColor == Color.Red)
                valid = false;
            if (selected_INodeFactory.ForeColor == Color.Red)
                valid = false;
            if (selected_IPhysicalProcessor.ForeColor == Color.Red)
                valid = false;
            if (selected_IRandomizerFactory.ForeColor == Color.Red)
                valid = false;
            if (selected_GraphicsRunning.ForeColor == Color.Red)
                valid = false;

            string filename = text_IOFolder.Text + "\\"
                    + text_IOFileTag.Text + "_SimInfo.txt";

            if (filename.IndexOfAny(System.IO.Path.GetInvalidPathChars()) > -1)
                valid = false;

            if (!valid)
            {
                enableConfiguration();
                label_Info.Text = "ERR: Fix Highlighted Red/Yellow Options.";
                return;
            }

            // To prevent SW from getting stuck. Seems to happen when restarting many visualizations.
            sw = new StopWatch.StopWatch();
            sw.Reset();
            resetTimeTick = 0;

            // Set up modules & settings
            Type INodeFactoryType = (Type)this.cb_INode.SelectedItem;
            Type IPhysicalProcessorType = (Type)this.cb_IPhysicalProcessor.SelectedItem;
            Type IDeployerType = (Type)this.cb_IDeployer.SelectedItem;
            Type IApplicationEventGeneratorType = (Type)this.cb_IApplicationEventGenerator.SelectedItem;
            Type IRandomizerFactoryType = (Type)this.cb_IRandomizerFactory.SelectedItem;
            Type ILocationType = (Type)this.cb_ILocation.SelectedItem;
            double x1 = double.Parse(text_FieldX1.Text);
            double y1 = double.Parse(text_FieldY1.Text);
            double x2 = double.Parse(text_FieldX2.Text);
            double y2 = double.Parse(text_FieldY2.Text);

            double timeScale = double.Parse(TimeScale.Text);
            if (!cb_InvertScale.Checked)
                timeScale = 1 / timeScale;                          // Sim seconds per real second
            secPerTick = timeScale / double.Parse(FPS.Text);        // Sim seconds per frame

            bool multirun = false;
            int numruns = 1;
            if (cb_Multirun.Checked && (tb_Multirun.BackColor == Color.White))
            {
                multirun = true;
                numruns = int.Parse(tb_Multirun.Text);
                disableConfigurationMultirun();
            }

            outputFile = null;

            // write to Run Info File
            string indent = "     ";
            StreamWriter simInfoFile = new StreamWriter(filename, false);
            simInfoFile.WriteLine("Simulation Tag: " + text_IOFileTag.Text);
            simInfoFile.Write("Run Flags: ");
            if (cb_AppSetsSink.Checked)
                simInfoFile.Write("[Application Sets Sink Node] ");
            if (cb_randomSink.Checked)
                simInfoFile.Write("[Randomized Sink Node] ");
            if (cb_GraphicsOff.Checked)
                simInfoFile.Write("[Graphics Off] ");
            else
                simInfoFile.Write("[Graphics On] ");
            if (cb_Multirun.Checked)
                simInfoFile.Write("[Multirun with " + tb_Multirun.Text + " Runs]");
            simInfoFile.Write("\n");

            simInfoFile.WriteLine("ILocation: " + ILocationType.ToString());
            simInfoFile.WriteLine(indent + "Initial Corner: ("
                + text_FieldX1.Text + ", " + text_FieldY1.Text + ")");
            simInfoFile.WriteLine(indent + "Final Corner:   ("
                + text_FieldX2.Text + ", " + text_FieldY2.Text + ")");

            // Initial randomizer factory
            IRandomizerFactory randomFactoryMultirun
                        = (IRandomizerFactory)Activator.CreateInstance(IRandomizerFactoryType);
            randomFactoryMultirun.PanelObjs = setPanelObjValues(PanelObjs_IRandomizerFactory);
            randomFactoryMultirun.Initialize();

            simInfoFile.WriteLine("IRandomizerFactory: " + IRandomizerFactoryType.ToString());
            foreach (PanelObj pObj in PanelObjs_IRandomizerFactory)
            {
                pObj.UpdateInfo();
                simInfoFile.WriteLine(indent + pObj.name + ": Text = " + pObj.text
                    + "; Value = " + pObj.value);
            }

            simInfoFile.WriteLine("IDeployer: " + IDeployerType.ToString());
            foreach (PanelObj pObj in PanelObjs_IDeployer)
            {
                pObj.UpdateInfo();
                simInfoFile.WriteLine(indent + pObj.name + ": Text = " + pObj.text
                    + "; Value = " + pObj.value);
            }

            simInfoFile.WriteLine("IPhysicalProcessor: " + IPhysicalProcessorType.ToString());
            foreach (PanelObj pObj in PanelObjs_IPhysProc)
            {
                pObj.UpdateInfo();
                simInfoFile.WriteLine(indent + pObj.name + ": Text = " + pObj.text
                    + "; Value = " + pObj.value);
            }

            simInfoFile.WriteLine("INodeFactory: " + INodeFactoryType.ToString());
            foreach (PanelObj pObj in PanelObjs_INode)
            {
                pObj.UpdateInfo();
                simInfoFile.WriteLine(indent + pObj.name + ": Text = " + pObj.text
                    + "; Value = " + pObj.value);
            }

            simInfoFile.WriteLine("IApplicationEventGenerator: " + IApplicationEventGeneratorType.ToString());
            foreach (PanelObj pObj in PanelObjs_IApplicationEventGenerator)
            {
                pObj.UpdateInfo();
                simInfoFile.WriteLine(indent + pObj.name + ": Text = " + pObj.text
                    + "; Value = " + pObj.value);
            }

            simInfoFile.WriteLine();

            // Start running simulation
            label_Info.Text = "Simulation Running";
            label_Info.Refresh();
            System.Threading.Thread.Sleep(250);

            for (run = 0; run < numruns; run++)
            {
                // SIM START
                isSimRunning = true;
                reporter = new Reporter(secPerTick);
                reporter.EnableGraphics = !cb_GraphicsOff.Checked;

                IRandomizerFactory randomFactory = (IRandomizerFactory)Activator.CreateInstance(IRandomizerFactoryType);
                randomFactory.PanelObjs = setPanelObjValues(PanelObjs_IRandomizerFactory);
                if (run == 0)
                    randomFactory.SetSeed(randomFactoryMultirun.InitialSeed);
                else
                    randomFactory.SetSeed(randomFactoryMultirun.CreateRandomizer().Next());

                simInfoFile.WriteLine("Run #" + run + ": Randomizer Seed Info");
                simInfoFile.WriteLine(indent + "Random Seed: " + randomFactory.InitialSeed);

                Nodes nodes = new Nodes(randomFactory.CreateRandomizer());

                EventManager eventMgr = new EventManager();

                IPhysicalProcessor physProc
                    = (IPhysicalProcessor)Activator.CreateInstance(IPhysicalProcessorType);
                physProc.PanelObjs = setPanelObjValues(PanelObjs_IPhysProc);

                ReporterIWF repIWF = new ReporterIWF(secPerTick, physProc.TransmissionSpeed,
                    physProc.PropagationSpeed);
                repIWF.Attach(reporter);
                physProc.RepIWF = repIWF;

                INodeFactory nodeFactory = (INodeFactory)Activator.CreateInstance(INodeFactoryType);
                nodeFactory.PanelObjs = setPanelObjValues(PanelObjs_INode);
                nodeFactory.Initialize(eventMgr, physProc, randomFactory, reporter);

                XYDoubleLocation[] field = new XYDoubleLocation[2];
                field[0] = new XYDoubleLocation(x1, y1);
                field[1] = new XYDoubleLocation(x2, y2);

                IDeployer deployer = (IDeployer)Activator.CreateInstance(IDeployerType);
                deployer.PanelObjs = setPanelObjValues(PanelObjs_IDeployer);
                deployer.Initialize(nodes, nodeFactory, field, randomFactory);

                //SimulationCompleteEvent finalEvent = new SimulationCompleteEvent();
                //finalEvent.Time = 0 /*hours*/   * 60 * 60
                //                + 10 /*minutes*/ * 60
                //                + 0 /*seconds*/;
                //eventMgr.AddEvent(finalEvent);

                deployer.Deploy();

                // Physical Processor needs to be initialized after the nodes are deployed.
                physProc.Initialize(nodes, eventMgr);
                repIWF.MaxBitDistance = physProc.MaximumRange;

                IApplicationEventGenerator eventGen = (IApplicationEventGenerator)
                        Activator.CreateInstance(IApplicationEventGeneratorType);
                eventGen.PanelObjs = setPanelObjValues(PanelObjs_IApplicationEventGenerator);
                eventGen.Attach(reporter);
                eventGen.Initialize(eventMgr, nodes, randomFactory.CreateRandomizer(),
                    field);

                if (cb_AppSetsSink.Checked)
                {
                    if (cb_randomSink.Checked)
                    {
                        eventGen.GenerateEvent();
                        nodes.SetRandomSinkNode();
                    }
                    else
                    {
                        INode[] furthestPair = nodes.FindFurthestNodes();
                        eventGen.GenerateEvent(furthestPair[0].Location);
                        furthestPair[1].IsSink = true;
                    }
                }
                else
                    eventGen.GenerateEvent();

                nodes.InitializeNodes();

                tab_INode.SelectedTab = tab_Statistics;

                backgroundWorker_RunSim.RunWorkerAsync(eventMgr);
                while (backgroundWorker_RunSim.IsBusy)
                    Application.DoEvents();

                if (cb_GraphicsOff.Checked)
                {
                    label_Info.Text = "Run " + (run + 1).ToString() + " of " + numruns.ToString()
                        + " is running.";
                    label_Info.Refresh();

                    runSimStruct runSimArgs;
                    runSimArgs.outputFile = outputFile;
                    runSimArgs.run = run;

                    backgroundWorker_RunSim.RunWorkerAsync(runSimArgs);
                    while (backgroundWorker_RunSim.IsBusy)
                        Application.DoEvents();
                }
                else
                {
                    label_Info.Text = "Visualizer Running";
                    label_Info.Refresh();
                    currTimeTick = 0;
                    timerDraw.Tick += new EventHandler(runVisualizer);
                    timerDraw.Start();
                }
            }

            if (cb_GraphicsOff.Checked)
            {// Press "stop"
                EventArgsMessage args = new EventArgsMessage("Simulation Complete.");
                btn_Stop_Sim_Click(sender, args);
                enableConfigurationMultirun();
            }

            simInfoFile.Close();
        }
        CircleReport generateStaticReport(double time, XYDoubleLocation eventCenter)
        {
            GraphicsPath gradientPath = new GraphicsPath();
            gradientPath.AddEllipse((float)eventCenter.X, (float)eventCenter.Y,
                (float)(eventSize), (float)(eventSize));

            CircleReport circReport = new CircleReport(time, eventCenter, eventSize * 2,
                gradientPath, true, -1);
            circReport.Color = ColorEnum.FlashOverride;
            circReport.FinalColor = ColorEnum.Transparent;

            circReport.Layer = DrawLayer.Background;

            return circReport;
        }
        public void GenerateEvent(double time, ILocation location)
        {
            // Overloads GenerateEvent to allow the simulation to provide the time the event occurs.
            XYDoubleLocation initalCorner = (XYDoubleLocation)field[0];  // Casting to xyLocation objects. Other
            XYDoubleLocation finalCorner = (XYDoubleLocation)field[1];     // coordinate systems are not supported.

            List<PEQNode> nodesInRange = new List<PEQNode>();

            // Generate the random center location of the event.
            eventCenter = (XYDoubleLocation)location;

            eventCenter.SetField(field);

            Notify(generateStaticReport(time, eventCenter));

            foreach (PEQNode node in nodes.NodeQueue)
            { // Find which nodes are within the effective detection area.
                if (eventCenter.Distance(node.Location) <= eventSize) // if in the event area
                    nodesInRange.Add(node);
            }

            double eventTime = 0;
            for (int i = 0; i < this.numOccurances; i++)
            {
                eventTime = time + i / this.eventFreq;

                foreach (PEQNode node in nodesInRange)
                {
                    PEQMessageApplication appMsg = new PEQMessageApplication(); // Create a new app message
                    appMsg._Data._DataID = _dataID++;
                    MessageEvent msgEvent = new MessageEvent(appMsg); // create a new message event
                    msgEvent.Referrer = node; // set the referrer to the current node

                    PEQDataInfoReport rep = new PEQDataInfoReport(node.ID, eventTime);
                    rep._Sent = 1;
                    rep._DataID = appMsg._Data._DataID;
                    Notify(rep);

                    PEQTimerInternal messageTimer = new PEQTimerInternal(appMsg, eventTime, node);
                    eventMgr.AddEvent(messageTimer);   // add the event to the Event Queue.
                }
            }

            SimulationCompleteEvent simCompleteEvent = new SimulationCompleteEvent(nodes);
            simCompleteEvent.Time = eventTime + 60; // one minute after last event occurs
            eventMgr.AddEvent(simCompleteEvent);
        }
        public void GenerateEvent()
        {
            // Rather than setting a random time, in this case the event is simply generated when specified.
            XYDoubleLocation initalCorner = (XYDoubleLocation)field[0];  // Casting to xyLocation objects. Other
            XYDoubleLocation finalCorner = (XYDoubleLocation)field[1];     // coordinate systems are not supported.

            XYDoubleLocation location;

            for (int i = 0; i < 5; i++)
            {
                location = new XYDoubleLocation(initalCorner.X,
                    i*(finalCorner.Y-initalCorner.Y)/4);

                GenerateEvent(location);
            }
        }
        public void GenerateEvent(double time, ILocation location)
        {
            // Overloads GenerateEvent to allow the simulation to provide the time the event occurs.
            XYDoubleLocation initalCorner = (XYDoubleLocation)field[0];  // Casting to xyLocation objects. Other
            XYDoubleLocation finalCorner = (XYDoubleLocation)field[1];     // coordinate systems are not supported.

            // Generate the random center location of the event.
            eventCenter = (XYDoubleLocation)location;

            eventCenter.SetField(field);

            Notify(generateStaticReport(time, eventCenter));

            foreach (FloodingQueryNode node in nodes.NodeQueue)
            { // Find which nodes are within the effective detection area.
                if (eventCenter.Distance(node.Location) <= eventSize) // if in the event area
                {
                    FloodingQueryApplicationMessage appMsg = new FloodingQueryApplicationMessage(); // Create a new app message
                    MessageEvent msgEvent = new MessageEvent(appMsg); // create a new message event
                    msgEvent.Referrer = node; // set the referrer to the current node

                    NodeTimerEvent timerEvent = new NodeTimerEvent();   // create a timer event
                    timerEvent.Time = time;
                    timerEvent.Event = msgEvent;                        // apply the message event
                    timerEvent.node = node;
                    eventMgr.AddEvent(timerEvent);                      // add the event to the Event Queue.
                }
            }
        }
        public void GenerateEvent()
        {
            // Rather than setting a random time, in this case the event is simply generated at 15 seconds.
            XYDoubleLocation initalCorner = (XYDoubleLocation)field[0];  // Casting to xyLocation objects. Other
            XYDoubleLocation finalCorner = (XYDoubleLocation)field[1];     // coordinate systems are not supported.

            XYDoubleLocation location = new XYDoubleLocation((float)(randomizer.NextDouble() * (finalCorner.X - initalCorner.X) + initalCorner.X),
                (float)(randomizer.NextDouble() * (finalCorner.Y - initalCorner.Y) + initalCorner.Y));
            GenerateEvent(location);

            SimulationCompleteEvent simCompleteEvent = new SimulationCompleteEvent(nodes);
            simCompleteEvent.Time = eventMeanTime + 60; // one minute after event occurs
            eventMgr.AddEvent(simCompleteEvent);
        }
        public void Deploy()
        {
            if (!isInitialized)
                throw new InvalidOperationException("RandomDeployer not initialized!");

            XYDoubleLocation center, current;
            center = new XYDoubleLocation((field[0].X + field[1].X) / 2, (field[0].Y + field[1].Y) / 2);

            List<XYDoubleLocation> pointList = new List<XYDoubleLocation>();

            //rand = randFactory.CreateRandomizer();

            bool continueFlag = true;

            int i = 0;
            double s = 2 * Math.PI * b;  // For l=pi*s*n^2
            double n, theta, l, r, x, y;
            while (continueFlag)
            {
                l = i * nodeDistance;
                n = Math.Sqrt(l / (Math.PI * s));
                theta = 2 * Math.PI * n;

                r = a + b * theta;
                x = r * Math.Cos(theta) + center.X;
                y = r * Math.Sin(theta) + center.Y;

                current = new XYDoubleLocation(x, y);
                current.SetField(field);

                if (current.InField())
                    nodes.AddNode(nodeFactory.CreateNode(current));
                else
                    continueFlag = false;
                i++;
            }
        }
 public LineReport(double time, XYDoubleLocation nearLoc, XYDoubleLocation farLoc,
     double distance, double length, bool isStatic, int id)
     : this(time, nearLoc, farLoc, distance, length)
 {
     this.isStatic = isStatic;
     this.id = id;
     if (isStatic) layer = DrawLayer.Static;
 }
        public void Deploy()
        {
            if (!isInitialized)
                throw new InvalidOperationException("RandomDeployer not initialized!");

            List<XYDoubleLocation> pointList = new List<XYDoubleLocation>();

            rand = randFactory.CreateRandomizer();

            bool continueFlag;
            XYDoubleLocation initial, final, current;
            initial = (XYDoubleLocation)field[0];
            final = (XYDoubleLocation)field[1];
            current = new XYDoubleLocation();

            // Sink
            current = new XYDoubleLocation(final.X, (final.Y - initial.Y)/2);
            current.SetField(field);
            nodes.AddNode(nodeFactory.CreateNode(current));
            pointList.Add(current);
            nodes.GetNodeByID(0).IsSink = true;

            // Sources
            for (int i = 1; i < 6; i++)
            {
                current = new XYDoubleLocation(initial.X, (i-1)*(final.Y-initial.Y)/4);
                current.SetField(field);
                nodes.AddNode(nodeFactory.CreateNode(current));
                pointList.Add(current);
            }

            // Node Field
            for (int i = 6; i < numNodes; i++)
            {
                continueFlag = false;
                while (!continueFlag)
                {
                    continueFlag = true;
                    current = new XYDoubleLocation(
                        rand.NextDouble() * (final.X - initial.X - 2 * padding) + initial.X + padding,
                        rand.NextDouble() * (final.Y - initial.Y - 2 * padding) + initial.Y + padding);
                    foreach (XYDoubleLocation point in pointList)
                    {
                        if (current.Distance(point) < minDistance)
                            continueFlag = false;
                    }
                }
                pointList.Add(current);
                current.SetField(field);
                nodes.AddNode(nodeFactory.CreateNode(current));
            }
        }
        public void GenerateEvent()
        {
            // Rather than setting a random time, in this case the event is simply generated when specified.
            XYDoubleLocation initalCorner = (XYDoubleLocation)field[0];  // Casting to xyLocation objects. Other
            XYDoubleLocation finalCorner = (XYDoubleLocation)field[1];     // coordinate systems are not supported.

            XYDoubleLocation location = new XYDoubleLocation((float)(randomizer.NextDouble() * (finalCorner.X - initalCorner.X) + initalCorner.X),
                (float)(randomizer.NextDouble() * (finalCorner.Y - initalCorner.Y) + initalCorner.Y));

            GenerateEvent(location);
        }
        public void Deploy()
        {
            if (!isInitialized)
                throw new InvalidOperationException("GridDeployer not initialized!");

            double x, y;
            XYDoubleLocation initial, final, current;
            initial = (XYDoubleLocation)field[0];
            final = (XYDoubleLocation)field[1];

            for (x = initial.X + padding; x <= final.X - padding; x += nodeDistance)
                for (y = initial.Y + padding; y <= final.Y - padding; y += nodeDistance)
                {
                    current = new XYDoubleLocation(x, y);
                    current.SetField(field);
                    nodes.AddNode(nodeFactory.CreateNode(current));  // Creates a node using the factory and adds it to the collection.
                }
        }