// module: TRUE
// @ts-ignore
import { gui } from "./pre_intrusion_contour_plot_gui.jsi";
let workflowDefinitionFilename = Workflow.WorkflowDefinitionFilename();
// The following variables are global as they are passed into multiple functions
let a; // node 1 object
let b; // node 2 object
let c; // node 3 object
let xx; // x vector x direction
let xy; // x vector y direction
let xz; // x vector z direction
let yx; // y vector x direction
let yy; // y vector y direction
let yz; // y vector z direction
let zx; // z vector x direction
let zy; // z vector y direction
let zz; // z vector z direction
let m; // the model that is selected in the set up function
set_up();
/* Show the first window */
gui.Window1.keepOnTop = true; // Makes the GUI stay on top, otherwise when you move the graphics window it gets hidden behind it and you can't see it
if (gui) gui.Window1.Show(false);
function set_up() {
// Selecting the model to use if there are multiple ones open in PRIMER
gui.model = Model.Select("Select the model to use");
if (gui.model == null) {
Window.Information("", "You need to select a model before you can use this workflow");
Exit();
}
m = gui.model;
// Reading in any previously saved data
let numModels = Workflow.NumberOfModels();
for (let i = 0; i < numModels; i++) {
let modelID = Workflow.ModelIdFromIndex(i);
if (modelID != gui.model.number) {
continue;
}
/** @type {UserData} */
let userData = Workflow.ModelUserDataFromIndex(i);
try {
// @ts-ignore
gui.Window1.txtParts.text = userData.parts;
// @ts-ignore
gui.Window1.txtN1.text = userData.node1;
// @ts-ignore
gui.Window1.txtN2.text = userData.node2;
// @ts-ignore
gui.Window1.txtN3.text = userData.node3;
} catch (e) {
ErrorMessage("Error reading saved data");
}
}
// setting up callback functions
gui.Window1.btnSelect.onClick = select;
gui.Window1.txtN1.onChange = coordinate_system;
gui.Window1.txtN2.onChange = coordinate_system;
gui.Window1.txtN3.onChange = coordinate_system;
gui.Window1.btnSelectN1.onClick = select_n1;
gui.Window1.btnSelectN2.onClick = select_n2;
gui.Window1.btnSelectN3.onClick = select_n3;
gui.Window1.btnSaveToFile.onClick = save_to_file;
gui.Window1.btnSaveToModel.onClick = save_to_model;
gui.Window1.helpBtn.onClick = workflow_manual;
}
/**
* Select the parts when clicked
*/
function select() {
/* Select parts and populate text box. Assume there is just one model loaded */
if (!m) {
Window.Message("", "You need to read a model into PRIMER");
return;
}
let f = AllocateFlag();
let selection = Part.Select(f, "Pick parts of interest", m, false);
if (selection == null) {
ReturnFlag(f);
return;
}
let text = "";
let p = Part.First(m);
let first = true;
while (p) {
if (p.Flagged(f)) {
if (first) {
text += p.label;
first = false;
} else {
text += " " + p.label;
}
}
p = p.Next();
}
ReturnFlag(f);
gui.Window1.txtParts.text = text;
}
/**
* Select node 1 when pick is clicked
*/
function select_n1() {
let n1 = Node.Pick("Pick node1", m);
if (!n1) return;
gui.Window1.txtN1.text = n1.label;
coordinate_system();
}
/**
* Select node 2 when pick is clicked
*/
function select_n2() {
let n2 = Node.Pick("Pick node2", m);
if (!n2) return;
gui.Window1.txtN2.text = n2.label;
coordinate_system();
}
/**
* Select node 3 when pick is clicked
*/
function select_n3() {
let n3 = Node.Pick("Pick node3", m);
if (!n3) return;
gui.Window1.txtN3.text = n3.label;
coordinate_system();
}
/**
* Calculates coordinate system ready for it be drawn
*/
function coordinate_system() {
// Exits the function if any of the nodes does not contain a number or any text at all
if (gui.Window1.txtN1.text == "") {
return;
}
if (gui.Window1.txtN2.text == "") {
return;
}
if (gui.Window1.txtN3.text == "") {
return;
}
if (isNaN(gui.Window1.txtN1.text)) {
return;
}
if (isNaN(gui.Window1.txtN2.text)) {
return;
}
if (isNaN(gui.Window1.txtN3.text)) {
return;
}
a = Node.GetFromID(m, parseInt(gui.Window1.txtN1.text)); // node 1
b = Node.GetFromID(m, parseInt(gui.Window1.txtN2.text)); // node 2
c = Node.GetFromID(m, parseInt(gui.Window1.txtN3.text)); // node 3
if (a == null || b == null || c == null) {
WarningMessage("One of the nodes you entered does not exist");
return;
}
// X vector is b-a
xx = b.x - a.x;
xy = b.y - a.y;
xz = b.z - a.z;
// B vector is c-a
let bx = c.x - a.x;
let by = c.y - a.y;
let bz = c.z - a.z;
// To get the Z vector we need to cross the X vector with the B vector
// z cross product vector
zx = xy * bz - by * xz;
zy = bx * xz - xx * bz;
zz = xx * by - bx * xy;
// To get the Y cross product vector you then need to cross the Z and the X vectors.
yx = zy * xz - xy * zz;
yy = xx * zz - zx * xz;
yz = zx * xy - xx * zy;
// Find the magnitude of the vectors
let lengthx = Math.sqrt(xx * xx + xy * xy + xz * xz);
let lengthy = Math.sqrt(yx * yx + yy * yy + yz * yz);
let lengthz = Math.sqrt(zx * zx + zy * zy + zz * zz);
// Normalise the vectors
xx /= lengthx; // This is shorthand for xx = xx / lengthx
xy /= lengthx;
xz /= lengthx;
yx /= lengthy;
yy /= lengthy;
yz /= lengthy;
zx /= lengthz;
zy /= lengthz;
zz /= lengthz;
// Make the lines the size you want
let size = 250;
xx = xx * size;
xy = xy * size;
xz = xz * size;
yx = yx * size;
yy = yy * size;
yz = yz * size;
zx = zx * size;
zy = zy * size;
zz = zz * size;
// how PRIMER calculates coordinate system, un-comment this to check if own method is correct.
// we can't use this PRIMER method because it saves an entity to the model which we don't want.
//let cs = new CoordinateSystem(m, CoordinateSystem.NODES, 200, parseInt(gui.Window1.txtN1.text), parseInt(gui.Window1.txtN2.text), parseInt(gui.Window1.txtN3.text), 0, 1, "Test csys");
//cs.Sketch();
do_draw();
Graphics.DrawingFunction(do_draw);
View.Redraw();
}
/**
* Draws coordinate geometry based on the selected nodes
*/
function do_draw() {
Graphics.Start();
Graphics.DepthTest(false); // Turning depth testing off may be used to ensure that an item (e.g. a line or text) is always drawn in front of parts and will not be obscured.
// Setting up details for sketching. The sketch colour ensures colour matches theme of PRIMER so you can always see it.
Graphics.LineWidth(1);
Graphics.LineColour(Colour.SKETCH);
Graphics.LineStyle(Graphics.SOLID_LINE);
Graphics.TextColour(Colour.SKETCH);
Graphics.TextSize(10);
// X Line
Graphics.Line(a.x, a.y, a.z, a.x + xx, a.y + xy, a.z + xz);
Graphics.MoveTo(a.x + xx / 2, a.y + xy / 2, a.z + xz / 2);
Graphics.Text("X");
// Z Line
Graphics.Line(a.x, a.y, a.z, a.x + zx, a.y + zy, a.z + zz);
Graphics.MoveTo(a.x + zx / 2, a.y + zy / 2, a.z + zz / 2);
Graphics.Text("Z");
// Y Line
Graphics.Line(a.x, a.y, a.z, a.x + yx, a.y + yy, a.z + yz);
Graphics.MoveTo(a.x + yx / 2, a.y + yy / 2, a.z + yz / 2);
Graphics.Text("Y");
Graphics.Finish();
}
/**
* Saves the data to a file
*/
function save_to_file() {
/* Get data to write to file */
let userData = get_user_data();
/* Ask the user where to write it */
let outputFilename = Window.GetFile(".json", true);
if (outputFilename == null) return;
/* API call to write workflow file */
Workflow.WriteToFile(userData, outputFilename, workflowDefinitionFilename);
Message("Written workflow file to " + outputFilename);
}
/**
* Saves the data to the model
*/
function save_to_model() {
/* Get data to write to file */
let userData = get_user_data();
/* Ask the user which model to write it to */
let model = Model.Select("Select the model to write to");
if (model == null) return;
/* API call to write workflow to a model */
Workflow.WriteToModel(userData, model, workflowDefinitionFilename);
Message("Workflow data added to post *END data. You need to write out the model from the main Model->Write menu to save the additions.");
}
/**
* The user data object
* @returns {Object} UserData
*/
function get_user_data() {
return {
parts: gui.Window1.txtParts.text,
node1: parseInt(gui.Window1.txtN1.text),
node2: parseInt(gui.Window1.txtN2.text),
node3: parseInt(gui.Window1.txtN3.text)
};
}
/**
* Opens up the clickhelp manual when the help button is pressed
*/
function workflow_manual() {
OpenManual("primer", "intrusion-contour-plot.html");
}
/**
* The user data object in the workflow file
* @typedef {Object} UserData
*/