post_eroded_elements.js

// module: TRUE

/** Model ID for workflow model
 *  @type {number} */
let model_id = Workflow.ModelIdFromIndex(0);
let unit_system = Workflow.ModelUnitSystemFromIndex(0);

/** Model information for workflow model */
let info = GetModelInfo(model_id);

/** Window ID for workflow model
 *  @type {number} */
let win_id = -1;

/** Number of BEAMs in workflow model
 *  @type {number} */
let nbeam = 0;

/** Number of SHELLs in workflow model
 *  @type {number} */
let nshell = 0;

/** Number of SOLIDs in workflow model
 *  @type {number} */
let nsolid = 0;

/** Number of TSHELLs in workflow model
 *  @type {number} */
let ntshell = 0;

/** To store the previous state
 *  @type {number} */
let prev_st = info.num_states;

/** To store the previous comp_state
 *  @type {number} */
let prev_cst = 0;

/** Workflow initialisation
 * @type {boolean} */
let initialised = false;

/** Properties filename
 * @type {string} */
let props_filename = null;

/** Exit script without changing properties
 * @type {boolean} */
let exit_without_props = false;

import { SavePropFile, LoadPropFile, DelPropFile } from "../../modules/d3plot_properties.js";

import * as guiWdw from "./post_eroded_elements_gui_raw.js";
guiWdw.wdwErodedElements.Show(false); /* Show the first window */

/**
 * Main callback function to update the deleted elements displayed
 */
