Пример #1
0
        public static Image <Rgb24> FrameSliceOf3DSpectrogram_DayOfYear(Image <Rgb24> bmp1, Image <Rgb24> titleBar, int year, int dayOfYear, TimeSpan xInterval, int herzValue, FileInfo sunriseSetData, int nyquistFreq)
        {
            Image <Rgb24> suntrack = SunAndMoon.AddSunTrackToImage(bmp1.Width, sunriseSetData, year, dayOfYear);

            bmp1.Mutate(g =>
            {
                Pen pen        = new Pen(Color.White, 1);
                var stringFont = Drawing.Arial12;

                //Font stringFont = Drawing.Tahoma9;

                DateTime theDate  = new DateTime(year, 1, 1).AddDays(dayOfYear - 1);
                string dateString = $"{year} {DataTools.MonthNames[theDate.Month - 1]} {theDate.Day:d2}";
                g.DrawText(dateString, stringFont, Color.Wheat, new PointF(10, 3));
            });

            TimeSpan xAxisPixelDuration = TimeSpan.FromSeconds(60);
            var      minuteOffset       = TimeSpan.Zero;
            double   secondsDuration    = xAxisPixelDuration.TotalSeconds * bmp1.Width;
            TimeSpan fullDuration       = TimeSpan.FromSeconds(secondsDuration);

            // init frequency scale
            int herzInterval = 1000;
            int frameSize    = bmp1.Height;
            var freqScale    = new DSP.FrequencyScale(nyquistFreq, frameSize, herzInterval);

            SpectrogramTools.DrawGridLinesOnImage((Image <Rgb24>)bmp1, minuteOffset, fullDuration, xInterval, freqScale);

            int trackHeight      = 20;
            int imageHt          = bmp1.Height + trackHeight + trackHeight + trackHeight;
            var xAxisTicInterval = TimeSpan.FromMinutes(60); // assume 60 pixels per hour
            var timeScale24Hour  = ImageTrack.DrawTimeTrack(fullDuration, minuteOffset, xAxisTicInterval, bmp1.Width, trackHeight, "hours");

            var imageList = new List <Image <Rgb24> >
            {
                titleBar,
                timeScale24Hour,
                suntrack,
                bmp1,
                timeScale24Hour
            };
            var compositeBmp = ImageTools.CombineImagesVertically(imageList);

            // trackHeight = compositeBmp.Height;
            // Image<Rgb24> timeScale12Months = ImageTrack.DrawYearScaleVertical(40, trackHeight);
            // Image<Rgb24> freqScale = DrawFreqScale_vertical(40, trackHeight, HerzValue, nyquistFreq);

            imageList = new List <Image <Rgb24> >();

            // imageList.Add(timeScale12Months);
            imageList.Add(compositeBmp);

            // imageList.Add(freqScale);
            compositeBmp = ImageTools.CombineImagesInLine(imageList.ToArray());

            return(compositeBmp);
        }
Пример #2
0
        public static Image FrameSliceOf3DSpectrogram_DayOfYear(Image bmp1, Image titleBar, int year, int dayOfYear, TimeSpan xInterval, int herzValue, FileInfo sunriseSetData, int nyquistFreq)
        {
            Bitmap suntrack = SunAndMoon.AddSunTrackToImage(bmp1.Width, sunriseSetData, year, dayOfYear);

            Graphics g          = Graphics.FromImage(bmp1);
            Pen      pen        = new Pen(Color.White);
            Font     stringFont = new Font("Arial", 12);

            //Font stringFont = new Font("Tahoma", 9);

            DateTime theDate    = new DateTime(year, 1, 1).AddDays(dayOfYear - 1);
            string   dateString = string.Format("{0} {1} {2:d2}", year, DataTools.MonthNames[theDate.Month - 1], theDate.Day);

            g.DrawString(dateString, stringFont, Brushes.Wheat, new PointF(10, 3));

            TimeSpan xAxisPixelDuration = TimeSpan.FromSeconds(60);
            var      minuteOffset       = TimeSpan.Zero;
            double   secondsDuration    = xAxisPixelDuration.TotalSeconds * bmp1.Width;
            TimeSpan fullDuration       = TimeSpan.FromSeconds(secondsDuration);

            // init frequency scale
            int herzInterval = 1000;
            int frameSize    = bmp1.Height;
            var freqScale    = new DSP.FrequencyScale(nyquistFreq, frameSize, herzInterval);

            SpectrogramTools.DrawGridLinesOnImage((Bitmap)bmp1, minuteOffset, fullDuration, xInterval, freqScale);

            int trackHeight      = 20;
            int imageHt          = bmp1.Height + trackHeight + trackHeight + trackHeight;
            var xAxisTicInterval = TimeSpan.FromMinutes(60); // assume 60 pixels per hour
            var timeScale24Hour  = ImageTrack.DrawTimeTrack(fullDuration, minuteOffset, xAxisTicInterval, bmp1.Width, trackHeight, "hours");

            var imageList = new List <Image>();

            imageList.Add(titleBar);
            imageList.Add(timeScale24Hour);
            imageList.Add(suntrack);
            imageList.Add(bmp1);
            imageList.Add(timeScale24Hour);
            Image compositeBmp = ImageTools.CombineImagesVertically(imageList.ToArray());

            // trackHeight = compositeBmp.Height;
            // Bitmap timeScale12Months = ImageTrack.DrawYearScaleVertical(40, trackHeight);
            // Bitmap freqScale = DrawFreqScale_vertical(40, trackHeight, HerzValue, nyquistFreq);

            imageList = new List <Image>();

            // imageList.Add(timeScale12Months);
            imageList.Add(compositeBmp);

            // imageList.Add(freqScale);
            compositeBmp = ImageTools.CombineImagesInLine(imageList.ToArray());

            return(compositeBmp);
        }
Пример #3
0
        public static Image FrameSliceOf3DSpectrogram_ConstantFreq(Image bmp1, Image titleBar, TimeSpan xInterval, int herzValue, FileInfo sunriseSetData, int nyquistFreq)
        {
            SunAndMoon.AddSunRiseSetLinesToImage((Bitmap)bmp1, sunriseSetData, 0, 365, 1); // assume full year and 1px/day

            var g          = Graphics.FromImage(bmp1);
            var pen        = new Pen(Color.White);
            var stringFont = new Font("Arial", 12);
            var str        = $"Freq = {herzValue} Hz";

            g.DrawString(str, stringFont, Brushes.Wheat, new PointF(10, 7));

            var    xAxisPixelDuration = TimeSpan.FromSeconds(60);
            var    startOffset        = TimeSpan.Zero;
            double secondsDuration    = xAxisPixelDuration.TotalSeconds * bmp1.Width;
            var    fullDuration       = TimeSpan.FromSeconds(secondsDuration);

            // init frequency scale
            int herzInterval = 1000;
            int frameSize    = bmp1.Height;
            var freqScale    = new DSP.FrequencyScale(nyquistFreq, frameSize, herzInterval);

            SpectrogramTools.DrawGridLinesOnImage((Bitmap)bmp1, startOffset, fullDuration, xInterval, freqScale);

            int trackHeight      = 20;
            var xAxisTicInterval = TimeSpan.FromMinutes(60); // assume 60 pixels per hour
            var timeScale24Hour  = ImageTrack.DrawTimeTrack(fullDuration, startOffset, xAxisTicInterval, bmp1.Width, trackHeight, "hours");

            var imageList = new List <Image> {
                titleBar, timeScale24Hour, bmp1, timeScale24Hour
            };
            var compositeBmp = ImageTools.CombineImagesVertically(imageList.ToArray());

            if (compositeBmp == null)
            {
                throw new ArgumentNullException(nameof(compositeBmp));
            }

            trackHeight = compositeBmp.Height;
            Bitmap timeScale12Months = ImageTrack.DrawYearScaleVertical(40, trackHeight);
            Bitmap freqScaleImage    = DrawFreqScale_vertical(40, trackHeight, herzValue, nyquistFreq);

            imageList = new List <Image> {
                timeScale12Months, compositeBmp, freqScaleImage
            };
            compositeBmp = ImageTools.CombineImagesInLine(imageList.ToArray());

            return(compositeBmp);
        }
