Warning, /firebird/firebird-ng/src/lib-root-geometry/root-geo-edit.ts is written in an unsupported language. File is not indexed.
0001 import {
0002 GeoNodeWalkCallback,
0003 getGeoNodesByLevel,
0004 walkGeoNodes
0005 } from "./root-geo-navigation";
0006 import {wildCardCheck} from "../app/utils/wildcard";
0007 import {GeoAttBits, setGeoBit, toggleGeoBit} from "./root-geo-attribute-bits";
0008
0009
0010 export enum EditActions {
0011 Nothing, /** Do not remove this or other nodes */
0012 Remove, /** Removes this node from parent */
0013 RemoveSiblings, /** Remove all sibling nodes and leave only this node */
0014 RemoveChildren, /** Remove all child nodes */
0015 RemoveBySubLevel, /** Remove all nodes below N levels */
0016 SetGeoBit, /** Set certain Root GeoAtt bit */
0017 UnsetGeoBit, /** Unset certain ROOT GeoAtt bit */
0018 ToggleGeoBit /** Toggle certain ROOT GeoAtt bit */
0019 }
0020
0021 /**
0022 * Defines editing rules for geographic nodes based on a pattern.
0023 */
0024 export class GeoNodeEditRule {
0025 public pattern: string = '';
0026 public action?: EditActions = EditActions.Nothing;
0027 public pruneSubLevel?: number = Infinity;
0028
0029 /** Used only if action is one of SetGeoBit, UnsetGeoBit or ToggleGeoBit */
0030 public geoBit?:GeoAttBits;
0031
0032 public childrenRules?: GeoNodeEditRule[] = [];
0033 public childrenRulesMaxLevel?: number = Infinity;
0034 }
0035
0036
0037 /**
0038 * Edits ROOT Geometry nodes based on specified rules. This function walks through each node,
0039 * applying transformation rules such as removing nodes or modifying node arrays based on provided patterns.
0040 *
0041 * @param {any} topNode - The top node of the geometry tree to edit.
0042 * @param {GeoNodeEditRule[]} rules - An array of rules defining how nodes should be edited.
0043 * @param {number} [maxLevel=Infinity] - The maximum level of the node tree to traverse.
0044 * @returns {any[]} An array of objects detailing nodes that were postponed for processing.
0045 */
0046 export function editGeoNodes(topNode: any, rules: GeoNodeEditRule[], maxLevel:number=Infinity): any[] {
0047 let postponedProcessing: {node: any, fullPath: string, rule: GeoNodeEditRule}[] = [];
0048
0049 let tmpRules = [...rules];
0050
0051 // Define a callback using the GeoNodeWalkCallback type
0052 const collectNodes: GeoNodeWalkCallback = (node, nodeFullPath, level) => {
0053 for(const rule of tmpRules) {
0054
0055 if(nodeFullPath === undefined) {
0056 console.log(`nodeFullPath == undefined`);
0057 }
0058
0059 if(rule?.pattern === undefined) {
0060 console.log(`rule?.pattern == undefined ${rule}`);
0061 }
0062
0063 // Does the node fulfill the rule?
0064 if(wildCardCheck(nodeFullPath, rule.pattern)) {
0065
0066 // This rule has subnode rules
0067 if(rule.childrenRules?.length) {
0068 // Invoke first children rules
0069 editGeoNodes(node, rule.childrenRules, rule.childrenRulesMaxLevel ?? Infinity);
0070 }
0071
0072 // Remove this geo node
0073 if(rule.action === EditActions.Remove) {
0074 removeGeoNode(node);
0075 return false; // Don't go through children
0076 }
0077
0078 // Remove all daughters
0079 if(rule.action === EditActions.RemoveChildren) {
0080 removeChildren(node);
0081 return false; // don't process children
0082 }
0083
0084 // (!) All next actions may need to process children
0085 if(rule.action === EditActions.RemoveSiblings || rule.action === EditActions.RemoveBySubLevel) {
0086 // Add a node to matches to process them after
0087 postponedProcessing.push({ node: node, fullPath: nodeFullPath, rule: rule });
0088 }
0089
0090 if(rule.action === EditActions.SetGeoBit){
0091 if(rule.geoBit !== undefined) {
0092 setGeoBit(node.fVolume, rule.geoBit, 1);
0093 }
0094 }
0095 if(rule.action === EditActions.UnsetGeoBit){
0096 if(rule.geoBit !== undefined) {
0097 setGeoBit(node.fVolume, rule.geoBit, 0);
0098 }
0099 }
0100 if(rule.action === EditActions.ToggleGeoBit){
0101 if(rule.geoBit !== undefined) {
0102 toggleGeoBit(node.fVolume, rule.geoBit);
0103 }
0104 }
0105 }
0106 }
0107 return true; // Just continue
0108 };
0109
0110 // Use walkGeoNodes with the collecting callback and the pattern
0111 walkGeoNodes(topNode, collectNodes, maxLevel);
0112
0113 // Now we process nodes that we can't process on fly
0114 for(let item of postponedProcessing) {
0115 let node = item.node;
0116 let fullPath = node.fullPath;
0117 let rule:GeoNodeEditRule = item.rule;
0118 let motherVolume = item.node.fMother
0119 let siblings = motherVolume?.fNodes?.arr
0120
0121 // Remove siblings but keep this one
0122 if(rule.action == EditActions.RemoveSiblings) {
0123 if (siblings) {
0124 motherVolume.fNodes.arr = [node]
0125 }
0126 else
0127 {
0128 console.log(`Can't get an array for: ${node} at ${fullPath}`);
0129 }
0130 }
0131
0132 // Remove daughters by sublevels
0133 if(rule.action == EditActions.RemoveBySubLevel) {
0134 let pruneSubNodes = getGeoNodesByLevel(node, rule.pruneSubLevel);
0135 for (const pruneSubNodeItem of pruneSubNodes) {
0136 removeGeoNode(pruneSubNodeItem.geoNode);
0137 }
0138 }
0139 }
0140
0141 return postponedProcessing;
0142 }
0143
0144
0145 /**
0146 * Removes a node from its mother volume.
0147 *
0148 * @param {any} node - The node to be removed.
0149 */
0150 export function removeGeoNode(node: any): void {
0151 let motherVolume = node.fMother
0152 let siblings = motherVolume?.fNodes?.arr
0153 if (siblings) {
0154 const index = siblings.indexOf(node);
0155 if (index !== -1) { // Check if the item was found
0156 siblings.splice(index, 1); // Remove the item
0157 } else {
0158 console.warn(`Item ${node} not found in array???`);
0159 }
0160 } else {
0161 console.warn(`Can't get siblings of ${node}`);
0162 }
0163 }
0164
0165 /**
0166 * Removes all child nodes from the given node.
0167 *
0168 * @param {any} node - The node from which to remove the child nodes.
0169 */
0170 export function removeChildren(node: any): void {
0171 let daughters = node.fVolume?.fNodes?.arr;
0172
0173 if (daughters) {
0174 node.fVolume.fNodes.arr = []
0175 } else {
0176 console.log(`Can't get child nodes of ${node}`);
0177 }
0178 }