export function update_plot()
{
    SetCurrentModel(model_id);

    win_id = calc_window_id();

    /* Update total number of states in model */
    guiWdw.stateTotal.text = `/ ${info.num_states}`;

    /** Deleted elements display mode
     *  @type {number} */
    let mode = 1;

    switch (guiWdw.displayMode.selectedItem.text.substring(0, 1))
    {
        case "1": mode = 1; break;
        case "2": mode = 2; break;
        case "3": mode = 3; break;

        default: mode = 1;
    }

    /* If stateTB.text is not a number, revert to previous comparison state */
    if (isNaN(parseInt(guiWdw.cstateTB.text)))
    {
        WarningMessage(`${guiWdw.cstateTB.text} is not a number. Reverted to previous comparison state.`);
        guiWdw.cstateTB.text = `${prev_cst}`;
        return;
    }

    /** Deleted elements before this state are not displayed
     *  @type {number} */
    let comp_state = parseInt(guiWdw.cstateTB.text);

    /* If comp_state is not a valid state, revert to previous comparison state */
    if (comp_state < 0 || comp_state > info.num_states)
    {
        WarningMessage(`State ${comp_state} is not a valid state between 0 to ${info.num_states}. Reverted to previous comparison state.`);
        guiWdw.cstateTB.text = `${prev_cst}`;
        return;
    }

    /* If comp_state is not a valid state, revert to previous comparison state */
    if (comp_state > prev_st)
    {
        WarningMessage(`State ${comp_state} exceeds plot state (${prev_st}). Reverted to previous comparison state.`);
        guiWdw.cstateTB.text = `${prev_cst}`;
        return;
    }

    guiWdw.cstateTB.text = `${comp_state}`;
    prev_cst = comp_state;

    /* If stateTB.text is not a number, revert to previous plot state */
    if (isNaN(parseInt(guiWdw.stateTB.text)))
    {
        WarningMessage(`${guiWdw.stateTB.text} is not a number. Reverted to previous plot state.`);
        guiWdw.stateTB.text = `${prev_st}`;
        return;
    }

    /** Deleted elements displayed are elements deleted by this state
     *  @type {number} */
    let state = parseInt(guiWdw.stateTB.text);

    /* If state is not a valid state, revert to previous plot state */
    if (state < 1 || state < comp_state || state > info.num_states)
    {
        if (state < 1 || state > info.num_states)
            WarningMessage(`State ${state} is not a valid state between 1 to ${info.num_states}. Reverted to previous plot state.`);
        else
            WarningMessage(`State ${state} is before the comparison state (${comp_state}). Reverted to previous plot state.`);
        guiWdw.stateTB.text = `${prev_st}`;
        return;
    }

    guiWdw.stateTB.text = `${state}`;
    prev_st = state;

    /* Lower the frequency of the graphics updates */
    DialogueInputNoEcho("/UTILITIES CUSTOMISE UPDATE_LEVEL", "1");

    /* Go to first state & count elements */
    DialogueInputNoEcho(`/CM ${model_id}`, "/STATE 1");
    SetCurrentState(1);
    nbeam = GetNumberOf(BEAM);
    nshell = GetNumberOf(SHELL);
    nsolid = GetNumberOf(SOLID);
    ntshell = GetNumberOf(TSHELL);

    /** Number of elements deleted (from comparison state to concerned state)
     *  @type {number} */
    let deleted_elems = 0;

    /* Check for presence of deleted elements */
    if (comp_state == 0)
        deleted_elems = NumDeleted(ELEM, state);
    else
        deleted_elems = NumDeleted(ELEM, state) - NumDeleted(ELEM, comp_state);

    /* Give message if there are no deleted elements for state concerned */
    if (!deleted_elems)
    {
        if (mode == 1 || mode == 3)
        {
            /* Blank everything */
            Blank(MODEL, "ALL", win_id);
        }
        else if (mode == 2)
        {
            /* Unblank everything */
            Unblank(MODEL, "ALL", win_id);

            /* Set everything to transparent-grey */
            DialogueInputNoEcho("/PROPERTIES TRANSPARENCY ALL", "50");
            DialogueInputNoEcho("/PROPERTIES COLOUR ALL", "GREY");
        }
        /* Refresh graphics */
        DialogueInputNoEcho("/REDRAW");

        /* Reset the frequency of the graphics updates*/
        DialogueInputNoEcho("/UTILITIES CUSTOMISE UPDATE_LEVEL", "3");

        /* Quit dialogue input */
        DialogueInputNoEcho("Quit");

        WarningMessage(`No elements have been deleted from state ${comp_state} to state ${state}`);
        return;
    }

    /* Blank everything */
    Blank(MODEL, "ALL", win_id);

    if (mode == 1)
    {
        /* Reset transparency */
        DialogueInputNoEcho("/PROPERTIES TRANSPARENCY ALL", "0");
        /* Reset colours to default */
        DialogueInputNoEcho("/PROPERTIES COLOUR ALL", "DEFAULT");

        /* Unblank all elements deleted (from comparison state to concerned state) */
        SetCurrentState(state);
        Unblank(ELEM, "ALL_DEL", win_id);
        if (comp_state != 0)
        {
            SetCurrentState(comp_state);
            Blank(ELEM, "ALL_DEL", win_id);
        }
        SetCurrentState(1);
    }
    else if (mode == 2) // Working but has slight flicker at /SH
    {
        /* Set everything to transparent-grey */
        DialogueInputNoEcho("/PROPERTIES TRANSPARENCY ALL", "50");
        DialogueInputNoEcho("/PROPERTIES COLOUR ALL", "GREY");

        /* Unblank all elements deleted (from comparison state to concerned state) */
        SetCurrentState(state);
        Unblank(ELEM, "ALL_DEL", win_id);
        if (comp_state != 0)
        {
            SetCurrentState(comp_state);
            Blank(ELEM, "ALL_DEL", win_id);
        }
        SetCurrentState(1);

        /* Refresh graphics, required for AV to work properly */
        DialogueInputNoEcho("/REDRAW");

        /* Set deleted elements to red-opaque */
        colour_elements("AV", "RED"); //Change "AV" to "ALL_DEL" once its been added to the dialogue input, will remove the flicker
        transparency_elements("AV", "0");

        /* Unblank everything */
        Unblank(MODEL, "ALL", win_id);
    }
    else if (mode == 3) // Working but has slight flicker at /SH
    {
        /* Set everything to transparent-grey */
        DialogueInputNoEcho("/PROPERTIES TRANSPARENCY ALL", "50");
        DialogueInputNoEcho("/PROPERTIES COLOUR ALL", "GREY");

        /* Unblank all elements deleted (from comparison state to concerned state) */
        SetCurrentState(state);
        Unblank(ELEM, "ALL_DEL", win_id);
        if (comp_state != 0)
        {
            SetCurrentState(comp_state);
            Blank(ELEM, "ALL_DEL", win_id);
        }
        SetCurrentState(1);

        /* Refresh graphics, required for AV to work properly */
        DialogueInputNoEcho("/REDRAW");

        /* Set deleted elements to default colour & transparency */
        colour_elements("AV", "DEFAULT"); //Change "AV" to "ALL_DEL" once its been added to the dialogue input, will remove the flicker
        transparency_elements("AV", "0");

        /* Unblank all visible parts */
        DialogueInputNoEcho("/UNBLANK PART AV");
    }

    /* Refresh graphics (Shaded Image mode) */
    DialogueInputNoEcho("/SH");

    /* Reset the frequency of the graphics updates*/
    DialogueInputNoEcho("/UTILITIES CUSTOMISE UPDATE_LEVEL", "3");

    /* Quit dialogue input */
    DialogueInputNoEcho("Quit");

    /* Inform users about total number of deleted elements */
    Message(`${deleted_elems} elements have been deleted from state ${comp_state} to state ${state}`);
}

/**
 * Callback function that sets the colour for elements (BEAM, SHELL, SOLID & TSHELL)
 * @param {string} items Element items to set the colour. Can be "ALL", "AV" etc.
 * @param {string} colour Colour: "RED", "GREY" etc.
 */