Пример #4
0
        /// <summary>
        /// Converts summary indices to a tracks image
        /// </summary>
        /// <param name="listOfIndexProperties"></param>
        /// <param name="dictionaryOfSummaryIndices"></param>
        /// <param name="titleText"></param>
        /// <param name="indexCalculationDuration"></param>
        /// <param name="recordingStartDate"></param>
        /// <param name="sunriseDataFile"></param>
        /// <param name="errors"></param>
        public static Bitmap DrawImageOfSummaryIndices(
            Dictionary <string, IndexProperties> listOfIndexProperties,
            Dictionary <string, double[]> dictionaryOfSummaryIndices,
            string titleText,
            TimeSpan indexCalculationDuration,
            DateTimeOffset?recordingStartDate,
            FileInfo sunriseDataFile   = null,
            List <GapsAndJoins> errors = null,
            bool verbose = false)
        {
            // to translate past keys into current keys
            Dictionary <string, string> translationDictionary = InitialiseIndexProperties.GetKeyTranslationDictionary();

            const int trackHeight = DefaultTrackHeight;
            int       scaleLength = 0;
            var       bitmapList  = new List <Tuple <IndexProperties, Image> >(dictionaryOfSummaryIndices.Keys.Count);

            // accumulate the individual tracks in a List
            foreach (string key in dictionaryOfSummaryIndices.Keys)
            {
                string correctKey = key;
                if (!listOfIndexProperties.ContainsKey(key))
                {
                    if (translationDictionary.ContainsKey(key))
                    {
                        correctKey = translationDictionary[key];
                        LoggedConsole.WriteWarnLine(
                            "The csv header is an unknown index <{0}>. Translated to <{1}>",
                            key,
                            correctKey);
                    }
                    else
                    {
                        if (verbose)
                        {
                            Logger.Warn(
                                "A index properties configuration could not be found for {0} (not even in the translation directory). Property is ignored and not rendered"
                                .Format2(key));
                        }

                        continue;
                    }
                }

                IndexProperties ip = listOfIndexProperties[correctKey];
                if (!ip.DoDisplay)
                {
                    continue;
                }

                string   name  = ip.Name;
                double[] array = dictionaryOfSummaryIndices[key];
                scaleLength = array.Length;
                Image bitmap = ip.GetPlotImage(array, errors);

                bitmapList.Add(Tuple.Create(ip, bitmap));
            }

            var listOfBitmaps = bitmapList
                                .OrderBy(tuple => tuple.Item1.Order)
                                .Select(tuple => tuple.Item2)
                                .Where(b => b != null).ToList();

            //set up the composite image parameters
            int      X_offset      = 2;
            int      graphWidth    = X_offset + scaleLength;
            int      imageWidth    = X_offset + scaleLength + TrackEndPanelWidth;
            TimeSpan scaleDuration = TimeSpan.FromMinutes(scaleLength);
            int      imageHt       = trackHeight * (listOfBitmaps.Count + 4); //+3 for title and top and bottom time tracks
            Bitmap   titleBmp      = ImageTrack.DrawTitleTrack(imageWidth, trackHeight, titleText);

            //Bitmap time1Bmp = ImageTrack.DrawTimeTrack(scaleDuration, TimeSpan.Zero, DrawSummaryIndices.TimeScale, graphWidth, TrackHeight, "Time (hours)");
            TimeSpan       xAxisPixelDuration = indexCalculationDuration;
            TimeSpan       fullDuration       = TimeSpan.FromTicks(xAxisPixelDuration.Ticks * graphWidth);
            Bitmap         timeBmp1           = ImageTrack.DrawTimeRelativeTrack(fullDuration, graphWidth, trackHeight);
            Bitmap         timeBmp2           = timeBmp1;
            Bitmap         suntrack           = null;
            DateTimeOffset?dateTimeOffset     = recordingStartDate;

            if (dateTimeOffset.HasValue)
            {
                // draw extra time scale with absolute start time. AND THEN Do SOMETHING WITH IT.
                timeBmp2 = ImageTrack.DrawTimeTrack(fullDuration, dateTimeOffset, graphWidth, trackHeight);
                suntrack = SunAndMoon.AddSunTrackToImage(scaleLength, dateTimeOffset, sunriseDataFile);
            }

            //draw the composite bitmap
            var imageList = new List <Image>();

            imageList.Add(titleBmp);
            imageList.Add(timeBmp1);
            for (int i = 0; i < listOfBitmaps.Count; i++)
            {
                imageList.Add(listOfBitmaps[i]);
            }

            imageList.Add(timeBmp2);
            imageList.Add(suntrack);
            Bitmap compositeBmp = (Bitmap)ImageTools.CombineImagesVertically(imageList);

            return(compositeBmp);
        }
