AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX Blogs
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 01.12.2018, 16:13   #1  
Blog bot is offline
Blog bot
Участник
 
25,459 / 846 (79) +++++++
Регистрация: 28.10.2006
gideonvos: Visualize 3D Models in D365 FinOps
Источник: https://gideonvos.wordpress.com/2018...n-d365-finops/
==============

In this short blog post I’m going to show you how to build a 3D extensible control using the Extensible Control Framework in Dynamics 365 FinOps (AX). This can come in handy for ISV’s working in the manufacturing or additive manufacturing space (3D Printing).

Being able to fully visualize and interact with 3D models of parts within D365 brings us one step close to having a full end to end ERP > 3D printing interface, which is a side project I am working on.

Extensible controls allows us to build self-contained visual controls that we can share and allow other developers to simply drop onto a form. There are basically 3 main parts to it, the HTML, optional JavaScript, and the X++ class for the control itself, which allows us to communicate between the web browser front-end and the X++ back-end side of things.

For this post I’ll focus on the STL file format, arguably the most popular of the 3D formats, and widely used by 3D printers. We’ll add some basic properties to the control, including the URL of the STL file we want to visualize, object color and control height and width. This can be extended further of course, but we’ll keep things simple for a start.

We’ll start with the X++ class (or classes, in this case) which consists of the Control and BuildControl classes. The BuildControl class is where we define our controls public properties that once dropped on a form can be set by the X++ developer, and maintained during runtime. The source for our class is shown below.

/// /// Build Control for 3D STL Viewer/// [FormDesignControlAttribute("XalSTL")]class XalSTLControlBuild extends FormBuildControl{ str url = ""; int innerHeight = 540; int innerWidth = 1024; int objectColor = 925765; //dark blue int objectShininess = 200;}[FormDesignPropertyAttribute("URL","XalSTL")]public str parmURL(str _url=url){ if (prmIsDefault(_url)) { url = _url; } return url;}[FormDesignPropertyAttribute("InnerHeight","XalSTL")]public int parmInnerHeight(int _innerHeight=innerHeight){ if (prmIsDefault(_innerHeight)) { innerHeight = _innerHeight; } return innerHeight;}[FormDesignPropertyAttribute("InnerWidth","XalSTL")]public int parmInnerWidth(int _innerWidth=innerWidth){ if (prmIsDefault(_innerWidth)) { innerWidth = _innerWidth; } return innerWidth;}[FormDesignPropertyAttribute("ObjectColor","XalSTL")]public int parmObjectColor(int _objectColor=objectColor){ if (prmIsDefault(_objectColor)) { objectColor = _objectColor; } return objectColor;}[FormDesignPropertyAttribute("ObjectShininess","XalSTL")]public int parmObjectShininess(int _objectShininess=objectShininess){ if (prmIsDefault(_objectShininess)) { objectShininess = _objectShininess; } return objectShininess;}


Next up is our main control class, with source below. Not much happening here, just basic framework stuff.

/// /// Defines a 3D STL Viewer Control/// [FormControlAttribute('XalSTL','',classstr(XalSTLControlBuild))]class XalSTLControl extends FormTemplateControl{ FormProperty url; FormProperty innerHeight; FormProperty innerWidth; FormProperty objectColor; FormProperty objectShininess;}protected void new(FormBuildControl _build, FormRun _formRun){ super(_build, _formRun); this.setTemplateId('XalSTL'); this.setResourceBundleName('/resources/html/XalSTL'); url = properties.addProperty(methodStr(XalSTLControl, parmURL), Types::String); innerHeight = properties.addProperty(methodStr(XalSTLControl, parmInnerHeight), Types::Integer); innerWidth = properties.addProperty(methodStr(XalSTLControl, parmInnerWidth), Types::Integer); objectColor = properties.addProperty(methodStr(XalSTLControl, parmObjectColor), Types::Integer); objectShininess = properties.addProperty(methodStr(XalSTLControl, parmObjectShininess), Types::Integer);}[FormPropertyAttribute(FormPropertyKind::Value, "URL")]public str parmURL(str _value = url.parmValue()){ if (!prmIsDefault(_value)) { url.setValueOrBinding(_value); } return url.parmValue();}[FormPropertyAttribute(FormPropertyKind::Value, "InnerHeight")]public int parmInnerHeight(int _value = innerHeight.parmValue()){ if (!prmIsDefault(_value)) { innerHeight.setValueOrBinding(_value); } return innerHeight.parmValue();}[FormPropertyAttribute(FormPropertyKind::Value, "InnerWidth")]public int parmInnerWidth(int _value = innerWidth.parmValue()){ if (!prmIsDefault(_value)) { innerWidth.setValueOrBinding(_value); } return innerWidth.parmValue();}[FormPropertyAttribute(FormPropertyKind::Value, "ObjectColor")]public int parmObjectColor(int _value = objectColor.parmValue()){ if (!prmIsDefault(_value)) { objectColor.setValueOrBinding(_value); } return objectColor.parmValue();}[FormPropertyAttribute(FormPropertyKind::Value, "ObjectShininess")]public int parmObjectShininess(int _value = objectShininess.parmValue()){ if (!prmIsDefault(_value)) { objectShininess.setValueOrBinding(_value); } return objectShininess.parmValue();}public void applyBuild(){ super(); XalSTLControlBuild build = this.build(); if (build) { this.parmURL(build.parmURL()); this.parmInnerHeight(build.parmInnerHeight()); this.parmInnerWidth(build.parmInnerWidth()); }}