function colour_elements(items, colour)
{
    if (nbeam) DialogueInputNoEcho(`/PROPERTIES COLOUR BEAM ${items}`, colour);
    if (nshell) DialogueInputNoEcho(`/PROPERTIES COLOUR SHELL ${items}`, colour);
    if (nsolid) DialogueInputNoEcho(`/PROPERTIES COLOUR SOLID ${items}`, colour);
    if (ntshell) DialogueInputNoEcho(`/PROPERTIES COLOUR TSHELL ${items}`, colour);
}

/**
 * Callback function that sets the transparency for elements (BEAM, SHELL, SOLID & TSHELL)
 * @param {string} items Element items to set the transparency. Can be "ALL", "AV" etc.
 * @param {string} percentage Percentage transparency: "0", "50" etc.
 */
function transparency_elements(items, percentage)
{
    if (nbeam) DialogueInputNoEcho(`/PROPERTIES TRANSPARENCY BEAM ${items}`, percentage);
    if (nshell) DialogueInputNoEcho(`/PROPERTIES TRANSPARENCY SHELL ${items}`, percentage);
    if (nsolid) DialogueInputNoEcho(`/PROPERTIES TRANSPARENCY SOLID ${items}`, percentage);
    if (ntshell) DialogueInputNoEcho(`/PROPERTIES TRANSPARENCY TSHELL ${items}`, percentage);
}

/**
 * Callback function to calculate the window_id for model_id.
 * Returns -1 if a window can't be found (can happen if the window containing the
 * model has been deleted, but not the model [Window -> Close Window -> Leave Model]
 * @returns {number} Window ID
 */
function calc_window_id()
{
    /** Number of windows in D3PLOT
     *  @type {number} */
    let n = GetNumberOf(WINDOW);

    /** Window ID corresponding to model_id
     *  @type {number} */
    let window_id = -1;

    /** Number of models in window_id
     *  @type {number[]} */
    let nm = [1, 1];

    for (let i = 1; i <= n; i++)
    {
        /** Model numbers in window i */
        let wm = GetWindowModels(i);

        for (let j = 0; j < wm.nm; j++)
        {
            if (wm.list[j] == model_id)
            {
                window_id = i;
                nm[0] = wm.nm;
                nm[1] = j + 1;
                break;
            }
        }
    }

    if (nm[0] > 1)
    {
        WarningMessage(`Model ${model_id} is model ${nm[1]}/${nm[0]} in window ${window_id}. This workflow does not work properly for windows with more than 1 model.`);
        exit_without_props = true;
        exit_eroded_elements();
    }

    if (window_id == -1) /* Aka. if the window containing the model has been deleted, but not the model [Window -> Close Window -> Leave Model] */
    {
        WarningMessage("Unable to find model window");
        exit_without_props = true;
        exit_eroded_elements();
    }
    return window_id;
}

/**
 * Callback function corresponding to the firstState button
 */
export function first_state()
{
    /** Update stateTB with this state
     *  @type {number} */
    let state = 1;
    guiWdw.stateTB.text = `${state}`;

    update_plot();
}

/**
 * Callback function corresponding to the prevState button
 */
export function prev_state()
{
    /** Update stateTB with this state
     *  @type {number} */
    let state = parseInt(guiWdw.stateTB.text);
    if (state - 1 >= 1)
        state -= 1;
    else
    {
        WarningMessage("This is already the first state.");
        return;
    }
    guiWdw.stateTB.text = `${state}`;

    update_plot();
}

/**
 * Callback function corresponding to the nextState button
 */
export function next_state()
{
    /** Update stateTB with this state
     *  @type {number} */
    let state = parseInt(guiWdw.stateTB.text);
    if (state + 1 <= info.num_states)
        state += 1;
    else
    {
        WarningMessage("This is already the last state.");
        return;
    }

    guiWdw.stateTB.text = `${state}`;

    update_plot();
}

/**
 * Callback function corresponding to the finalState button
 */
export function last_state()
{
    /** Update stateTB with this state
     *  @type {number} */
    let state = info.num_states;
    guiWdw.stateTB.text = `${state}`;

    /* Save properties for restoration later */
    if (!initialised)
    {
        props_filename = SavePropFile(model_id);
        initialised = true;
    }

    update_plot();
}

/**
 * Callback function to open workflow manual
 */
export function workflow_manual()
{
    OpenManual("d3plot", "eroded-elements.html");
}

/**
 * Callback function to give message on exit of workflow
 */
export function exit_eroded_elements()
{
    if (exit_without_props)
        DelPropFile(props_filename); /* Delete temporary properties file */
    else
        LoadPropFile(model_id, props_filename);

    Message("Exited post_eroded_elements.js");
    Exit();
}