C# метод вызова библиотеки js
C# метод вызова библиотеки js

Предисловие

Используйте .NET 6 для разработки программы Winform для обработки файлов Excel и экспорта результатов в файлы Excel. Используются два алгоритма: один — метод booleanPointInPolygon библиотеки turf.js для определения того, находятся ли координаты долготы и широты в пределах области, второй — алгоритм коррекции долготы и широты, поскольку региональный набор координат, заданный другой стороной; смещение и его необходимо исправить.

Для этих двух алгоритмов сложно найти реализации на C# в Интернете, во-вторых, мне еще нужно их протестировать, чтобы убедиться в отсутствии проблем. Раньше при создании электронных карт я использовал библиотеку turf.js и js-версию алгоритма коррекции, доверяю им и уверен, что проблем не возникнет.

Поэтому я планирую вызвать метод библиотеки js через C# для реализации обработки данных.

УстановитьClearScript

ClearScript — это js-движок Microsoft с открытым исходным кодом, поддерживающий Windows, Linux и Mac. Установка поиска NuGet: Microsoft.ClearScript.Core Microsoft.ClearScript.V8 Microsoft.ClearScript.V8.Native.win-x64

Импортировать js-файлы

Поместите в проект Leaflet.mapCorrection.js, turf.v6.5.0.min.js и свой собственный Calc.js, щелкните правой кнопкой мыши настройки свойств и скопируйте их в выходной каталог: скопируйте, если они более новые.

Calc.js реализует функции путем вызова методов в Leaflet.mapCorrection.js и turf.v6.5.0.min.js. Содержимое файла следующее:

Язык кода:javascript
копировать
function calc(lng, lat, polygonStr) {
    var point = turf.point([lng, lat]);
    var polygonPoints = JSON.parse(polygonStr);
    var polygon = turf.polygon(polygonPoints);

    var bl = turf.booleanPointInPolygon(point, polygon);
    return bl;
}

function correct(lng, lat) {
    var newPoint = new CoordConvertor().gcj02_To_gps84(lng, lat);
    return newPoint;
}

Создать объект V8ScriptEngine.

Язык кода:javascript
копировать
private V8ScriptEngine _engine = new V8ScriptEngine();

Загрузка js-файлов через js-движок

Добавьте следующий код в метод Form1_Load:

Язык кода:javascript
копировать
_engine.AddHostType("Console", typeof(Console));
string fileName = AppDomain.CurrentDomain.BaseDirectory + "turf.v6.5.0.min.js";
string js;
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    byte[] bArr = new byte[fs.Length];
    await fs.ReadAsync(bArr, 0, bArr.Length);
    js = ASCIIEncoding.UTF8.GetString(bArr);
}
_engine.Execute(js);
fileName = AppDomain.CurrentDomain.BaseDirectory + "calc.js";
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    byte[] bArr = new byte[fs.Length];
    await fs.ReadAsync(bArr, 0, bArr.Length);
    js = ASCIIEncoding.UTF8.GetString(bArr);
}
_engine.Execute(js);
fileName = AppDomain.CurrentDomain.BaseDirectory + "leaflet.mapCorrection.js";
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
    byte[] bArr = new byte[fs.Length];
    await fs.ReadAsync(bArr, 0, bArr.Length);
    js = ASCIIEncoding.UTF8.GetString(bArr);
}
_engine.Execute(js);

C# вызывает метод js для реализации коррекции координат долготы и широты

Язык кода:javascript
копировать
double lng = Convert.ToDouble(lnglat[0]);
double lat = Convert.ToDouble(lnglat[1]);

//Коррекция координат
dynamic newPoint = _engine.Invoke("correct", new object[] { lng, lat });
lng = newPoint.lng;
lat = newPoint.lat;

C# вызывает метод js, чтобы определить, находится ли точка широты и долготы внутри многоугольника.

Язык кода:javascript
копировать
//_selectedRegionPointsкоординаты многоугольникаточкасобиратьjsonнить
bool bl = (bool)_engine.Invoke("calc", new object[] { lng, lat, _selectedRegionPoints });