Пример #5
0
        public static void Execute(Arguments arguments)
        {
            var inputDirs = arguments.InputDataDirectories.Select(FileInfoExtensions.ToDirectoryInfo);
            var output    = arguments.OutputDirectory.ToDirectoryInfo();

            string date = "# DATE AND TIME: " + DateTime.Now;

            LoggedConsole.WriteLine("\n# DRAW an EASY IMAGE from consecutive days of SUMMARY INDICES in CSV files.");
            LoggedConsole.WriteLine("#    IT IS ASSUMED THAT THE CSV files are already concatenated into 24 hour files.");
            LoggedConsole.WriteLine(date);
            LoggedConsole.WriteLine("# Summary Index.csv files are in directories:");
            foreach (DirectoryInfo dir in inputDirs)
            {
                LoggedConsole.WriteLine("    {0}", dir.FullName);
            }

            LoggedConsole.WriteLine("# Output directory: " + output);
            if (arguments.StartDate == null)
            {
                LoggedConsole.WriteLine("# Start date = NULL (No argument provided). Will revise start date ....");
            }
            else
            {
                LoggedConsole.WriteLine("# Start date = " + arguments.StartDate.ToString());
            }

            if (arguments.EndDate == null)
            {
                LoggedConsole.WriteLine("# End   date = NULL (No argument provided). Will revise end date ....");
            }
            else
            {
                LoggedConsole.WriteLine("# End   date = " + arguments.EndDate.ToString());
            }

            LoggedConsole.WriteLine("# FILE FILTER = " + arguments.FileFilter);
            LoggedConsole.WriteLine();

            // PATTERN SEARCH FOR SUMMARY INDEX FILES.
            //string pattern = "*__Towsey.Acoustic.Indices.csv";
            FileInfo[] csvFiles = IndexMatrices.GetFilesInDirectories(inputDirs.ToArray(), arguments.FileFilter);

            //LoggedConsole.WriteLine("# Subdirectories Count = " + subDirectories.Length);
            LoggedConsole.WriteLine("# SummaryIndexFiles.csv Count = " + csvFiles.Length);

            if (csvFiles.Length == 0)
            {
                LoggedConsole.WriteErrorLine("\n\nWARNING from method DrawEasyImage.Execute():");
                LoggedConsole.WriteErrorLine("        No SUMMARY index files were found.");
                LoggedConsole.WriteErrorLine("        RETURNING EMPTY HANDED!");
                return;
            }

            // Sort the files by date and return as a dictionary: sortedDictionaryOfDatesAndFiles<DateTimeOffset, FileInfo>
            //var sortedDictionaryOfDatesAndFiles = LDSpectrogramStitching.FilterFilesForDates(csvFiles, arguments.TimeSpanOffsetHint);

            // calculate new start date if passed value = null.
            DateTimeOffset?startDate = arguments.StartDate;
            DateTimeOffset?endDate   = arguments.EndDate;

            TimeSpan totalTimespan = (DateTimeOffset)endDate - (DateTimeOffset)startDate;
            int      dayCount      = totalTimespan.Days + 1; // assume last day has full 24 hours of recording available.

            LoggedConsole.WriteLine("\n# Start date = " + startDate.ToString());
            LoggedConsole.WriteLine("# End   date = " + endDate.ToString());
            LoggedConsole.WriteLine(string.Format("# Elapsed time = {0:f1} hours", dayCount * 24));
            LoggedConsole.WriteLine("# Day  count = " + dayCount + " (inclusive of start and end days)");
            LoggedConsole.WriteLine("# Time Zone  = " + arguments.TimeSpanOffsetHint.ToString());

            // create top level output directory if it does not exist.
            DirectoryInfo opDir = output;

            if (!opDir.Exists)
            {
                opDir.Create();
            }

            // SET UP DEFAULT SITE LOCATION INFO    --  DISCUSS IWTH ANTHONY
            // The following location data is used only to draw the sunrise/sunset tracks on images.
            double?latitude        = null;
            double?longitude       = null;
            var    siteDescription = new SiteDescription();

            siteDescription.SiteName  = arguments.FileStemName;
            siteDescription.Latitude  = latitude;
            siteDescription.Longitude = longitude;

            // the following required if drawing the index images
            FileInfo indexPropertiesConfig = null;

            // require IndexGenerationData and indexPropertiesConfig for drawing
            //indexGenerationData = IndexGenerationData.GetIndexGenerationData(csvFiles[0].Directory);
            indexPropertiesConfig = arguments.IndexPropertiesConfig.ToFileInfo();
            Dictionary <string, IndexProperties>    listOfIndexProperties = IndexProperties.GetIndexProperties(indexPropertiesConfig);
            Tuple <List <string>, List <double[]> > tuple = CsvTools.ReadCSVFile(csvFiles[0].FullName);
            var names = tuple.Item1;

            // default EASY indices
            int    redID = 3; // backgroundNoise
            int    grnID = 5; // avSNROfActiveframes
            int    bluID = 7; // events per second
            string rep   = @"bgn-avsnr-evn";

            // ACI Ht Hpeaks EASY indices
            if (false)
            {
                redID = 11;  // ACI
                grnID = 12;  // Ht

                //bluID = 13;  // HavgSp
                //bluID = 14;  // Hvariance
                //bluID = 15;  // Hpeaks
                bluID = 16;  // Hcov

                //bluID = 7;  // SPT
                rep = @"aci-ht-hcov";

                //rep = @"aci-ht-spt";
            }

            // LF, MF, HF
            if (true)
            {
                redID = 10;  // LF
                grnID = 9;   // MF
                bluID = 8;   // HF
                rep   = @"lf-mf-hf";
            }

            IndexProperties redIndexProps = listOfIndexProperties[names[redID]];
            IndexProperties grnIndexProps = listOfIndexProperties[names[grnID]];
            IndexProperties bluIndexProps = listOfIndexProperties[names[bluID]];

            int dayPixelHeight = 4;
            int rowCount       = (dayPixelHeight * dayCount) + 35; // +30 for grid lines
            int colCount       = 1440;
            var bitmap         = new Image <Rgb24>(colCount, rowCount);
            var colour         = Color.Yellow;
            int currentRow     = 0;
            var oneDay         = TimeSpan.FromHours(24);
            int graphWidth     = colCount;
            int trackHeight    = 20;
            var stringFont     = Drawing.Arial8;

            string[] monthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

            // for drawing the y-axis scale
            int scaleWidth = trackHeight + 7;
            var yAxisScale = new Image <Rgb24>(scaleWidth, rowCount + (2 * trackHeight));

            yAxisScale.Mutate(g =>
            {
                g.Clear(Color.Black);

                // loop over days
                for (int d = 0; d < dayCount; d++)
                {
                    var thisday = ((DateTimeOffset)startDate).AddDays(d);

                    if (thisday.Day == 1)
                    {
                        int nextRow = currentRow + 1;
                        for (int c = 0; c < colCount; c++)
                        {
                            bitmap[c, currentRow] = Color.Gray;
                            bitmap[c, nextRow]    = Color.Gray;
                        }

                        for (int c = 0; c < scaleWidth; c++)
                        {
                            yAxisScale[c, currentRow + trackHeight] = Color.Gray;
                            yAxisScale[c, nextRow + trackHeight]    = Color.Gray;
                        }

                        string month = monthNames[thisday.Month - 1];
                        if (thisday.Month == 1) // January
                        {
                            g.DrawText(thisday.Year.ToString(), stringFont, Color.White,
                                       new PointF(0, nextRow + trackHeight + 1));  //draw time
                            g.DrawText(month, stringFont, Color.White,
                                       new PointF(1, nextRow + trackHeight + 11)); //draw time
                        }
                        else
                        {
                            g.DrawText(month, stringFont, Color.White,
                                       new PointF(1, nextRow + trackHeight + 1)); //draw time
                        }

                        currentRow += 2;
                    }

                    // get the exact date and time
                    LoggedConsole.WriteLine($"READING DAY {d + 1} of {dayCount}:   {thisday.ToString()}");

                    // CREATE DAY LEVEL OUTPUT DIRECTORY for this day
                    string dateString = $"{thisday.Year}{thisday.Month:D2}{thisday.Day:D2}";

                    tuple      = CsvTools.ReadCSVFile(csvFiles[d].FullName);
                    var arrays = tuple.Item2;

                    var redArray = arrays[redID];
                    var grnArray = arrays[grnID];
                    var bluArray = arrays[bluID];

                    // NormaliseMatrixValues the indices
                    redArray = DataTools.NormaliseInZeroOne(redArray, redIndexProps.NormMin, redIndexProps.NormMax);
                    grnArray = DataTools.NormaliseInZeroOne(grnArray, grnIndexProps.NormMin, grnIndexProps.NormMax);
                    bluArray = DataTools.NormaliseInZeroOne(bluArray, bluIndexProps.NormMin, bluIndexProps.NormMax);

                    for (int c = 0; c < colCount; c++)
                    {
                        for (int r = 0; r < dayPixelHeight; r++)
                        {
                            //transformedValue = Math.Sqrt(redArray[c]);
                            var transformedValue = redArray[c] * redArray[c];
                            int redVal           = (int)Math.Round(transformedValue * 255);
                            if (redVal < 0)
                            {
                                redVal = 0;
                            }
                            else if (redVal > 255)
                            {
                                redVal = 255;
                            }

                            //transformedValue = Math.Sqrt(grnArray[c]);
                            transformedValue = grnArray[c] * grnArray[c]; // square the value
                            int grnVal       = (int)Math.Round(transformedValue * 255);
                            if (grnVal < 0)
                            {
                                grnVal = 0;
                            }
                            else if (grnVal > 255)
                            {
                                grnVal = 255;
                            }

                            //transformedValue = Math.Sqrt(bluArray[c]);
                            transformedValue = bluArray[c] * bluArray[c]; // square the value
                            int bluVal       = (int)Math.Round(transformedValue * 255);
                            if (bluVal < 0)
                            {
                                bluVal = 0;
                            }
                            else if (bluVal > 255)
                            {
                                bluVal = 255;
                            }

                            bitmap[c, currentRow + r] = Color.FromRgb((byte)redVal, (byte)grnVal, (byte)bluVal);
                        }
                    } // over all columns

                    currentRow += dayPixelHeight;

                    if (thisday.Day % 7 == 0)
                    {
                        for (int c = 0; c < colCount; c++)
                        {
                            bitmap[c, currentRow] = Color.Gray;
                        }

                        currentRow++;
                    }
                } // over days
            });
            // draw on civil dawn and dusk lines
            int startdayOfYear = ((DateTimeOffset)startDate).DayOfYear;
            int endDayOfYear   = ((DateTimeOffset)endDate).DayOfYear;

            SunAndMoon.AddSunRiseSetLinesToImage(bitmap, arguments.BrisbaneSunriseDatafile.ToFileInfo(), startdayOfYear, endDayOfYear, dayPixelHeight);

            // add the time scales
            Image <Rgb24> timeBmp1      = ImageTrack.DrawTimeRelativeTrack(oneDay, graphWidth, trackHeight);
            var           imageList     = new [] { timeBmp1, bitmap, timeBmp1 };
            Image <Rgb24> compositeBmp1 = (Image <Rgb24>)ImageTools.CombineImagesVertically(imageList);

            imageList = new [] { yAxisScale, compositeBmp1 };
            Image <Rgb24> compositeBmp2 = (Image <Rgb24>)ImageTools.CombineImagesInLine(imageList);

            // indices used for image
            string        indicesDescription = $"{redIndexProps.Name}|{grnIndexProps.Name}|{bluIndexProps.Name}";
            string        startString        = $"{startDate.Value.Year}/{startDate.Value.Month}/{startDate.Value.Day}";
            string        endString          = $"{endDate.Value.Year}/{endDate.Value.Month}/{endDate.Value.Day}";
            string        title    = $"EASY:   {arguments.FileStemName}    From {startString} to {endString}                          Indices: {indicesDescription}";
            Image <Rgb24> titleBar = ImageTrack.DrawTitleTrack(compositeBmp2.Width, trackHeight, title);

            imageList     = new [] { titleBar, compositeBmp2 };
            compositeBmp2 = (Image <Rgb24>)ImageTools.CombineImagesVertically(imageList);
            var outputFileName = Path.Combine(opDir.FullName, arguments.FileStemName + "." + rep + ".EASY.png");

            compositeBmp2.Save(outputFileName);
        } // Execute()
Пример #6
0
    //画面を更新する(球体地図)
    public void updateScreen2()
    {
        double hinode_keido, hinoiri_keido, asayake, higure;
        int    hinoiriX = 0, hinodeX = 0;
        int    asayakeX = 0, higureX = 0;
        double x, y;
        double halfPI = Math.PI / 2.0;

        //double scrDist = (scrWidth / 2.0) / Math.Tan(scrAngle / 180.0 * Math.PI);

        //if (screen == null | screen2 == null) return;

        //イメージを初期化

        Color opaque = new Color(0, 0, 0, 0);

        for (int i = 0; i < shadow.width; i++)
        {
            for (int j = 0; j < shadow.height; j++)
            {
                shadow.SetPixel(i, j, opaque);
            }
        }

        EquatorialCoordinate sun  = new EquatorialCoordinate();
        EquatorialCoordinate moon = new EquatorialCoordinate();

        double[] result   = new double[3];
        double[] result2  = new double[3];
        double[] location = new double[2];
        double   asc      = 0.0;
        double   dec      = 0.0;
        double   moonasc  = 0.0;
        double   moondec  = 0.0;

        try
        {
            SunAndMoon.getSunRightAscension(utc, result);
            sun.setRightAscension(result[0]);
            sun.setCelestialDeclination(result[1]);
            sun.setDistance(result[2]);
            asc = result[0]; //赤経
            dec = result[1]; //赤緯

            SunAndMoon.getMoonRightAscension(utc, result);
            moon.setRightAscension(result[0]);
            moon.setCelestialDeclination(result[1]);
            moon.setDistance(result[2]);
            moonasc = result[0];
            moondec = result[1];
        }
        catch (Exception) { Debug.Log("Exception1 ");  return; }

        double phai0 = Almanac.getGreenidgeSiderealTime(utc);//グリニッジ恒星時
        //恒星時をもとに、背景の回転を行う(恒星時は春分点の時角)
        Material skybox = RenderSettings.skybox;

        skybox.SetFloat("_Rotation", (float)-phai0);//時角のマイナス方向に回転。skyboxのマテリアルは左右が逆

        //太陽位置計算(orbiterと同じコード)
        {
            double Theta = phai0 - asc;
            if (Theta < 0)
            {
                Theta += 360.0;
            }
            double DegToRad    = Math.PI / 180;
            double denominator = (Math.Sin(dec * DegToRad) * Math.Cos(90.0 * DegToRad) - Math.Cos(dec * DegToRad) * Math.Sin(90.0 * DegToRad) * Math.Cos(Theta * DegToRad));
            double A           = Math.Atan((-Math.Cos(dec * DegToRad) * Math.Sin(Theta * DegToRad)) / denominator);
            double h           = Math.Asin(Math.Sin(dec * DegToRad) * Math.Sin(90.0 * DegToRad) + Math.Cos(dec * DegToRad) * Math.Cos(90.0 * DegToRad) * Math.Cos(Theta * DegToRad));
            A = A / DegToRad;
            h = h / DegToRad;
            //Arctanの象限を検討せよ
            if (denominator > 0)
            {
                //何故か解説書とは逆だが、分母が正の時に180度加算して象限を変える必要がある
                A += 180.0;
            }
            Vector3 sunvector = new Vector3(1.0f, 0.0f, 0.0f);
            sunvector = Quaternion.Euler(0.0f, 0.0f, (float)h) * sunvector;
            sunvector = Quaternion.Euler(0.0f, (float)A, 0.0f) * sunvector;


            float ratio = 1500.0f / sunvector.magnitude;
            sunvector *= ratio;

            GameObject game = GameObject.Find("Directional Light");
            if (game != null)
            {
                game.transform.position = sunvector;
                Vector3 forward = sunvector;
                forward.Normalize();
                game.transform.forward = -forward;
            }
        }
        //日の出・日の入りの同時線を描く

        double dist                 = sun.getDistance();
        double parallax             = SunAndMoon.getSunParallax(dist);//太陽視差
        double k                    = SunAndMoon.getSunriseAltitude(SunAndMoon.getSunDiameter(dist), 0.0, SunAndMoon.refraction, parallax);
        double celestialdeclination = sun.getCelestialDeclination();

        for (int i = -90; i < 90; i++)
        {
            //緯度を取得
            double latitude = i;//getLatitudeFromY(Yequator - i);

            //緯度を元に時角を計算する
            double jikaku = SunAndMoon.getTimeAngle(k, celestialdeclination, latitude);

            if (!Double.IsNaN(jikaku))//時角がNaNでない
            {
                hinode_keido  = SunAndMoon.reviseAngle(-jikaku + sun.getRightAscension() - phai0);
                hinoiri_keido = SunAndMoon.reviseAngle(jikaku + sun.getRightAscension() - phai0);
                //   hinodeX =(int)getXfromLongitude(hinode_keido);
                //   hinoiriX = (int)getXfromLongitude(hinoiri_keido);//昼側か調べる
                drawShadowTexture(hinode_keido, latitude, Color.white);
                drawShadowTexture(hinoiri_keido, latitude, Color.white);
            }
        }

        //輪郭の描画
        VesselElements ve = new VesselElements(sun, moon, utc);

        SolarEclipse.getCrossPoint(ve, result, result2);
        double maxQ = SolarEclipse.getPenumbralQ(ve, result);
        double minQ = SolarEclipse.getPenumbralQ(ve, result2);

        //Debug.Log("MaxQ = " + maxQ + " minQ = " + minQ);

        //月位置計算(orbiterと同じコード)
        {
            double Theta = phai0 - moonasc;
            if (Theta < 0)
            {
                Theta += 360.0;
            }
            double DegToRad    = Math.PI / 180;
            double denominator = (Math.Sin(moondec * DegToRad) * Math.Cos(90.0 * DegToRad) - Math.Cos(moondec * DegToRad) * Math.Sin(90.0 * DegToRad) * Math.Cos(Theta * DegToRad));
            double A           = Math.Atan((-Math.Cos(moondec * DegToRad) * Math.Sin(Theta * DegToRad)) / denominator);
            double h           = Math.Asin(Math.Sin(moondec * DegToRad) * Math.Sin(90.0 * DegToRad) + Math.Cos(moondec * DegToRad) * Math.Cos(90.0 * DegToRad) * Math.Cos(Theta * DegToRad));
            A = A / DegToRad;
            h = h / DegToRad;
            //Arctanの象限を検討せよ
            if (denominator > 0)
            {
                //何故か解説書とは逆だが、分母が正の時に180度加算して象限を変える必要がある
                A += 180.0;
            }
            Vector3 sunvector = new Vector3(1.0f, 0.0f, 0.0f);
            sunvector = Quaternion.Euler(0.0f, 0.0f, (float)h) * sunvector;
            sunvector = Quaternion.Euler(0.0f, (float)A, 0.0f) * sunvector;
            float ratio = (float)(moon.getDistance() * Constants.AUde * 3.16f) / sunvector.magnitude;
            sunvector *= ratio;

            //

            //      Debug.Log("moondist = " + moon.getDistance());
            GameObject game = GameObject.Find("Moon");
            if (game != null)
            {
                game.transform.position = sunvector;
            }
        }

        /*  Vector3 moonPos = new Vector3((float)ve.getX0(), (float)ve.getY0(), (float)ve.getZ0());
         *  moonPos.Normalize();
         *  moonPos *= 20;
         *  GameObject moonobj = GameObject.Find("Moon");
         *
         *  if (moonobj!= null)
         *   {
         *    moonobj.transform.position = moonPos;
         *   }
         */
        //半影の描画
        if (Double.IsNaN(maxQ) && Double.IsNaN(minQ))
        {
            double first_longitude = Double.NaN;
            double first_latitude  = Double.NaN;
            double last_longitude  = Double.NaN;
            double last_latitude   = Double.NaN;

            for (double i = 0.0; i <= 360.0; i += 0.2)
            {
                SolarEclipse.getPenumbralOutline(ve, i, result);
                if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2]))
                {
                    continue;                                                                     //NaNが含まれていたらスキップする
                }
                if (first_longitude == double.NaN | first_latitude == double.NaN)
                {
                    first_longitude = result[0];
                    first_latitude  = result[1];
                }
                last_longitude = result[0];
                last_latitude  = result[1];

                Coordinate.transformICRStoGCS(ve, result, location);
                drawShadowTexture(location[0], location[1], Color.red);
            }
            //Debug.Log(first_longitude + ":" + first_latitude + "::" + last_longitude + ":" + last_latitude);
        }
        else if (!Double.IsNaN(maxQ) && !Double.IsNaN(minQ))
        {
            double first_x = double.NaN;
            double first_y = double.NaN;
            double first_z = double.NaN;
            double last_x  = double.NaN;
            double last_y  = double.NaN;
            double last_z  = double.NaN;

            if ((maxQ - minQ) >= 0.0)
            {
                maxQ -= 360.0;
            }
            SolarEclipse.getPenumbralOutline(ve, maxQ, result);
            Coordinate.transformICRStoGCS(ve, result, location);
            //Debug.Log("MaxQ :" + location[0] + ":" + location[1]+ ":" + maxQ);
            SolarEclipse.getPenumbralOutline(ve, minQ, result);
            Coordinate.transformICRStoGCS(ve, result, location);
            //Debug.Log("MinQ :" + location[0] + ":" + location[1] + ":" + minQ);

            /*
             *    //maxQが通常の計算でNaNとなる場合に備えて、強制的に描画する。
             *    SolarEclipse.getPenumbralOutline(ve, maxQ, result);
             *    result[2] = -0.01;//強制的に基準面に設定する
             *    Coordinate.transformICRStoGCS(ve, result, location);
             *    drawShadowTexture(location[0], location[1], Color.black);
             */
            for (double i = maxQ /*Math.Ceiling(maxQ)*/; i < minQ; i += 0.2)
            {
                SolarEclipse.getPenumbralOutline(ve, i, result);
                if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2]))
                {
                    continue;                                                                     //NaNが含まれていたらスキップする
                }
                if (Double.IsNaN(first_x) | Double.IsNaN(first_y) | Double.IsNaN(first_z))
                {
                    first_x = result[0];
                    first_y = result[1];
                    first_z = result[2];
                }
                last_x = result[0];
                last_y = result[1];
                last_z = result[2];

                Coordinate.transformICRStoGCS(ve, result, location);

                drawShadowTexture(location[0], location[1], Color.red);
            }
            {
                SolarEclipse.getPenumbralOutline(ve, minQ, result);
                if (!Double.IsNaN(result[0]) & !Double.IsNaN(result[1]) & !Double.IsNaN(result[2]))
                {
                    Coordinate.transformICRStoGCS(ve, result, location);
                    last_x = result[0];
                    last_y = result[2];
                    last_z = result[1];
                    drawShadowTexture(location[0], location[1], Color.red);
                }
            }
            //drawClosingLine2(ve, first_x, first_y, first_z, last_x, last_y, last_z);
            //Debug.Log(first_longitude + ":" + first_latitude + "::" + last_longitude + ":" + last_latitude);

            /*
             *    //minQが通常の計算でNaNとなる場合に備えて、強制的に描画する。
             *    SolarEclipse.getPenumbralOutline(ve, minQ, result);
             *    result[2] = -0.01;//強制的に基準面に設定する
             *    Coordinate.transformICRStoGCS(ve, result, location);
             *    drawShadowTexture(location[0], location[1], Color.red);
             */
        }

        //本影の描画
        for (int i = 0; i <= 360; i += 5)
        {
            SolarEclipse.getUmbralOutline(ve, (double)i, result);
            if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2]))
            {
                continue;                                                                       //NaNが含まれていたらスキップする
            }
            Coordinate.transformICRStoGCS(ve, result, location);
            drawShadowTexture(location[0], location[1], Color.black);
        }
        GameObject earthobj = GameObject.Find("perfectsphere");

        Material[] mats = earthobj.GetComponent <Renderer>().materials;
        Debug.Log("elements =" + mats.Length);
        mats[0].SetTexture("_MainTex", (Texture)shadow);
        //mats[1].SetTexture("_EmissionMap", shadow);
        //repaint();
    }
