Моделирование работы умного города на основе HTML5 WebGL

HTML
Моделирование работы умного города на основе HTML5 WebGL

предисловие

Умный город — это система. Также известен как сетевой город, цифровой город, информационный город.

Строительство умного города - это системный проект: первое, что нужно реализовать, - это интеллектуализация управления городом, которому помогает система управления умным городом управлять городом.Через систему управления люди могут контролировать работу города. , понимать изменения, которые происходят в городе каждый день, и своевременно реагировать на эти изменения.Осуществлять соответствующее управление, второе - это интеллектуализация инфраструктуры, включая интеллектуальный транспорт, интеллектуальную мощность, интеллектуальную безопасность и т. д. Движущая сила города , а плавный поток трафика ускоряет развитие города.Умный город также включает в себя социальный интеллект, такой как умное медицинское обслуживание, умный дом и умное образование, а также производственный интеллект умных предприятий, умных банков и умных магазинов. , чтобы всесторонне улучшить модернизацию городского производства, управления и эксплуатации.

В этой демонстрации используетсяHT for WebОблегченная схема моделирования HTML5/WebGL продукта создает сцену городской застройки, добавляет городские дороги, реализует веб-визуализацию умного города и моделирует работу города с помощью анимации.

демонстрационный адрес:Woohoo.hightopo.com/demo/Intelling…

предварительный просмотр:

在这里插入图片描述

Код

сцена загрузки

Сначала создайте новую сцену и добавьте ее на страницу.

let dm = this.dm = new ht.DataModel();
let entryG3d = this.entryG3d = new ht.graph3d.Graph3dView(dm);
entryG3d.addToDOM(); // 将场景添加到页面中

Компоненты HT, как правило, встроены в такие контейнеры, такие как BorderPane, SplitView и TabView, в то время как компонент Outerment HT требует, чтобы пользователь вручную добавить базовый элемент div, возвращенный GetView () в элемент DOM страницы. Следует отметить здесь, что, При изменении размера родительской контейнера, если родительский контейнер представляет собой предварительно определенный компонент контейнера HT, такой как BorderPane и SplitView, HT-контейнер автоматически вызывает функцию Invalidate Compont Compont для уведомления обновления. Однако, если родительский контейнер представляет собой нативный HTML-элемент, компонент HT не может знать, что он должен быть обновлен. Следовательно, внешнее компонент HT, как правило, необходимо контролировать событие размера окна, и вызовов функцию недействительной функции внешнего Компонент для обновления.

Для самых внешних компонентов все компоненты HT имеют все компоненты HTaddToDOMлогика ее реализации выглядит следующим образом, где iv — это сокращение для недействительности:

addToDOM = function(){   
    var self = this,
        view = self.getView(), // 获取组件 div  
        style = view.style;
    document.body.appendChild(view); // 将组件添加到文档对象中            
    style.left = '0';
    style.right = '0';
    style.top = '0';
    style.bottom = '0';      
    window.addEventListener('resize', function () { self.iv(); }, false); // 监听窗口变化,刷新组件            
}

Затем десериализуйте json городской сцены.

ht.Default.xhrLoad('scenes/园区/城市demo.json', (text) => {
    let json = ht.Default.parse(text); // 还原 json 字符串
    let scene = json.scene; // 获取 json 中设置的投影参数
    entryG3d.setEye(scene.eye); // 设置视角
    entryG3d.setCenter(scene.center); // 设置目标中心点
    entryG3d.setFar(scene.far); // 设置远端截面位置
    entryG3d.setNear(scene.near); // 设置近端截面位置
    dm.deserialize(text); // 场景反序列化
    this.setSkyBox(entryG3d); // 设置天空球
    this.initentryG3dEvent(); // 添加场景监听事件
    this.startAnimate(); // 启动城市动画
    this.startCarAnimate(['car1Line'], dm.getDataByTag('car1')); // 启动消防小车1动画
    this.startCarAnimate(['car2Line'], dm.getDataByTag('car2')); // 启动消防小车2动画
});

рендеринг сцены

1.Карта освещения окружающей среды: визуализируйте изображение карты в сцене и используйте node.s('envmap', 0.5), чтобы установить степень рендеринга узла. Он в основном используется для добавления эффектов отражения объектов на полу. Вы также можете добавьте украшение звездного света, как в этой демонстрации.

dataModel.setEnvmap('环境光贴图.png'); // 贴图要求宽高像素为 2^n
node.s('envmap', 0.1); 

Сравнительная таблица:

在这里插入图片描述
在这里插入图片描述
На картинке справа карта рассеянного света — это звездный свет, а центральная часть города имеет синий цвет звездного неба.Вы также можете увидеть очевидные изменения звездного света при повороте сцены в демо.

2.Свечение: Это относится к физическому явлению газового разряда в газе низкого давления. Он используется для выделения ярких цветов в 3D-сценах, представляя световой эффект. Он может контролировать интенсивность свечения, диапазон отображения свечения и яркость свечения. порог.

g3d.enablePostProcessing('Bloom', true); // 开启辉光
module = g3d.getPostProcessingModule('Bloom');
module.strength = 0.18; // 强度
module.threshold = 0.62; // 阈值
module.radius = 0.4; //范围
g3d.iv(); // 刷新拓扑