Релиз после завершения разработки программы

После публикации папка копируется в систему Win10 пользователя и может использоваться напрямую без установки среды .net6. Я не могу запустить его на своей очень старой виртуальной машине с Win7 SP1, и ClearScriptV8.win-x64.dll не может быть успешно загружен, я пока не знаю, почему.

Полный код Form1.cs выглядит следующим образом:

На тот момент программа писалась впопыхах. Конечно, программу можно было оптимизировать, но в этом не было необходимости. Объем обрабатываемых данных был невелик, а функция работала нормально.

Язык кода:javascript
копировать
using Models;
using Newtonsoft.Json;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.ClearScript.JavaScript;
using Microsoft.ClearScript.V8;
using NPOI.HSSF.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.SS.UserModel;
using System.Reflection;
using System.Windows.Forms;
using NPOI.Util;

namespace точка
{
    public partial class Form1 : Form
    {
        private Regions _regions;
        private List<CameraInfo> _cameraList = new List<CameraInfo>();
        private V8ScriptEngine _engine = new V8ScriptEngine();
        private string _selectedRegionPoints;

        public Form1()
        {
            InitializeComponent();
        }

        private async void Form1_Load(object sender, EventArgs e)
        {
            //Загрузка js-файлов через js-движок
            _engine.AddHostType("Console", typeof(Console));
            string fileName = AppDomain.CurrentDomain.BaseDirectory + "turf.v6.5.0.min.js";
            string js;
            using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                byte[] bArr = new byte[fs.Length];
                await fs.ReadAsync(bArr, 0, bArr.Length);
                js = ASCIIEncoding.UTF8.GetString(bArr);
            }
            _engine.Execute(js);
            fileName = AppDomain.CurrentDomain.BaseDirectory + "calc.js";
            using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                byte[] bArr = new byte[fs.Length];
                await fs.ReadAsync(bArr, 0, bArr.Length);
                js = ASCIIEncoding.UTF8.GetString(bArr);
            }
            _engine.Execute(js);
            fileName = AppDomain.CurrentDomain.BaseDirectory + "leaflet.mapCorrection.js";
            using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                byte[] bArr = new byte[fs.Length];
                await fs.ReadAsync(bArr, 0, bArr.Length);
                js = ASCIIEncoding.UTF8.GetString(bArr);
            }
            _engine.Execute(js);

            //Инициализация раскрывающегося списка административного подразделения
            fileName = AppDomain.CurrentDomain.BaseDirectory + "Аньхой.json";
            using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                byte[] bArr = new byte[fs.Length];
                await fs.ReadAsync(bArr, 0, bArr.Length);
                string json = ASCIIEncoding.UTF8.GetString(bArr);
                _regions = JsonConvert.DeserializeObject<Regions>(json);
            }

            List<Records> citys = _regions.RECORDS.ToList().FindAll(a => a.civilcode.Length == 4);
            cbxCity.DataSource = citys;
            cbxCity.DisplayMember = "civilname";
            cbxCity.ValueMember = "civilcode";
        }

        private void button1_Click(object sender, EventArgs e)
        {
            openFileDialog1.Title = «Выберите файл Excel для обработки»;
            openFileDialog1.Filter = «Файл Excel(*.xlsx)|*.xlsx»;
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                using (FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                {

                }
            }
        }


        private void cbxCity_SelectedIndexChanged(object sender, EventArgs e)
        {
            Records record = cbxCity.SelectedItem as Records;
            List<Records> citys = _regions.RECORDS.ToList().FindAll(a => a.civilcode.Length > 4 && a.civilcode.Substring(0, 4) == record.civilcode);
            citys.Insert(0, new Records() { civilcode = null, civilname = "==Пожалуйста, выберите==" });
            cbxCounty.DataSource = citys;
            cbxCounty.DisplayMember = "civilname";
            cbxCounty.ValueMember = "civilcode";
        }

        private void cbxCounty_SelectedIndexChanged(object sender, EventArgs e)
        {
            Records record = cbxCounty.SelectedItem as Records;
            if (record.civilcode == null)
            {
                record = cbxCity.SelectedItem as Records;
            }
            Regex regex = new Regex(@"^POLYGON\((\(.*\),?)*\)$");
            var mc = regex.Matches(record.polygongeo);
            StringBuilder sb = new StringBuilder();
            foreach (Match m in mc)
            {
                string value = m.Groups[1].Value.TrimStart('(').TrimEnd(')');
                string[] lnglatArr = value.Split(',');
                bool first = true;
                if (sb.Length > 0)
                {
                    sb.Append(",");
                }
                sb.Append("[[");
                foreach (string lnglatStr in lnglatArr)
                {
                    string[] lnglat = lnglatStr.Trim().Split(' ');
                    double lng = Convert.ToDouble(lnglat[0]);
                    double lat = Convert.ToDouble(lnglat[1]);

                    //Коррекция координат
                    dynamic newPoint = _engine.Invoke("correct", new object[] { lng, lat });
                    lng = newPoint.lng;
                    lat = newPoint.lat;

                    if (first)
                    {
                        first = false;
                        sb.AppendFormat($"[{lng}, {lat}]");
                    }
                    else
                    {
                        sb.AppendFormat($",[{lng}, {lat}]");
                    }
                }
                sb.Append("]]");
            }
            _selectedRegionPoints = sb.ToString();
        }

        private async void openFileDialog1_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
        {
            await Task.Delay(10);

            //Читаем Excel
            _cameraList = new List<CameraInfo>();
            using (FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                XSSFWorkbook workbook = new XSSFWorkbook(fs);
                ISheet sheet = workbook.GetSheetAt(0);
                for (int i = 1; i <= sheet.LastRowNum; i++)
                {
                    IRow row = sheet.GetRow(i);
                    CameraInfo cameraInfo = new CameraInfo();
                    cameraInfo.CameraNo = row.GetCell(1).StringCellValue.Trim();
                    cameraInfo.City = row.GetCell(2).StringCellValue.Trim();
                    cameraInfo.County = row.GetCell(3).StringCellValue.Trim();
                    cameraInfo.CameraName = row.GetCell(4).StringCellValue.Trim();
                    cameraInfo.Lng = row.GetCell(5).StringCellValue.Trim();
                    cameraInfo.Lat = row.GetCell(6).StringCellValue.Trim();
                    cameraInfo.CameraFunType = row.GetCell(7).StringCellValue.Trim();
                    cameraInfo.Region = row.GetCell(8).StringCellValue.Trim();
                    cameraInfo.Type = row.GetCell(9).StringCellValue.Trim();
                    cameraInfo.Status = row.GetCell(10).StringCellValue.Trim();
                    cameraInfo.Mac = row.GetCell(11).StringCellValue.Trim();
                    cameraInfo.Ip = row.GetCell(12).StringCellValue.Trim();
                    _cameraList.Add(cameraInfo);
                }
            }

            //Фильтрация данных
            _cameraList = _cameraList.FindAll(cameraInfo =>
            {
                if (!string.IsNullOrWhiteSpace(cameraInfo.Lng) && !string.IsNullOrWhiteSpace(cameraInfo.Lat))
                {
                    double lng = Convert.ToDouble(cameraInfo.Lng);
                    double lat = Convert.ToDouble(cameraInfo.Lat);
                    bool bl = (bool)_engine.Invoke("calc", new object[] { lng, lat, _selectedRegionPoints });
                    if (bl) //в пределах зоны
                    {
                        return false;
                    }
                    else //За пределами области
                    {
                        return true;
                    }
                }
                else
                {
                    return false;
                }
            });

            saveFileDialog1.Title = «Выберите место и имя файла, в который будут сохраняться результаты обработки»;
            saveFileDialog1.Filter = «Файл Excel(*.xlsx)|*.xlsx»;
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                if (File.Exists(saveFileDialog1.FileName))
                {
                    File.Delete(saveFileDialog1.FileName);
                }
                string template = AppDomain.CurrentDomain.BaseDirectory + "точкашаблон.xlsx";
                XSSFWorkbook workbook;
                using (FileStream fs = new FileStream(template, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    workbook = new XSSFWorkbook(fs);

                    using (FileStream fs2 = new FileStream(saveFileDialog1.FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                    {
                        ISheet sheet = workbook.GetSheetAt(0);
                        sheet.RemoveRow(sheet.GetRow(1));
                        sheet.RemoveRow(sheet.GetRow(2));
                        Dictionary<int, ICellStyle> cellStyles = GetCellStyles(sheet);
                        int i = 1;
                        foreach (CameraInfo cameraInfo in _cameraList)
                        {
                            IRow row = sheet.CreateRow(i);
                            ICell cell1 = row.CreateCell(1, CellType.String);
                            ICell cell2 = row.CreateCell(2, CellType.String);
                            ICell cell3 = row.CreateCell(3, CellType.String);
                            ICell cell4 = row.CreateCell(4, CellType.String);
                            ICell cell5 = row.CreateCell(5, CellType.String);
                            ICell cell6 = row.CreateCell(6, CellType.String);
                            ICell cell7 = row.CreateCell(7, CellType.String);
                            ICell cell8 = row.CreateCell(8, CellType.String);
                            ICell cell9 = row.CreateCell(9, CellType.String);
                            ICell cell10 = row.CreateCell(10, CellType.String);
                            ICell cell11 = row.CreateCell(11, CellType.String);
                            ICell cell12 = row.CreateCell(12, CellType.String);
                            SetCellStyles(row, cellStyles);
                            cell1.SetCellValue(cameraInfo.CameraNo);
                            cell2.SetCellValue(cameraInfo.City);
                            cell3.SetCellValue(cameraInfo.County);
                            cell4.SetCellValue(cameraInfo.CameraName);
                            cell5.SetCellValue(cameraInfo.Lng);
                            cell6.SetCellValue(cameraInfo.Lat);
                            cell7.SetCellValue(cameraInfo.CameraFunType);
                            cell8.SetCellValue(cameraInfo.Region);
                            cell9.SetCellValue(cameraInfo.Type);
                            cell10.SetCellValue(cameraInfo.Status);
                            cell11.SetCellValue(cameraInfo.Mac);
                            cell12.SetCellValue(cameraInfo.Ip);
                            i++;
                        }
                        workbook.Write(fs2);
                    }
                    MessageBox.Show("Завершено");
                }
            }
        }

        private Dictionary<int, ICellStyle> GetCellStyles(ISheet sheet)
        {
            var styleRow = sheet.GetRow(5);
            Dictionary<int, ICellStyle> result = new Dictionary<int, ICellStyle>();
            for (int i = 1; i <= 12; i++)
            {
                result.Add(i, styleRow.GetCell(i).CellStyle);
            }
            return result;
        }

        private void SetCellStyles(IRow row, Dictionary<int, ICellStyle> styles)
        {
            for (int i = 1; i <= 12; i++)
            {
                row.GetCell(i).CellStyle = styles[i];
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _engine.Dispose();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.Description = «Выберите место для сохранения файла шаблона»;
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                string template = AppDomain.CurrentDomain.BaseDirectory + "точкашаблон.xlsx";
                string filePath = Path.Combine(folderBrowserDialog1.SelectedPath, "точкашаблон.xlsx");
                if (File.Exists(filePath))
                {
                    if (MessageBox.Show("Файл шаблона уже существует, вы хотите его перезаписать?", "намекать", MessageBoxButtons.OKCancel) == DialogResult.OK)
                    {
                        File.Copy(template, filePath, true);
                        MessageBox.Show("Загрузка завершена");
                    }
                }
                else
                {
                    File.Copy(template, filePath, true);
                    MessageBox.Show("Загрузка завершена");
                }
            }
        }
    }
}
boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose