[{"content":" Evolving Innovation #","date":null,"permalink":"https://virtualdesignfactory.com.au/","section":"","summary":"","title":""},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/articles/","section":"Articles","summary":"","title":"Articles"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/categories/","section":"Categories","summary":"","title":"Categories"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/categories/math/","section":"Categories","summary":"","title":"Math"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/tags/programming/","section":"Tags","summary":"","title":"Programming"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/tags/","section":"Tags","summary":"","title":"Tags"},{"content":"3D graphics requires points in three dimensional space expressed as x y z\nThere are a number of different possible orientations in a Cartesian coordinate system, however converting between different systems is reasonably straight forward.\nA simple Vector3 class is all that is required to get started. Example code will be shown in typescript.\nexport class Vector3 { // Initialise values to 0 if not supplied constructor(public x: number = 0, public y: number = 0, public z: number = 0) {} // Provide a simple to array method to export vector fields toArray() { return [this.x, this.y, this.z]; } // Provide a simple from array method to import vector fields fromArray(array: number[]) { if (array.length !== 3) { throw new Error(\u0026#39;x, y, z values required\u0026#39;); } this.x = array[0]; this.y = array[1]; this.z = array[2]; return this; } // extend the class here with functions below } You would create and use an instance of this class as follows:\nconst vector1 = new Vector3(); const vector2 = new Vector3(1, 2, 3); console.log(vector1.toArray()); // [0, 0, 0] console.log(vector2.toArray()); // [1, 2, 3] In order to allow multiple operations chained together it\u0026rsquo;s advantageous to always return this; at the end of any methods that effect the current vector instance (any methods that would otherwise return void). This technique allows for method chaining as you will see in the examples I have.\nBy itself this class is simply a container for the labeled data x y z. It would be very useful to extend this class so that different Vector3 instances could interact with simple methods such as these:\n//... after constructor add(vector: Vector3) { this.x += vector.x; this.y += vector.y; this.z += vector.z; return this; } sub(vector: Vector3) { this.x -= vector.x; this.y -= vector.y; this.z -= vector.z; return this; } // ... before end curly brace Multiplication can also be done with vectors, for 3D graphics it is usually enough to provide a scalar value with which to apply to all the axis:\nmultiplyScalar(value: number) { this.x *= value; this.y *= value; this.z *= value; return this; } The magnitude of a vector is just the same as the total length of the vector and can be calculated as the square root of all the individual vector elements squared:\nmagnitude(): number { return Math.sqrt(this.x ** 2 + this.y ** 2 + this.z ** 2); } A normalised vector (normal) or otherwise knows as a unit vector is a vector that has a magnitude of 1. It can be very useful to take a vector and normalise it, so that you can then apply the multiplyScalar method to it, thereby extending it to a specific length. For example applying multiplyScalar(5) to a unit vector will ensure that the vector is now 5 units long:\nnormalize() { const currentMagnitude = this.magnitude(); this.x /= currentMagnitude; this.y /= currentMagnitude; this.z /= currentMagnitude; return this; } Calculating a dot product for the vector yeilds a single number, and is useful in a number of other vector calculation. It can be caluclated as follows:\ndot(vector: Vector3): number { return this.x * vector.x + this.y * vector.y + this.z * vector.z; } The angle between two vectors can also be calculated and uses some of the previous methods we\u0026rsquo;ve added to get the result:\nangleBetween(vector: Vector3): number { // Note: this will return the angle in radians return Math.acos(this.dot(vector) / (this.magnitude() * vector.magnitude())); } Here is an example of using the angleBetween method:\nconst vector1 = new Vector3(3, 1, 0); const vector2 = new Vector3(4, 0, 0); console.log(vector1.angleBetween(vector2)); // 0.3217505543966423 // Convert to degrees by multiplying by 180 and dividing by PI // 0.3217505543966423 * 180 / Math.PI; // 18.434948822922017 A clone method is also useful in case you do not wish to change the value of a vector when performing calculations with it:\nclone(): Vector3 { return new Vector3(this.x, this.y, this.z); } As an example of this:\nconst vector1 = new Vector3(1, 2, 3); const vector2 = new Vector3(4, 5, 5); // The add method would normally change the vector it\u0026#39;s called on // vector1.add(vector2); // will alter the values of vector1 to be [5, 7, 9] // To create a new vector based on vector1, leaving vector1 // unmodified in the process call the clone method const vector3 = vector1.clone().add(vector2); console.log(vector1); // Vector3 { x: 1, y: 2, z: 3 } console.log(vector2); // Vector3 { x: 4, y: 5, z: 5 } console.log(vector3); // Vector3 { x: 5, y: 7, z: 8 } The cross product of a vector will modify a vector to be perpendicular to the plane of the original vector and the vector passed in. This is very useful for calculating face normals for groups of vectors or points:\ncross(vector: Vector3) { const x = this.y * vector.z - this.z * vector.y; const y = this.x * vector.z - this.z * vector.x; const z = this.x * vector.y - this.y * vector.x; // The Y value needs to be inverted but I don\u0026#39;t // like the value -0 so we will check for that // posibility with the turnery operator this.x = x; this.y = y === 0 ? 0 : -y; this.z = z; return this; } Let\u0026rsquo;s look at an example of getting the plane normal from three points that we might use to create a polygon face:\n// This is an array of points creating a // simple triangle along the X-Y plane const polyFace = [ new Vector3(1, 1, 0), // point 0 new Vector3(5, 1, 0), // point 1 new Vector3(1, 3, 0), // point 2 ]; // The vector from point 0 to point 1 - Vector3 { x: 4, y: 0, z: 0 } const vector1 = polyFace[1].clone().sub(polyFace[0]); // The vector from point 0 to point 2 - Vector3 { x: 0, y: 2, z: 0 } const vector2 = polyFace[2].clone().sub(polyFace[0]); // Use the cross product to calculate the perpendicular vector // Then normalise const planeNormal = vector1.clone().cross(vector2).normalize(); console.log(planeNormal); // Vector3 { x: 0, y: 0, z: 1 } // The resulting vector points straight up on the Z axis That is the basic toolkit for working with 3D vectors. Further improvments could be made to this class by adding in a fromArray() method. I\u0026rsquo;m sure that other methods will also to mind when you start working with the vector class.\n","date":null,"permalink":"https://virtualdesignfactory.com.au/articles/three-dimensional-vectors/","section":"Articles","summary":"","title":"Three Dimensional Vectors"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/tags/typescript/","section":"Tags","summary":"","title":"Typescript"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/tags/c++/","section":"Tags","summary":"","title":"C++"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/categories/windows/","section":"Categories","summary":"","title":"Windows"},{"content":"Main Window Requirements # Window Procedure Function Main Window Function Window Class (not a c++ class) Message Loop Resource file (optional) The windows API uses a LOT of preprocessor instructions to modify function definitions that can be very confusing at first. Also most of the interactions with the API will be through Macros rather than functions.\nFirst things first #Text encoding should be UNICODE as that is the standard these days. To enable unicode you will need to add two define statements:\n#define UNICODE #define _UNICODE Without these define statements, either in the code or as a compiler flag the wrong functions might be called. When using an IDE put them in the code, and make sure there are no automatic defines assumed by the IDE so as not to show confusing results with code paths.\nWindows Procedure Function #The window procedure needs to be defined, or at least declared prior to the main window function. The signature is:\nLRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM) LRESULT is a window API typedef CALLBACK expands to __stdcall and is absolutely required for this function to work\nFor the main window procedure, you should pass on any unprocessed messages to the default windows procedure:\nreturn DefWindowProc(hand, msg, wParam, lParam); Main Window Function #The main window function is a macro and the inclusion of the header file \u0026lt;windows.h\u0026gt; causes the compiler to use a different entry point (not main) and will prepare and call the WinMain function with the listed parameters.\nInt APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) APIENTRY expads to __stdcall and is required hInstance is a handle to the module (.exe) hPrevInstance is a hold over from the win16 api and is no longer used lpCmdLine is a string pointer containing the command line args nCmdShow is an int containing command line info regarding how the window should be show on start, useful for shortcut configurations\nWindow Class #The window class is a STRUCT and needs to be filled out completely prior to being registered with the system. Incorrect details will cause the class registration to fail…\nUse WNDCLASSEX (extended)\nSee example program at the bottom.\nMessage Loop #The message loop is blocking and runs for the entire time the window executable is running.\nMessages are obtained from the system, and then translated and distributed to the running application. Note the while loop for this, the logical comparison \u0026gt; 0 is important here, as negative values here would indicate an error so don’t use != 0 or leave it off.\nResource File #Using a resource file will allow the use of a manifest and also greatly simplify loading resources. See useful website references for details.\nThe file should be resource.rc\nIt needs to be compiled with the program objects.\nTo get an object compiled from a resource file you need to use a program called winders:\nwindres -i resource.rc -o resource.o Include resources in the program like this:\nMAKEINTRESOURCE(IDI_APPICON)\nOr depending on the use case just access the custom resource directly\nIDI_APPICON\nIDI_APPICON in this case is a custom defined resource and will be in the resource.h file\nExample Program #This is an example of a minimal program from which you could build off:\n#define UNICODE #define _UNICODE #include \u0026lt;windows.h\u0026gt; const wchar_t className[] = TEXT(\u0026#34;WindowClass\u0026#34;); LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, INT nCmdShow) { WNDCLASSEX wc; HWND hWnd; MSG msg; wc.cbClsExtra = 0; wc.cbSize = sizeof(WNDCLASSEX); wc.cbWndExtra = 0; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wc.hInstance = hInstance; wc.lpfnWndProc = WindowProc; wc.lpszClassName = className; wc.lpszMenuName = NULL; wc.style = 0; // Register the window class if (!RegisterClassEx(\u0026amp;wc)) { MessageBox(NULL, TEXT(\u0026#34;Could not register the window class\u0026#34;), TEXT(\u0026#34;Error\u0026#34;), MB_OK | MB_ICONERROR); return 1; } // Create the window hWnd = CreateWindowEx( 0, className, TEXT(\u0026#34;Window Title\u0026#34;), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInstance, NULL); if (!hWnd) { MessageBox(NULL, TEXT(\u0026#34;Could not create window\u0026#34;), TEXT(\u0026#34;Error\u0026#34;), MB_OK | MB_ICONERROR); return 1; } // Show the window ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Handle the message loop while (GetMessage(\u0026amp;msg, hWnd, 0, 0) \u0026gt; 0) { TranslateMessage(\u0026amp;msg); DispatchMessage(\u0026amp;msg); } return (INT)msg.lParam; } LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, msg, wParam, lParam); } I found a lot of useful resources while figuring out how to work with the Win32 API:\nOfficial Microsoft Documentation\nSome GUI Examples\nMinimizing C++ Win32 App To System Tray\nBuilding Win32 GUI apps with MinGW\nThe Forgers Win32 API Programming Tutorial\n","date":null,"permalink":"https://virtualdesignfactory.com.au/articles/working-with-the-win32-api/","section":"Articles","summary":"","title":"Working With the Win32 Api"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/categories/devops/","section":"Categories","summary":"","title":"Devops"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/tags/docker/","section":"Tags","summary":"","title":"Docker"},{"content":"What is Docker? #According to Wikipedia Docker is a set of platform as a service products that uses OS-level virtualization to deliver software in packages called containers.\nContainers are isolated from each other and contain their own software and configuration files. Containers are able to communitcate through private networks setup by docker.\nWhy put it on your server? #Installing Docker and configuring containers to run on an Ubuntu server can greatly simplify the task of setting up and maintaining the various software and services you may wish to run on your sever.\nThere is an emense collection of pre-built containers that you can use with docker for everything from hosting a simple web server to deploying complex microservices and more.\nInstallation #Now that we\u0026rsquo;ve covered the what and why, it\u0026rsquo;s time to actaully get started with the installation. For the purpose of this post, we\u0026rsquo;ll assume that you have a vanilla installation of UbuntuServer 18.04.4 LTS that you currently have SSH access to.\nDocker exists in the standard repositorys. It is possible to add the offical Docker repository to your sources list, but unless you have a particular need to do so, I find that it\u0026rsquo;s simpler and easier to use the one available in the standard repository.\nFirst things first:\nsudo apt update \u0026amp;\u0026amp; sudo apt upgrade -y Then install Docker:\nsudo apt install docker.io If you plan to use docker-compose to configure and run multiple containers at one, you will need to install that seperatley:\nsudo apt install docker-compose Next we should start Docker:\nsudo systemctl start docker Once that is all done, you can optionally configure Docker to start on boot:\nsudo systemctl enable docker To work with docker without having to use sudo you should add yourself to the docker group:\nsudo usermod -aG docker \u0026lt;your user name\u0026gt; In order for group assignments to take effect you may need to log out and back in to your server before continuing.\nAnd you should be able to check the Docker version without any errors appearing in the terminal:\ndocker --version At the time of writing the lastest docker version was\nDocker version 19.03.6, build 369ce74a3c\n","date":null,"permalink":"https://virtualdesignfactory.com.au/articles/installing-docker-on-ubuntu-server/","section":"Articles","summary":"","title":"Installing Docker on Ubuntu Server"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/tags/linux/","section":"Tags","summary":"","title":"Linux"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/tags/express/","section":"Tags","summary":"","title":"Express"},{"content":"","date":null,"permalink":"https://virtualdesignfactory.com.au/categories/node/","section":"Categories","summary":"","title":"Node"},{"content":"Express is a very popular web framework for Node JS which is a javascript runtime built on Chrome\u0026rsquo;s V8 javascript engine. Node can run on Windows, Mac or Linux and so can be used on your web server.\nIf you are new to Express, this is for you. Basic knowledge of Node and requiring node packages in your code is required.\nBefore we can get into programming the API itself, first we need to make a project folder and initialize package.json file so we can install the Express framework.\nMake a new directory for your example API and change into it:\nmkdir ExampleAPI cd ExampleAPI Create a package.json file with no questions asked and install the express framework\nnpm init -y npm i express compression cors helmet body-parser After a small download you should now see a new folder in your project directory called node_modules this is where the node package manager stores your project specific dependencies.\nNote: If you are using source control, you should update your .gitignore file to ignore this node_modules folder. If you clone this on another machine, to install the packages again you just type npm i in the project directory.\nWe have installed the express framework itself, along with some popular middleware that helps with security performace and parsing requests.\nExpress has a simple hello world example on their website, that we will use to get up and running with our extremely simple example API quickly. We are going to modify it slightly in order to use some middleware and return a JSON response. We\u0026rsquo;ll also add a simple echoing endpoint for post requests so our API behaves much like other API\u0026rsquo;s you might be familiar with.\nMaking a more interesting API is a challenge I leave to you.\nindex.js:\n// Require all the dependencies const express = require(\u0026#39;express\u0026#39;); const compression = require(\u0026#39;compression\u0026#39;); const cors = require(\u0026#39;cors\u0026#39;); const helmet = require(\u0026#39;helmet\u0026#39;); const bodyParser = require(\u0026#39;body-parser\u0026#39;); // Create the app const app = express(); const port = 3000; // Rudimentary logging function log(message) { console.log(`[${new Date().toISOString()}] ${message}`); } // Add middleware to the express app app.use(cors()); app.use(helmet()); app.use(compression()); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json({ extended: true })); // Routes are registered prior to starting the server // for more info on how routing works see the docs // https://expressjs.com/en/guide/routing.html // Simple route for displaying a messing on the root route app.get(\u0026#39;/\u0026#39;, (req, res) =\u0026gt; { log(`GET /`); res.status(200).json({ message: \u0026#39;Hello World\u0026#39; }); }); // Echo back any data provided under the \u0026#39;message\u0026#39; key app.post(\u0026#39;/echo\u0026#39;, (req, res) =\u0026gt; { log(`POST /echo -\u0026gt; ${JSON.stringify(req.body)}`); res.status(200).json({ message: req.body.message }); }); // Start the server app.listen(port, () =\u0026gt; { log(`Example JSON API listening at http://localhost:${port}`); }); With that done, we can test our new API by starting up the app from the terminal:\nnode index.js # Example app listening at http://localhost:3000 Using curl in a new terminal window you can test the response from the root route\ncurl http://localhost:3000 # {\u0026#34;message\u0026#34;:\u0026#34;Hello World\u0026#34;} And also we can POST some JSON data to our echo endpoint:\ncurl --header \u0026#34;Content-Type: application/json\u0026#34; \\ --request POST \\ --data \u0026#39;{ \u0026#34;message\u0026#34;: \u0026#34;This is my new JSON API\u0026#34; }\u0026#39; \\ http://localhost:3000/echo # {\u0026#34;message\u0026#34;:\u0026#34;This is my new JSON API\u0026#34;} ","date":null,"permalink":"https://virtualdesignfactory.com.au/articles/simple-json-api-express/","section":"Articles","summary":"","title":"Simple Json Api Express"},{"content":"If you need an example application to use try this Simple JSON API\nIn this basic example of how to containerize a node express app we will use Docker. It is assumed that that you have a working express application that you are ready to put into a container for deployment purposes.\nAlso assumed is that you have access to the Docker CLI which you can verify by running the following command in your terminal:\ndocker -v # Docker version 19.03.5, build 633a0ea (your version may differ) Building A Container #Navigate to your project folder and create a Dockerfile\nNote: This file is case sensitive so use a capital \u0026lsquo;D\u0026rsquo;\n# Use apline linux where ever possible # to keep container sizes to a minumum FROM node:alpine # Application Code WORKDIR /app # Install app dependencies COPY package*.json ./ # Install Dependancies RUN npm install # Expose port 3030 from the container EXPOSE 3030 # Run server by default CMD [\u0026#34;npm\u0026#34;, \u0026#34;start\u0026#34;] # Add application code COPY . . Each command in the Dockerfile results in a layer that is added to the base image layers. It is worth thinking about the order of operation here. Most updates that you make to your app after having deployed a build for testing will be code changes. As you can by the order of the commands copying in the application code is the last step. So if the only change is something in your application code only the last layer would need to be re-build in subsequent builds. If you were to add a new package to your project, then all the layers down to COPY package*.json ./ would need to be discarded and rebuilt.\nThe most important part of this file is the EXPOSE port number, in my example app it listens on port 3000, yours may be different, change the port number to suit if required.\nIf you are using the Simple JSON API example, this is all tha should be required to build your container. Using the docker CLI we can initiate a build using the docker build command:\ndocker build -t example-json-api:dev . In this command the -t stands for the tag name and the . is just referring to the current directory as the location of the Dockerfile\nOnce the build is completed you should see the last entry on the terminal indicating success:\n# Successfully tagged example-json-api:dev Now you should be able to see this new image in your list of local images:\ndocker images # REPOSITORY TAG IMAGE ID CREATED SIZE # example-json-api dev 6ba575ffb51f 2 minutes ago 83.2MB Running A Container #You can test run the image with the following command:\ndocker run --rm -p 3000:3000 example-json-api:dev The --rm flag here will automatically remove the container from the local container instances once you \u0026lt;ctrl\u0026gt; + C to stop the running container.\nThe -p flag tells docker to map local ports to the exposed container ports \u0026lt;local port\u0026gt;:\u0026lt;container port\u0026gt;\nThen you should be able to interact your app on the port that is exposed. In this example by opening a new termainal and using curl. The running container should log to the console when new requests are recieved.\n# [2020-04-25T16:01:51.034Z] Example JSON API listening at http://localhost:3000 # [2020-04-25T16:01:54.271Z] POST /echo -\u0026gt; {\u0026#34;message\u0026#34;:\u0026#34;This is my new JSON API\u0026#34;} # [2020-04-25T16:01:55.284Z] GET / Stop the container by using \u0026lt;ctrl\u0026gt; + C in the running container terminal.\nSaving A Container #Docker CLI has a very useful save command that we can use to convert the container into a .tar.gz file which can then be shared.\ndocker save example-json-api:dev | gzip \u0026gt; example-json-api.tar.gz Alternitively if you prefer not to gzip the result you will end up with a .tar file\ndocker save example-json-api:dev \u0026gt; example-json-api.tar Delete A Container #Using Docker CLI you can remove a container image as long as it\u0026rsquo;s not currently running on in a container instance with the following command:\ndocker rmi example-json-api:dev You can check that it\u0026rsquo;s successfully removed from your local images by running this command and verifying that it\u0026rsquo;s not in the list:\ndocker images Loading A Container #Docker CLI also has a load command for extracting .tar or .tar.gz archives that you may have saved.\ndocker load --input example-json-api.tar.gz Or if you have a .tar file\ndocker load --input example-json-api.tar You can check that it\u0026rsquo;s successfully loaded into your local images by running this command and verifying that it is in the list:\ndocker images # REPOSITORY TAG IMAGE ID CREATED SIZE # example-json-api dev 6ba575ffb51f 5 minutes ago 83.2MB The beauty of containerising your application is that it will be able to run on any platform that docker can run on, and there will not be any cross platform issues that mean there are subtle differences in how your app runs or unexpected bugs based on different underlying hardware.\n","date":null,"permalink":"https://virtualdesignfactory.com.au/articles/containerising-a-node-express-app/","section":"Articles","summary":"","title":"Containerising a Node Express App"}]