Сравнительная таблица:

在这里插入图片描述
在这里插入图片描述

3. Глубина резкости: управление четкостью вокруг центра сцены, размытие окружения, украшение изображения, выделение объекта, улучшение перспективы и управление порогом глубины резкости (степень размытия окружения).

g3d.enablePostProcessing('Dof', true); // 开启景深
module = g3d.getPostProcessingModule('Dof');
module.aperture = 0.18; // 景深阀值
module.image= '景深贴图.png'; // 景深贴图 
g3d.iv(); // 刷新拓扑

Сравнительная таблица:

在这里插入图片描述
在这里插入图片描述

Видно, что область спутника и крайний левый край на правом изображении размыты.

4.Sky Ball: модель сцены помещается в большую сферу, для имитации неба выполняется отображение внутренней сферы.

node = new ht.Node()
node.s({
    'shape3d':'sphere', // 球体
    'shape3d.image': 'earth' // 贴图路径
});
node.s3(10000, 10000, 10000);
g3d.dm().add(node);
g3d.setSkyBox(node); // 设置天空球

Реализация анимации

Загруженная городская сцена показана ниже:

在这里插入图片描述
Мы видим, что группы зданий имеют свои собственные панели отображения данных.Вокруг центрального здания есть модель поезда с апертурой, которая является имитацией поезда в центре города, и город-спутник справа.Теперь давайте изменим данные панели данных, пусть поезд, Спутник начал двигаться.

Реализация анимации достигается с помощью функции диспетчеризации (Руководство по планированию), давайте сначала разберемся с использованием функции планирования:

Процесс планирования в HT - первый пропускdataModelДобавьте задачу планирования, DataModel пройдет в DataModel, когда приходит промежуточный интервал времени планирования.Все примитивные задачи планирования обратного вызоваФункцию действия можно использовать для изменения свойств входящих примитивов данных для достижения эффектов анимации.

dataModel.addScheduleTask(task) Добавьте задачу планирования, где задача — это объект json, и можно указать следующие свойства:

  • interval: интервал в миллисекундах, значение по умолчанию 10
  • включено: включить ли переключатель, по умолчанию верно
  • действие: функция интервального действия, эта функция должна быть установлена

dataModel.removeScheduleTask(task) удаляет запланированную задачу, где задача — ранее добавленный объект запланированной задачи.

Код реализации анимации выглядит следующим образом:

startAnimate() {
    let dr = Math.PI / 180 * 2, PI2 = Math.PI * 2;
    let dm = this.dm;
    let rotateOval = dm.getDataByTag('rotateOval'); // 获取城市列车模型
    let logo = dm.getDataByTag('logo'); // 获取城市卫星模型

   // 设置动画参数 
    let roatateTask = this.roatateTask = {
        interval: 100,
        action: function(data){
            if(data === rotateOval || data === logo){
                data.setRotation((data.getRotation() - dr) % PI2);
            }                
        }        
    };
    dm.addScheduleTask(roatateTask); // 将动画加入到调度任务中
    
   // 获取建筑物数据面板
    let dglsd = dm.getDataByTag('dglsd'); // 戴谷岭隧道
    let xlsd = dm.getDataByTag('xlsd'); // 杏林隧道
    let xmg = dm.getDataByTag('xmg'); // 厦门港
    let jcglzx = dm.getDataByTag('jcglzx'); // 机场管理中心

   // 模拟建筑物数据面板的动态展示
    let valueChangeTask = this.valueChangeTask = {
        interval: 1000,
        action: function(data){
            if(data === dglsd){
                data.a('carHour', util.randomNumBetween(3000, 6000));
            }   
            if(data === xlsd){
                data.a('carHour', util.randomNumBetween(3000, 6000));
            } 
            if(data === xmg){
                data.a('ttl', util.randomNumBetween(3, 10));
                data.a('zy', util.randomNumBetween(0, 100));
            } 
            if(data === jcglzx){
                data.a('sskll', util.randomNumBetween(500, 2000));
            }            
        }        
    };
    dm.addScheduleTask(valueChangeTask); // 将数据变化加入到调度任务中 
}

Эффект анимации достигается следующим образом:

在这里插入图片描述
Демонстрация также имитирует пожарную машину, мчащуюся к месту возгорания.Анимация выглядит следующим образом:
在这里插入图片描述
Вождение пожарной машины используетсяht.Default.startAnim, давайте сначала посмотрим:

ht.Default.startAnim({
    frames: 12, // 动画帧数
    interval: 10, // 动画帧间隔毫秒数
    easing: function(t){ return t * t; }, // 动画缓动函数,默认采用 ht.Default.animEasing
    finishFunc: function(){ console.log('Done!') }, // 动画结束后调用的函数。
    action: function(v, t){ // action函数必须提供,实现动画过程中的属性变化。
        node.setPosition( // 此例子展示将节点`node`从位置`p1`动画到位置`p2`。
            p1.x + (p2.x - p1.x) * v,
            p1.y + (p2.y - p1.y) * v
        );
    }
});