We also add the control HTML which contains little more than a DIV which we will use as a canvas for our 3D viewer. I reference four additional files containing a modified version of the THREEJS library, which I’ll share upon request.

<span style="color:#007700;">src="/resources/scripts/three.js"><span style="color:#007700;">src="/resources/scripts/STLLoader.js"><span style="color:#007700;">src="/resources/scripts/Detector.js"><span style="color:#007700;">src="/resources/scripts/OrbitControls.js"><span style="color:#007700;"> id="XalSTL" style="max-height:400px;" data-dyn-bind="visible: $data.Visible"> <span style="color:#007700;">
<span style="color:#007700;">/>
/>
<span style="color:#007700;">src="/resources/scripts/XalSTL.js">


Finally, our control JavaScript contains the nuts and bolts that ties all this down into our control and makes this all work, fast and efficient, in D365. You’ll notice that our control has a URL parameter, and this allows us to store our (large) 3D models in Azure Blob Storage or via the dedicated storage account available within D365, via X++ code.

(function () { 'use strict'; $dyn.controls.XalSTL = function (data, element) { $dyn.ui.Control.apply(this, arguments); $dyn.ui.applyDefaults(this, data, $dyn.ui.defaults.XalSTL); }; $dyn.controls.XalSTL.prototype = $dyn.ui.extendPrototype($dyn.ui.Control.prototype, { init: function (data, element) { var self = this; var _url = ""; var _innerHeight = 540; var _innerWidth = 1024; var _objectColor = 0x0e2045; var _objectShininess = 200; $dyn.ui.Control.prototype.init.apply(this, arguments); if (!Detector.webgl) Detector.addGetWebGLMessage(); var camera, scene, renderer; scene = new THREE.Scene(); scene.add(new THREE.AmbientLight(0x999999)); camera = new THREE.PerspectiveCamera(35, _innerWidth / _innerHeight, 1, 500); camera.up.set(0, 0, 1); camera.position.set(0, -9, 6); camera.add(new THREE.PointLight(0xffffff, 0.8)); scene.add(camera); var grid = new THREE.GridHelper(25, 50, 0xffffff, 0x555555); grid.rotateOnAxis(new THREE.Vector3(1, 0, 0), 90 * (Math.PI / 180)); scene.add(grid); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setClearColor(0x999999); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(_innerWidth, _innerHeight); $(".XalSTL").context.activeElement.appendChild(renderer.domElement) $dyn.observe(data.URL, function (url) { if (url.toString().length > 0) { _url = url; RefreshModel(); } }); $dyn.observe(data.InnerHeight, function (innerHeight) { _innerHeight = innerHeight; RefreshModel(); }); $dyn.observe(data.InnerWidth, function (innerWidth) { _innerWidth = innerWidth; RefreshModel(); }); $dyn.observe(data.ObjectColor, function (objectColor) { _objectColor = objectColor; RefreshModel(); }); $dyn.observe(data.ObjectShininess, function (objectShininess) { _objectShininess = objectShininess; RefreshModel(); }); function RefreshModel() { if (_url.toString().length > 0) { var loader = new THREE.STLLoader(); var material = new THREE.MeshPhongMaterial({ color: _objectColor, specular: 0x111111, _objectShininess: 200 }); var controls = new THREE.OrbitControls(camera, renderer.domElement); loader.load(_url, function (geometry) { var mesh = new THREE.Mesh(geometry, material); mesh.position.set(0, 0, 0); mesh.rotation.set(0, 0, 0); mesh.scale.set(.02, .02, .02); mesh.castShadow = true; mesh.receiveShadow = true; scene.add(mesh); render(); controls.addEventListener('change', render); controls.target.set(0, 1.2, 2); controls.update(); window.addEventListener('resize', onWindowResize, false); }); } } function onWindowResize() { camera.aspect = _innerWidth / _innerHeight; camera.updateProjectionMatrix(); renderer.setSize(_innerWidth, _innerHeight); render(); } function render() { renderer.render(scene, camera); } } });})();


We can construct a basic demo dialog form as shown below, hit the Reload button and wait for the magic. Using the mouse, we can zoom in and out, and rotate the object in 3D.



Adding a Fabricate button can trigger an event to kick-start our 3D printing process. To tie this all together we can use the rest of the services in D365 for a proper end to end manufacturing pipeline containing CRM, BOM, Invoicing, Projects and everything else normally involved in manufacturing, without leaving the D365 UI.

For a demo video showing this control in action, click here



Источник: https://gideonvos.wordpress.com/2018...n-d365-finops/
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору.
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
gideonvos: API to CDM using Flow in a PowerApp Blog bot DAX Blogs 0 08.09.2017 11:11
gideonvos: FormsBox for Dynamics AX 7 Blog bot DAX Blogs 0 08.09.2017 11:11
axdaily: Models in AX 2012 Blog bot DAX Blogs 0 28.04.2011 04:27
mfp: AX models - Part 4 - Working with models inside MorphX Blog bot DAX Blogs 4 26.11.2009 16:55
mfp: Introducing AX models - Part 3 Blog bot DAX Blogs 0 16.10.2009 16:05
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 19:53.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.