Пример #7
0
    public void drawLines()
    {
        //テクスチャ初期化
        Color opaque = new Color(0, 0, 0, 0);

        for (int i = 0; i < shadow.width; i++)
        {
            for (int j = 0; j < shadow.height; j++)
            {
                shadow.SetPixel(i, j, opaque);
            }
        }

        EquatorialCoordinate sun  = new EquatorialCoordinate();
        EquatorialCoordinate moon = new EquatorialCoordinate();

        double[] result   = new double[3];
        double[] result2  = new double[3];
        double[] location = new double[2];
        double   asc      = 0.0;
        double   dec      = 0.0;
        double   moonasc  = 0.0;
        double   moondec  = 0.0;

        try
        {
            SunAndMoon.getSunRightAscension(utc, result);
            sun.setRightAscension(result[0]);
            sun.setCelestialDeclination(result[1]);
            sun.setDistance(result[2]);
            asc = result[0]; //赤経
            dec = result[1]; //赤緯

            SunAndMoon.getMoonRightAscension(utc, result);
            moon.setRightAscension(result[0]);
            moon.setCelestialDeclination(result[1]);
            moon.setDistance(result[2]);
            moonasc = result[0];
            moondec = result[1];
        }
        catch (Exception) { Debug.Log("Exception1 "); return; }

        double phai0 = Almanac.getGreenidgeSiderealTime(utc);//グリニッジ恒星時

        //太陽位置を計算してライトの位置と向きを変更する
        {
            //恒星時をもとに、背景の回転を行う(恒星時は春分点の時角)
            Material skybox = RenderSettings.skybox;
            skybox.SetFloat("_Rotation", (float)-phai0);//時角のマイナス方向に回転。skyboxのマテリアルは左右が逆

            //赤緯・赤経は北極から見て時計回り。自覚、恒星時は反時計回り。時角に合わせて計算する
            //float ramda = -(float)((-asc + phai0) * DegToRad);これを書き換えて下の式になる
            float ramda       = (float)((asc - phai0) * DegToRad);
            float psy         = (float)(dec * DegToRad);
            float sundistance = 400;
            float x           = Mathf.Cos(psy) * Mathf.Cos(ramda) * sundistance;
            float y           = Mathf.Cos(psy) * Mathf.Sin(ramda) * sundistance;
            float z           = Mathf.Sin(psy) * sundistance;

            GameObject light  = GameObject.Find("Directional Light");
            Vector3    sunpos = light.transform.position;
            sunpos.Set(x, z, y);
            light.transform.position = sunpos;
            sunpos.Normalize();
            sunpos *= -1;
            light.transform.forward = sunpos;
        }

        /*
         *  //日の出・日の入りの同時線を描く
         *   {
         *    double dist = sun.getDistance();
         *    double parallax = SunAndMoon.getSunParallax(dist);//太陽視差
         *    double k = SunAndMoon.getSunriseAltitude(SunAndMoon.getSunDiameter(dist), 0.0, SunAndMoon.refraction, parallax);
         *    double celestialdeclination = sun.getCelestialDeclination();
         *
         *    for (int i = -90; i < 90; i++)
         *     {
         *      //緯度を取得
         *      double latitude = i;//getLatitudeFromY(Yequator - i);
         *
         *      //緯度を元に時角を計算する
         *      double jikaku = SunAndMoon.getTimeAngle(k, celestialdeclination, latitude);
         *
         *      if (!Double.IsNaN(jikaku))//時角がNaNでない
         *       {
         *        double hinode_keido = SunAndMoon.reviseAngle(-jikaku + sun.getRightAscension() - phai0);
         *        double hinoiri_keido = SunAndMoon.reviseAngle(jikaku + sun.getRightAscension() - phai0);
         *        //   hinodeX =(int)getXfromLongitude(hinode_keido);
         *        //   hinoiriX = (int)getXfromLongitude(hinoiri_keido);//昼側か調べる
         *        drawShadowTexture(hinode_keido, latitude, Color.white);
         *        drawShadowTexture(hinoiri_keido, latitude, Color.white);
         *       }
         *     }
         *   }
         */
        //輪郭の描画
        //ベッセル数
        VesselElements ve = new VesselElements(sun, moon, utc);

        SolarEclipse.getCrossPoint(ve, result, result2);
        //月影と地球外円との交点を調べる
        double maxQ = SolarEclipse.getPenumbralQ(ve, result);
        double minQ = SolarEclipse.getPenumbralQ(ve, result2);

        //Debug.Log("MaxQ = " + maxQ + " minQ = " + minQ);

        //半影の描画
        if (Double.IsNaN(maxQ) && Double.IsNaN(minQ))
        {
            //交点が存在しない場合。月影がすべて地球上に投射されている。

            double first_longitude = Double.NaN;
            double first_latitude  = Double.NaN;
            double last_longitude;
            double last_latitude;
            Color  gray = new Color(0, 0, 0, 0.4f);

            //初期の点
            SolarEclipse.getPenumbralOutline(ve, 0.0, result);
            Coordinate.transformICRStoGCS(ve, result, location);
            last_longitude = location[0];
            last_latitude  = location[1];
            bool fill = true;
            for (double i = 1.0; i <= 360.0; i += 1.0)
            {
                SolarEclipse.getPenumbralOutline(ve, i, result2);
                if (Double.IsNaN(result2[0]) | Double.IsNaN(result2[1]) | Double.IsNaN(result2[2]))
                {
                    fill = false;
                    continue;//NaNが含まれていたらスキップする
                }
                Coordinate.transformICRStoGCS(ve, result2, location);
//         drawShadowTexture(location[0], location[1], gray);
                //Debug.Log("i=" + i + ":" +location[0] + ":" + location[1]);
                drawOutline(last_longitude, last_latitude, location[0], location[1], Color.red);
                last_longitude = location[0];
                last_latitude  = location[1];
            }

            if (fill)
            {
                fillShadow(last_longitude - 2, last_latitude, shadow, gray);
            }

            /*
             *   byte[] pngData = shadow.EncodeToPNG();   // pngのバイト情報を取得.
             *
             *   // ファイルダイアログの表示.
             *   string filePath = EditorUtility.SaveFilePanel("Save Texture", "", shadow.name + ".png", "png");
             *
             *   if (filePath.Length > 0)
             *    {
             *     // pngファイル保存.
             *     File.WriteAllBytes(filePath, pngData);
             *     }
             */
            //Debug.Log(first_longitude + ":" + first_latitude + "::" + last_longitude + ":" + last_latitude);
        }
        else if (!Double.IsNaN(maxQ) && !Double.IsNaN(minQ))//交点が存在する
        {
            double first_x = double.NaN;
            double first_y = double.NaN;
            double first_z = double.NaN;
            double last_x  = double.NaN;
            double last_y  = double.NaN;
            double last_z  = double.NaN;
            Color  gray    = new Color(0, 0, 0, 0.4f);
            if ((maxQ - minQ) >= 0.0)
            {
                maxQ -= 360.0;
            }
            SolarEclipse.getPenumbralOutline(ve, maxQ, result);
            Coordinate.transformICRStoGCS(ve, result, location);
            //Debug.Log("MaxQ :" + location[0] + ":" + location[1]+ ":" + maxQ);
            SolarEclipse.getPenumbralOutline(ve, minQ, result);
            Coordinate.transformICRStoGCS(ve, result, location);
            //Debug.Log("MinQ :" + location[0] + ":" + location[1] + ":" + minQ);

            /*
             *    //maxQが通常の計算でNaNとなる場合に備えて、強制的に描画する。
             *    SolarEclipse.getPenumbralOutline(ve, maxQ, result);
             *    result[2] = -0.01;//強制的に基準面に設定する
             *    Coordinate.transformICRStoGCS(ve, result, location);
             *    drawShadowTexture(location[0], location[1], Color.black);
             */
            for (double i = maxQ /*Math.Ceiling(maxQ)*/; i < minQ; i += 0.2)
            {
                SolarEclipse.getPenumbralOutline(ve, i, result);
                if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2]))
                {
                    continue;                                                                     //NaNが含まれていたらスキップする
                }
                if (Double.IsNaN(first_x) | Double.IsNaN(first_y) | Double.IsNaN(first_z))
                {
                    first_x = result[0];
                    first_y = result[1];
                    first_z = result[2];
                }
                last_x = result[0];
                last_y = result[1];
                last_z = result[2];

                Coordinate.transformICRStoGCS(ve, result, location);
                drawShadowTexture(location[0], location[1], gray);
            }

            {
                SolarEclipse.getPenumbralOutline(ve, minQ, result);
                if (!Double.IsNaN(result[0]) & !Double.IsNaN(result[1]) & !Double.IsNaN(result[2]))
                {
                    Coordinate.transformICRStoGCS(ve, result, location);
                    last_x = result[0];
                    last_y = result[2];
                    last_z = result[1];

                    drawShadowTexture(location[0], location[1], gray);
                }
            }
        }

        //本影の描画
        for (int i = 0; i <= 360; i += 5)
        {
            SolarEclipse.getUmbralOutline(ve, (double)i, result);
            if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2]))
            {
                continue;                                                                       //NaNが含まれていたらスキップする
            }
            Coordinate.transformICRStoGCS(ve, result, location);
            drawShadowTexture(location[0], location[1], Color.black);
        }
        //
        shadow.Apply();
    }