Приведенное выше анимация на основе кадров. Таким образом, пользователь контролирует эффект анимации, указав номер кадров анимации кадров и интервал интервала интервала анимации.

ht.Default.startAnim({
    duration: 500, // 动画周期毫秒数,默认采用`ht.Default.animDuration`
    action: function(v, t){ 
        ... 
    }
});

Вышеупомянутая анимация на основе времени, В этом методе пользователю нужно только указать количество миллисекунд периода анимации продолжительности, и HT завершит анимацию в течение указанного периода времени.

Поскольку язык js не может точно контролировать временной интервал интервала, использование на основе кадров не может точно контролировать период времени анимации.Даже если одни и те же кадры и параметры интервала находятся в разных средах, может быть большая разница в периоде анимации. Поэтому HT по умолчанию использует Time-Based.Основываясь на методе, если параметры продолжительности и кадров не установлены, параметр продолжительности будет автоматически установлен системой на значение ht.Default.animDuration.

Код для вождения пожарной машины выглядит следующим образом:

startCarAnimate(polylineTagArr, airNode) { // 传入消防车行驶路线 tag(唯一标签)组和消防车模型节点
    let dm = this.dm;
    let entryG3d = this.entryG3d;
    let curIndex = 0;
    let polyline = dm.getDataByTag(polylineTagArr[curIndex]); // 获取消防路线 ht.PolyLine(http://www.hightopo.com/guide/guide/core/shape/ht-shape-guide.html#ref_different)
    let prePos = airNode.p3(); // 获取节点初始位置
    let preRotate = airNode.r3(); // 获取节点初始旋转角度
    let lineLength = entryG3d.getLineLength(polyline); // 获取管道长度
    let params = { // 设置消防车行驶动画参数
            duration: 10000,
            easing: function(t){
                return t * t;
            },
            action: function(v, t){
                let offset = entryG3d.getLineOffset(polyline, lineLength * v), // 获取管道指定比例的偏移信息
                    point = offset.point,
                    px = point.x,
                    py = point.y,
                    pz = point.z,
                    tangent = offset.tangent,
                    tx = tangent.x,
                    ty = tangent.y,
                    tz = tangent.z;
                airNode.p3(px, py, pz); // 移动消防车到下一位置
                airNode.lookAt([px + tx, py + ty, pz + tz], 'front'); // 消防车沿着管道方向转向
            },
            finishFunc: function(){
                if(curIndex < polylineTagArr.length - 1) { // 进入下一段路线
                    curIndex++;
                }
                else {
                    curIndex = 0; // 返回第一段路线
                }
                if(curIndex === 0) { // 消防车返回原点
                    airNode.p3(prePos);
                    airNode.r3(preRotate);
                } 
                polyline = dm.getDataByTag(polylineTagArr[curIndex]); 
                lineLength = entryG3d.getLineLength(polyline);
                this.carAni = ht.Default.startAnim(params); // 执行下一段行驶动画   
            }
        };
    this.carAni = ht.Default.startAnim(params);
}

Вождение пожарной машины можно резюмировать следующим образом: сначала получают информацию о длине трубопровода проезжей части, вычисляют определенную долю точки смещения трубопровода, перемещают положение пожарной машины в расчетную точку смещения, корректируют ориентацию огня. модель грузовика и вычисление следующей точки смещения.Смещение до достижения конца текущего трубопровода, а затем получается информация о длине следующего трубопровода, и смещение продолжается.

Три упомянутых в коде метода: getLineLength, getLineOffset, lookAt, давайте посмотрим.

1. g3d.getLineLength(edgeOrPolyLine)

По названию метода параметра edgeOrPolyLine мы можем знать, что этот метод предназначен для получения длины соединения или трубы.

2. g3d.getLineOffset(edgeOrPolyLine, offset)

  • проволока или труба edgeOrPolyLine
  • смещение процент смещения

Этот метод получает информацию о смещении соединения или трубы и возвращает { point, tangent }, где point — это 3D-координата, а tangent — вектор касательной точки вдоль текущей линии.

3. node.lookAt(point, direction)

  • точка 3D координатная точка
  • направление Сторона узла, значение может быть «спереди | сзади | слева | справа | сверху | снизу»

Сориентируйте грань узла по координатной точке в пространстве.

Принципиальная схема движения и управления пожарной машиной:

在这里插入图片描述

  1. отправная точка;

  2. Достигает следующей позиции на установке3D (point.x, point.y, point.z), красная линия касательной к касательному вектору;

  3. Поверните переднюю часть автомобиля по касательной через node.lookAt([point.x + tangent.x, point.y + tangent.y, point.z + tangent.z], 'front');;

    1. Повторите вышеуказанные шаги.

Где [point.x + tangent.x, point.y + tangent.y, point.z + tangent.z] — координаты целевой точки.

在这里插入图片描述

Суммировать

В систему умного города также входит управление умными зданиями:

在这里插入图片描述
woohoo.hightopo.com/demo/contract - это...

Метро находится в центре городского транспорта, управление станциями метро также имеет важное значение:

在这里插入图片描述
woohoo.hightopo.com/demo/contract-subei…