src/js/globalvariables.js
import { create, all } from 'mathjs'
import Assembly from './molecules/assembly.js'
import Box from './molecules/box.js'
import CutList from './molecules/cutlist.js'
import Circle from './molecules/circle.js'
import Color from './molecules/color.js'
import CutLayout from './molecules/cutlayout.js'
import Rectangle from './molecules/rectangle.js'
import ShrinkWrap from './molecules/shrinkwrap.js'
import Move from './molecules/move.js'
import Tag from './molecules/tag.js'
import RegularPolygon from './molecules/regularpolygon.js'
import Extrude from './molecules/extrude.js'
import Stl from './molecules/stl.js'
import Svg from './molecules/svg.js'
//import Nest from './molecules/nest.js'
import Intersection from './molecules/intersection.js'
import Difference from './molecules/difference.js'
import Constant from './molecules/constant.js'
import Equation from './molecules/equation.js'
import ExtractTag from './molecules/extracttag.js'
import Molecule from './molecules/molecule.js'
import GeneticAlgorithm from './molecules/geneticAlgorithm.js'
import Input from './molecules/input.js'
import Readme from './molecules/readme.js'
import AddBOMTag from './molecules/BOM.js'
import Rotate from './molecules/rotate.js'
import GitHubMolecule from './molecules/githubmolecule.js'
import Output from './molecules/output.js'
import Gcode from './molecules/gcode.js'
import Code from './molecules/code.js'
import Group from './molecules/group.js'
import UploadSVG from './molecules/uploadSVG.js'
import GitHubModule from './githubOauth'
/**
* This class defines things which are made available to all objects which import it. It is a singlton which means that each time it is imported the same instance is made available so if it is written to in one place, it can be read somewhere else.
*/
class GlobalVariables{
/**
* The constructor creates a new instance of the Global Variables object.
*/
constructor(){
/**
* The canvas object on which the atoms are drawn.
* @type {object}
*/
this.canvas = null
/**
* The 2D reference to the canvas object on which the atoms are drawn.
* @type {object}
*/
this.c = null
/**
* An array of all of the available types of atoms which can be placed with a right click.
* @type {array}
*/
this.availableTypes = {
box: {creator: Box, atomType: 'Box'},
intersection: {creator: Intersection, atomType: 'Intersection', atomCategory: 'Interactions'},
difference: {creator: Difference, atomType: 'Difference', atomCategory: 'Interactions'},
assembly: {creator: Assembly, atomType: 'Assembly', atomCategory: 'Interactions'},
union: {creator: Group, atomType: 'Union', atomCategory: 'None'},
group: {creator: Group, atomType: 'Group', atomCategory: 'None'},
shrinkwrap: {creator: ShrinkWrap, atomType: 'ShrinkWrap', atomCategory: 'Interactions'},
readme: {creator: Readme, atomType: 'Readme', atomCategory: 'Tags'},
addBOMTag: {creator: AddBOMTag, atomType: 'Add-BOM-Tag', atomCategory: 'Tags'},
color: {creator: Color, atomType: 'Color', atomCategory: 'Tags'},
tag: {creator: Tag, atomType: 'Tag', atomCategory: 'Tags'},
extracttag: {creator: ExtractTag, atomType: 'ExtractTag', atomCategory: 'Tags'},
cutLayout: {creator: CutLayout, atomType: 'CutLayout', atomCategory: 'Tags'},
CutList: {creator: CutList, atomType: 'CutList', atomCategory: 'Tags'},
regularPolygon: {creator: RegularPolygon, atomType: 'RegularPolygon', atomCategory: 'Shapes'},
costant: {creator: Constant, atomType: 'Constant', atomCategory: 'Inputs'},
circle: {creator: Circle, atomType: 'Circle', atomCategory: 'Shapes'},
rectangle: {creator: Rectangle, atomType: 'Rectangle', atomCategory: 'Shapes'},
molecule: {creator: Molecule, atomType: 'Molecule', atomCategory: 'Shapes'},
input: {creator: Input, atomType: 'Input', atomCategory: 'Inputs'},
equation: {creator: Equation, atomType: 'Equation', atomCategory: 'Inputs'},
code: {creator: Code, atomType: 'Code', atomCategory: 'Inputs'},
rotate: {creator: Rotate, atomType: 'Rotate', atomCategory: 'Actions'},
extrude: {creator: Extrude, atomType: 'Extrude', atomCategory: 'Actions'},
move: {creator: Move, atomType: 'Move', atomCategory: 'Actions'},
translate: {creator: Move, atomType: 'Translate', atomCategory: 'none'},
GeneticAlgorithm: {creator: GeneticAlgorithm, atomType: 'GeneticAlgorithm', atomCategory: 'Actions'},
stl: {creator: Stl, atomType: 'Stl', atomCategory: 'Export'},
svg: {creator: Svg, atomType: 'Svg', atomCategory: 'Export'},
//nest: {creator: Nest, atomType: 'Nest', atomCategory: 'Export'},
gcode: {creator: Gcode, atomType: 'Gcode', atomCategory: 'Export'},
uploadSVG: {creator: UploadSVG, atomType: 'UploadSVG', atomCategory: 'Export'},
githubmolecule: {creator: GitHubMolecule, atomType: 'GitHubMolecule', atomCategory: 'Inputs'},
output: {creator: Output, atomType: 'Output'}
}
/**
* A reference to the molecule curently being displayed on the screen.
* @type {object}
*/
this.currentMolecule
/**
* A reference to the top level molecule of the project.
* @type {object}
*/
this.topLevelMolecule
/**
* A flag to indicate if the program is running in run mode (ie a shared link).
* @type {boolean}
*/
this.runMode = false
/**
* A flag to indicate if the program is running with a touch interface. Set in flowDraw.js.
* @type {boolean}
*/
this.touchInterface = false
/**
* The github object which is used to interact with GitHub.
* @type {object}
*/
this.gitHub = new GitHubModule()
/**
* A total of the number of atoms in this project
* @type {integer}
*/
this.totalAtomCount = 0
/**
* A counter used during the loading process to keep track of how many atoms are still to be loaded.
* @type {integer}
*/
this.numberOfAtomsToLoad = 0
/**
* A flag to indicate if the project is a fork.
* @type {boolean}
*/
this.fork = false
/**
* A flag to indicate if command is pressed
* @type {boolean}
*/
this.ctrlDown = false
/**
* A variable to save array to be copied
* @type {array}
*/
this.atomsSelected = []
/**
* The size (in mm) of segments to use for circles.
* @type {number}
*/
this.circleSegmentSize = 2
/**
* A flag to indicate if a display value is currently being processed.
* @type {bool}
*/
this.displayProcessing = false
/**
* The function to call to cancel the processing of the prevous display value.
* @type {function}
*/
this.cancelLastDisplayWorker = function(){}
/**
* The last path displayed. Used for updating the display when the controls change.
* @type {string}
*/
this.displayedPath = ""
/**
* A list of all of the paths in this project which can be read from memory
* @type {array}
*/
this.availablePaths = []
/**
* A flag to indicate if a grid should be displayed behind the shape
* @type {boolean}
*/
this.displayGrid = true
/**
* A flag to indicate if the edges of the shape should be displayed.
* @type {boolean}
*/
this.displayAxis = true
/**
* A flag to indicate if the display should show axis.
* @type {boolean}
*/
this.displayTriangles = true
/**
* A flag to indicate if the faces of the shape should be displayed.
* @type {boolean}
*/
this.displayEdges = true
const math = create(all) //What does this do? I think it is used to evalue strings as math
/**
* An evaluator for strings as mathmatical equations which is sandboxed and secure.
* @type {function}
*/
this.limitedEvaluate = math.evaluate
math.import({
'import': function () { throw new Error('Function import is disabled') },
'createUnit': function () { throw new Error('Function createUnit is disabled') },
'evaluate': function () { throw new Error('Function evaluate is disabled') },
'parse': function () { throw new Error('Function parse is disabled') },
'simplify': function () { throw new Error('Function simplify is disabled') },
'derivative': function () { throw new Error('Function derivative is disabled') }
}, { override: true })
}
/**
* A function to generate a pixel value for 0-1 location on screen depending on screen width
* @param {number} width 0-1
*/
widthToPixels(width){
width = Math.min(width, 1) //Constrain the position to be a max of 1
let pixels = this.canvas.width * width
return pixels
}
/**
* A function to generate a 0-1 value from pixels for location on screen depending on screen width
* @param {number} width 0-1
*/
pixelsToWidth(pixels){
let width = 1 /(this.canvas.width / pixels)
return width
}
/**
* A function to generate a pixel value for 0-1 location on screen depending on screen height
* @param {number} width 0-1
*/
heightToPixels(height){
height = Math.min(height, 1) //Constrain the position of the max value to be 1
let pixels = this.canvas.height * height
return pixels
}
/**
* A function which reads from a path and displays the geometry it contains
* @param {string} The path to read from
*/
writeToDisplay(path, resetView = false){
this.displayedPath = path
// Cancel the last write to display if there is one active because this one will replace it
if(this.displayProcessing){
this.cancelLastDisplayWorker()
this.displayProcessing = false
}
const {answer, terminate} = window.ask({ evaluate: "md`hello`",
op: "display",
readPath: path,
triangles: this.displayTriangles,
outline: this.displayEdges,
wireframe: false
})
answer.then( result => {
this.displayProcessing = false
document.getElementById('viewerContext').style.filter="sepia(0%)"
if(result && result != -1){
window.updateDisplay(result)
window.showGrid(this.displayGrid)
if(resetView){
window.updateFit()
}
}
}).catch ((e) => console.warn(e))
this.displayProcessing = true
document.getElementById('viewerContext').style.filter="sepia(100%)"
/**
* A function which cancels the worker processing display when called
*/
this.cancelLastDisplayWorker = terminate
}
/**
* A function to generate a 0-1 value from pixels for location on screen depending on screen height
* @param {number} width 0-1
*/
pixelsToHeight(pixels){
let height = 1 /(this.canvas.height / pixels)
return height
}
/**
* A function to generate a unique ID value. Currently uses random which does not gurintee that it will be unique.
*/
generateUniqueID(){
return Math.floor(Math.random()*900000) + 100000
}
/**
* Computes the distance between two points on a plane. This is a duplicate of the one in utils which should probably be deleted.
* @param {number} x1 - The x cordinate of the first point.
* @param {number} x2 - The x cordinate of the second point.
* @param {number} y1 - The y cordinate of the first point.
* @param {number} y2 - The y cordinate of the second point.
*/
distBetweenPoints(x1, x2, y1, y2){
var a2 = Math.pow(x1 - x2, 2)
var b2 = Math.pow(y1 - y2, 2)
var dist = Math.sqrt(a2 + b2)
return dist
}
}
/**
* Because we want global variables to be the same every time it is imported we export an instance of global variables instead of the constructor.
*/
export default (new GlobalVariables)