Пример #8
0
    /*
     * //球体版のカメラの変換行列を設定する。
     * private void initCameraVector(double longitude, double latitude)
     * {
     *  viewpoint = new double[3];
     *  double[] xaxis = new double[3];
     *  double[] position = new double[3];
     *
     *  double phai = longitude / 180.0 * Math.PI;
     *  double rho = latitude / 180.0 * Math.PI;
     *
     *  //緯度に基づいて回転させる
     *  position[0] = Altitude * Math.Cos(rho);
     *  position[1] = 0.0;
     *  position[2] = Altitude * Math.Sin(rho);
     *
     *  //Z軸に基づいて回転させる。
     *  double[][] Zrevolve = new double[][] { { Math.Cos(phai), Math.Sin(phai), 0.0 }, { -Math.Sin(phai), Math.Cos(phai), 0.0 }, { 0.0, 0.0, 1.0 } };
     *  Matrix.multiplication31type2(Zrevolve, position, viewpoint);
     *
     *  //接線ベクトルを計算する
     *  position[0] = 0.0;
     *  position[1] = 1.0;
     *  position[2] = 0.0;
     *
     *  //    double[][] Xrevolve = new double[][]{{1.0, 0.0, 0.0 }, { 0.0, Math.cos(rho), -Math.sin(rho) }, {0.0 Math.sin(rho), Math. cos(rho) }};
     *
     *  Matrix.multiplication31type2(Zrevolve, position, xaxis);
     *
     *  double norm = Math.Sqrt(viewpoint[0] * viewpoint[0] + viewpoint[1] * viewpoint[1] + viewpoint[2] * viewpoint[2]);
     *  double[] yaxis = new double[] { -(viewpoint[0] / norm), -(viewpoint[1] / norm), -(viewpoint[2] / norm) };
     *
     *  double[] zaxis = new double[3];
     *  Matrix.getOuterProduct(xaxis, yaxis, zaxis);
     *
     *  norm = Math.Sqrt(zaxis[0] * zaxis[0] + zaxis[1] * zaxis[1] + zaxis[2] * zaxis[2]);
     *  zaxis[0] /= norm;
     *  zaxis[1] /= norm;
     *  zaxis[2] /= norm;
     *
     *
     *  camvec = new double[][] { xaxis, yaxis, zaxis };
     *  InverseCam = new double[3][3];
     *  Matrix.getInverseMatrixType2(camvec, InverseCam);
     * }
     */

    //画面を更新する(球体版)

    /*
     * private void createScreen2()
     * {
     *  double hinode_keido, hinoiri_keido, asayake, higure;
     *  int hinoiriX = 0, hinodeX = 0;
     *  int asayakeX = 0, higureX = 0;
     *
     *  //    if (screen2 == null | earth == null) return;
     *
     *  //イメージを初期化
     *  Color opaque = new Color(0, 0, 0, 0);
     *  for (int i = 0; i < shadow.width; i++)
     *   {
     *    for (int j = 0; j < shadow.height; j++)
     *     {
     *      shadow.SetPixel(i, j, opaque);
     *     }
     *   }
     *
     *  double scrDist = (scrWidth / 2.0) / Math.Tan(scrAngle / 180.0 * Math.PI);
     *  double[] vector = new double[3];
     *  double[] result = new double[3];
     *
     *  double[] center = new double[] { viewpoint[0], viewpoint[1], viewpoint[2] }; //地球中心へ向かうベクトル
     *  double norm = Math.Sqrt(center[0] * center[0] + center[1] * center[1] + center[2] * center[2]);
     *  center[0] /= norm;
     *  center[1] /= norm;
     *  center[2] /= norm;
     *
     *  double altitude = Math.Sqrt(viewpoint[0] * viewpoint[0] + viewpoint[1] * viewpoint[1] + viewpoint[2] * viewpoint[2]);
     *
     *  for (int i = 0; i < scrWidth; i++)
     *  {
     *    double x = i - (scrWidth / 2);
     *    double y = scrDist;
     *    for (int j = 0; j < scrHeight; j++)
     *    {
     *      vector[0] = x;
     *      vector[1] = y;
     *      vector[2] = -(j - (scrHeight / 2));
     *      norm = Math.Sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
     *      vector[0] /= norm;
     *      vector[1] /= norm;
     *      vector[2] /= norm;
     *      Matrix.multiplication31type2(camvec, vector, result);
     *
     *      double theta = Math.Acos(-center[0] * result[0] - center[1] * result[1] - center[2] * result[2]);
     *
     *      double b2 = 2.0 * altitude * Math.Cos(theta); //コサインを変換する必要ないのでは?
     *      double D = b2 * b2 - 4.0 * (altitude * altitude - Constants.de * Constants.de);
     *
     *      if (D >= 0)
     *      {
     *        double root = 0.5 * Math.Sqrt(D);
     *
     *        double distance = altitude * Math.Cos(theta) - root;
     *        if (distance < 0) {  System.out.println("負の実数解"); return; }
     *
     *        //x1は交点までの距離。方向ベクトルに距離を掛けると位置が出る
     *        double pointX = viewpoint[0] + result[0] * distance;
     *        double pointY = viewpoint[1] + result[1] * distance;
     *        double pointZ = viewpoint[2] + result[2] * distance;
     *
     *        double latitude = Math.Asin(pointZ / Constants.de) / Math.PI * 180.0;
     *        double longitude = Math.Acos(pointX / Math.Sqrt(pointX * pointX + pointY * pointY)) / Math.PI * 180.0;
     *        if (pointY < 0) longitude = -longitude; //象限を考慮する
     *
     *        double xOnMap = longitude - longitudeleft;
     *        if (xOnMap < 0.0) xOnMap += 360.0;
     *        int x1 = (int)(xOnMap * (imageWidth / 360.0));
     *
     *        double yOnMap = (imageHeight / 180.0) * latitude;
     *        int y1 = Yequator - (int)yOnMap;
     *        if (x1 < earth.getWidth() & y1 < earth.getHeight()) screen2.setRGB(i, j, earth.getRGB(x1, y1));
     *      }
     *    }
     *  }
     * }
     */

    //3D空間内の地用と月のモデルの位置を変更する
    private void updateSunAndMoonPosition()
    {
          EquatorialCoordinate sun  = new EquatorialCoordinate();
        EquatorialCoordinate   moon = new EquatorialCoordinate();

        double asc     = 0.0;
        double dec     = 0.0;
        double moonasc = 0.0;
        double moondec = 0.0;

        try
        {
            double[] result = new double[2];
            SunAndMoon.getSunRightAscension(utc, result);
            asc = result[0]; //赤経
            dec = result[1]; //赤緯

            SunAndMoon.getMoonRightAscension(utc, result);
            moonasc = result[0];
            moondec = result[1];
        }
        catch (Exception) { Debug.Log("Exception1 "); return; }

        double phai0 = Almanac.getGreenidgeSiderealTime(utc); //グリニッジ恒星時
                                                              //恒星時をもとに、背景の回転を行う(恒星時は春分点の時角)
        Material skybox = RenderSettings.skybox;

        skybox.SetFloat("_Rotation", (float)-phai0);//時角のマイナス方向に回転。skyboxのマテリアルは左右が逆
        //太陽位置
        {
            //赤緯・赤経は北極から見て時計回り。自覚、恒星時は反時計回り。時角に合わせて計算する
            //float ramda = -(float)((-asc + phai0) * DegToRad);これを書き換えて下の式になる
            float ramda       = (float)((asc - phai0) * DegToRad);
            float psy         = (float)(dec * DegToRad);
            float sundistance = 400;
            float x           = Mathf.Cos(psy) * Mathf.Cos(ramda) * sundistance;
            float y           = Mathf.Cos(psy) * Mathf.Sin(ramda) * sundistance;
            float z           = Mathf.Sin(psy) * sundistance;

            GameObject light = GameObject.Find("Directional Light");

            Vector3 sunpos = light.transform.position;
            sunpos.Set(x, z, y);
            light.transform.position = sunpos;
            sunpos.Normalize();
            sunpos *= -1;
            light.transform.forward = sunpos;
        }
        //月位置
        {
            float ramda = (float)((moonasc - phai0) * DegToRad);
            float psy   = (float)(moondec * DegToRad);
            float x     = Mathf.Cos(psy) * Mathf.Cos(ramda) * distanceToMoon;
            float y     = Mathf.Cos(psy) * Mathf.Sin(ramda) * distanceToMoon;
            float z     = Mathf.Sin(psy) * distanceToMoon;

            GameObject light = GameObject.Find("Moon");

            Vector3 moonpos = light.transform.position;
            moonpos.Set(x, z, y);
            light.transform.position = moonpos;
        }
    }
Пример #9
0
    //地球に写る月の影の輪郭を描く
    public void drawLines(DateTime utc)
    {
        EquatorialCoordinate sun  = new EquatorialCoordinate();
        EquatorialCoordinate moon = new EquatorialCoordinate();

        double[] result   = new double[3];
        double[] result2  = new double[3];
        double[] dataset  = new double[7];
        double[] location = new double[2];
        double   asc      = 0.0;
        double   dec      = 0.0;
        double   moonasc  = 0.0;
        double   moondec  = 0.0;
        double   phai0;

        if (mode == PLAYMODE)
        {
            dataholder.getPositions(utc, dataset);
            asc = dataset[0];
            dec = dataset[1];
            sun.setRightAscension(dataset[0]);
            sun.setCelestialDeclination(dataset[1]);
            sun.setDistance(dataset[2]);

            moon.setRightAscension(dataset[3]);
            moon.setCelestialDeclination(dataset[4]);
            moon.setDistance(dataset[5]);
            moonasc = dataset[3];
            moondec = dataset[4];
            phai0   = dataset[6];
        }
        else if (mode == RECORDMODE)
        {
            try
            {
                SunAndMoon.getSunRightAscension(utc, result);
                asc = result[0];
                dec = result[1];
                sun.setRightAscension(result[0]);
                sun.setCelestialDeclination(result[1]);
                sun.setDistance(result[2]);

                SunAndMoon.getMoonRightAscension(utc, result);
                moon.setRightAscension(result[0]);
                moon.setCelestialDeclination(result[1]);
                moon.setDistance(result[2]);
                moonasc = result[0];
                moondec = result[1];
            }
            catch (Exception) { /* Debug.Log("Exception1 ");*/ return; }
            phai0 = Almanac.getGreenidgeSiderealTime(utc);//グリニッジ恒星時
            //記録する
            dataholder.setPositions(asc, dec, sun.getDistance(), moonasc, moondec, moon.getDistance(), phai0, utc);
        }
        else
        {
            return;
        }

        //輪郭の描画
        //ベッセル数
        VesselElements ve = new VesselElements(sun, moon, utc);

        // SolarEclipse.getD(ve, 143.009267, 42.7396185, 0);
        SolarEclipse.getCrossPoint(ve, result, result2);
        //月影と地球外円との交点を調べる
        double maxQ = SolarEclipse.getPenumbralQ(ve, result);
        double minQ = SolarEclipse.getPenumbralQ(ve, result2);

        //Debug.Log("MaxQ = " + maxQ + " minQ = " + minQ);

        //半影の描画
        if (Double.IsNaN(maxQ) && Double.IsNaN(minQ))
        {
            clearTexture();
            //交点が存在しない場合。月影がすべて地球上に投射されている。
            double last_longitude;
            double last_latitude;
            Color  gray = new Color(0, 0, 0, 0.4f);

            //初期の点
            SolarEclipse.getPenumbralOutline(ve, 0.0, result);
            Coordinate.transformICRStoGCS(ve, result, location);
            last_longitude = location[0];
            last_latitude  = location[1];
            double max_lat = -90, min_lat = 90;
            double east_lon = location[0];
            double west_lon = double.NaN;

            //bool
            for (double i = 1.0; i <= 360.0; i += 1.0)
            {
                SolarEclipse.getPenumbralOutline(ve, i, result2);
                if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2]))
                {
                    continue;//NaNが含まれていたらスキップする
                }
                Coordinate.transformICRStoGCS(ve, result2, location);

                if (double.IsNaN(location[0]) | double.IsNaN(location[1]))
                {
                    continue;
                }
                //値の取得で例外が発生したら、処理をスキップする
                try
                {
                    drawOutline(last_longitude, last_latitude, location[0], location[1], shadow, sunoutline);
                }
                catch (Exception ex) { continue; }

                last_longitude = location[0];
                last_latitude  = location[1];
                if (i == 180.0)
                {
                    west_lon = location[0];
                }
                if (max_lat < last_latitude)
                {
                    max_lat = last_latitude;
                }
                if (min_lat > last_latitude)
                {
                    min_lat = last_latitude;
                }
            }

            if (!double.IsNaN(west_lon) & !double.IsNaN(east_lon))
            {
                if (west_lon > east_lon)
                {
                    east_lon += 360.0;
                }

                Point paintpoint = getScreenPoint((east_lon + west_lon) / 2, (max_lat + min_lat) / 2);
                fillShadowEx(paintpoint.x, paintpoint.y, shadow, shadowcolor);
                // Debug.Log("west= " + west_lon + " east=" +east_lon) ;
            }
        }
        else if (!Double.IsNaN(maxQ) && !Double.IsNaN(minQ))//交点が存在する
        {
            double first_longitude;
            double first_latitude;
            double last_longitude;
            double last_latitude;

            clearTexture();
            Color gray = new Color(0, 0, 0, 0.4f);
            if ((maxQ - minQ) >= 0.0)
            {
                maxQ -= 360.0;
            }
            SolarEclipse.getPenumbralOutline(ve, maxQ, result);
            Coordinate.transformICRStoGCS(ve, result, location);
            //Debug.Log("MaxQ :" + location[0] + ":" + location[1]+ ":" + maxQ);
            SolarEclipse.getPenumbralOutline(ve, minQ, result);
            Coordinate.transformICRStoGCS(ve, result, location);

            //初期の点
            double delta = 0.0;
            while (true)
            {
                SolarEclipse.getPenumbralOutline(ve, maxQ + delta, result);
                if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2]))
                {
                    delta += 0.1;
                }
                else
                {
                    break;
                }
                if (delta > 5.0)
                {
                    break;
                }
            }

            Coordinate.transformICRStoGCS(ve, result, location);
            first_longitude = last_longitude = location[0];
            first_latitude  = last_latitude = location[1];
            // double max_lon = 0, max_lat = -90, min_lon = 360, min_lat = 90;

            for (double i = maxQ + delta + 0.5; i < minQ; i += 0.5)
            {
                SolarEclipse.getPenumbralOutline(ve, i, result2);
                if (Double.IsNaN(result2[0]) | Double.IsNaN(result2[1]) | Double.IsNaN(result2[2]))
                {
                    continue;//NaNが含まれていたらスキップする
                }
                Coordinate.transformICRStoGCS(ve, result2, location);

                //値の取得で例外が発生したら、処理をスキップする
                if (double.IsNaN(location[0]) | double.IsNaN(location[1]))
                {
                    continue;
                }
                try
                {
                    drawOutline(last_longitude, last_latitude, location[0], location[1], shadow, sunoutline);
                }
                catch (Exception e) { continue; }

                last_longitude = location[0];
                last_latitude  = location[1];
            }

            SolarEclipse.getPenumbralOutline(ve, minQ, result);
            if (!Double.IsNaN(result[0]) & !Double.IsNaN(result[1]) & !Double.IsNaN(result[2]))
            {
                Coordinate.transformICRStoGCS(ve, result, location);
                if (!double.IsNaN(location[0]) & !double.IsNaN(location[1]))
                {
                    drawOutline(last_longitude, last_latitude, location[0], location[1], shadow, sunoutline);
                    last_longitude = location[0];
                    last_latitude  = location[1];
                }
            }

            //同時線を描く
            {
                //日の出・日の入りの同時線を描く
                int alllength = getSunLine(sun, phai0);

                //終点から同時線までの最短の線を描く
                Point  pnt           = getScreenPoint(last_longitude, last_latitude);
                double leastdistance = double.MaxValue;
                int    finishindex   = -1; //終点と最も近い点のインデックス
                if (pnt.x < 0)
                {
                    pnt.x += shadow.width;
                }
                else if (pnt.x >= shadow.width)
                {
                    pnt.x -= shadow.width;
                }
                if (pnt.y < 0)
                {
                    pnt.y = 0;
                }
                else if (pnt.y >= shadow.width)
                {
                    pnt.y = shadow.width;
                }

                for (int i = 0; i < alllength; i++)
                {
                    double xdiff = Math.Abs(pnt.x - sunline[i * 2]);
                    if (xdiff > shadow.width / 2)
                    {
                        xdiff = shadow.width - xdiff;
                    }
                    double ydiff  = pnt.y - sunline[i * 2 + 1];
                    double length = Math.Sqrt(xdiff * xdiff + ydiff * ydiff);
                    if (length < leastdistance)
                    {
                        leastdistance = length; finishindex = i;
                    }
                }
                if (finishindex != -1 & leastdistance != double.MaxValue)
                {
                    if (!double.IsNaN(last_longitude) & !double.IsNaN(last_latitude))
                    {
                        drawScreenOutline(pnt.x, pnt.y, sunline[finishindex * 2], sunline[finishindex * 2 + 1], sunoutline);
                    }
                }

                //開始点から同時線までの最短の線を描く
                pnt           = getScreenPoint(first_longitude, first_latitude);
                leastdistance = double.MaxValue;
                int startindex = -1; //始点と最も近い点のインデックス
                if (pnt.x < 0)
                {
                    pnt.x += shadow.width;
                }
                else if (pnt.x >= shadow.width)
                {
                    pnt.x -= shadow.width;
                }
                if (pnt.y < 0)
                {
                    pnt.y = 0;
                }
                else if (pnt.y >= shadow.width)
                {
                    pnt.y = shadow.width;
                }

                for (int i = 0; i < alllength; i++)
                {
                    double xdiff = Math.Abs(pnt.x - sunline[i * 2]);
                    if (xdiff > shadow.width / 2)
                    {
                        xdiff = shadow.width - xdiff;
                    }
                    double ydiff  = pnt.y - sunline[i * 2 + 1];
                    double length = Math.Sqrt(xdiff * xdiff + ydiff * ydiff);
                    if (length < leastdistance)
                    {
                        leastdistance = length; startindex = i;
                    }
                }
                if (startindex != -1 & leastdistance != double.MaxValue)
                {
                    if (!double.IsNaN(last_longitude) & !double.IsNaN(last_latitude))
                    {
                        drawScreenOutline(pnt.x, pnt.y, sunline[startindex * 2], sunline[startindex * 2 + 1], sunoutline);
                    }
                }
                //判定を正確にするため、同時線は最後に描く。alllengthは要素数だから、マイナスしない
                for (int i = 0; i < alllength; i++)
                {
                    drawScreenPixel(sunline[i * 2], sunline[i * 2 + 1], boundscolor);
                }

                //影の中を塗る
                int middlepoint = -1;
                if (Math.Abs(finishindex - startindex) > (alllength / 2))
                {
                    middlepoint = (finishindex + startindex + alllength) / 2;
                    if (middlepoint >= alllength)
                    {
                        middlepoint -= alllength;
                    }
                    else if (middlepoint < 0)
                    {
                        middlepoint += alllength;
                    }
                }
                else
                {
                    middlepoint = (finishindex + startindex) / 2;
                }
                getInnerPoint(sunline[middlepoint * 2], sunline[middlepoint * 2 + 1], shadow);//塗の指示
            }//同時線の描画の終わり
        } //半影の描画の終わり
        else if (!Double.IsNaN(maxQ) | !Double.IsNaN(minQ)) /*Debug.Log("minQ or maxQ is NaN");*/ } {