From 5bc47d02cb42dd90cfbc7d2fe604bb754406f9a1 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Tue, 18 Oct 2022 16:16:30 +0200 Subject: [PATCH] Refactor InitializeChildrenWithPattern --- src/Components/Editor/Actions/AddContainer.ts | 196 +++++++++++++----- 1 file changed, 143 insertions(+), 53 deletions(-) diff --git a/src/Components/Editor/Actions/AddContainer.ts b/src/Components/Editor/Actions/AddContainer.ts index 5258bf6..227b73a 100644 --- a/src/Components/Editor/Actions/AddContainer.ts +++ b/src/Components/Editor/Actions/AddContainer.ts @@ -10,7 +10,7 @@ import { IHistoryState } from '../../../Interfaces/IHistoryState'; import { IPattern, GetPattern, ContainerOrPattern } from '../../../Interfaces/IPattern'; import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; import { Orientation } from '../../../Enums/Orientation'; -import { GetDefaultContainerProps, DEFAULTCHILDTYPE_MAX_DEPTH, DEFAULTCHILDTYPE_ALLOW_CYCLIC } from '../../../utils/default'; +import { GetDefaultContainerProps } from '../../../utils/default'; import { FindContainerById } from '../../../utils/itertools'; import { ApplyMargin } from '../../../utils/svg'; import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors'; @@ -301,9 +301,10 @@ function InitializeChildrenWithPattern( const configs: Map = new Map(configuration.AvailableContainers.map(config => [config.Type, config])); const patterns: Map = new Map(configuration.Patterns.map(pattern => [pattern.id, pattern])); const containerOrPattern = GetPattern(patternId, configs, patterns); - const pattern = containerOrPattern as IPattern; + const pattern = containerOrPattern as IPattern | IAvailableContainer; - if (pattern.children === undefined) { + if (!('children' in pattern)) { + // containerOrPattern is not a pattern but a container const container = containerOrPattern as IAvailableContainer; // Add Container AddNewContainerToParent( @@ -315,11 +316,38 @@ function InitializeChildrenWithPattern( newCounters, symbols ); + return; } // BFS over patterns + BuildPatterns(pattern, newContainer, configuration, containers, newCounters, symbols, configs, patterns); +} + +/** + * Apply the BFS algorithm to build containers from given patterns + * from the top to the bottom + * + * @param pattern + * @param newContainer + * @param configuration + * @param containers + * @param newCounters + * @param symbols + * @param configs + * @param patterns + */ +function BuildPatterns( + rootPattern: IPattern, + newContainer: ContainerModel, + configuration: IConfiguration, + containers: Map, + newCounters: Record, + symbols: Map, + configs: Map, + patterns: Map +): void { const rootNode: Node = { - containerOrPattern: pattern, + containerOrPattern: rootPattern, parent: newContainer }; @@ -330,69 +358,131 @@ function InitializeChildrenWithPattern( while (levelSize-- !== 0) { const node = queue.shift() as Node; - const pattern = node.containerOrPattern as IPattern; + const newParent = AddContainerInLevel(node, maxLevelSize, levelSize, configuration, containers, newCounters, symbols, configs); - if (pattern.children === undefined) { - // Add Container - const containerConfig = node.containerOrPattern as IAvailableContainer; - const index = maxLevelSize - levelSize; - AddNewContainerToParent( - containerConfig, - configuration, - containers, - node.parent, - index, 0, - newCounters, - symbols - ); + if (newParent === undefined) { + // node.pattern is not a IPattern, there is no children to iterate continue; } - let parent = node.parent; - if (pattern.wrapper !== undefined) { - // Add Container - const container = configs.get(pattern.wrapper); - if (container === undefined) { - console.warn(`[InitializeChildrenFromPattern] IAvailableContainer from pattern was not found in the configuration: ${pattern.wrapper}. - Process will ignore the container.`); - } else { - const newChildContainer = AddNewContainerToParent( - container, - configuration, - containers, - parent, - 0, 0, - newCounters, - symbols, - undefined, - false - ); + for (let i = newParent.pattern.children.length - 1; i >= 0; i--) { + const nextNode = GetNextNode(newParent.parent, newParent.pattern, i, configs, patterns); - // iterate - parent = newChildContainer; - } - } - - for (let i = pattern.children.length - 1; i >= 0; i--) { - const childId: string = pattern.children[i]; - - const child = GetPattern(childId, configs, patterns); - - if (child === undefined) { + if (nextNode === undefined) { continue; } - const nextNode: Node = { - containerOrPattern: child, - parent - }; - queue.push(nextNode); } } } } +/** + * Add a new container in the parent if node.pattern is a Pattern. + * Then, return the next parent to iterate with a pattern/container. + * Otherwise, if node.pattern is a IAvailableContainer, + * create the container from node.pattern and return undefined. + * + * @param node + * @param maxLevelSize + * @param levelSize + * @param configuration + * @param containers + * @param newCounters + * @param symbols + * @param configs + * @returns + */ +function AddContainerInLevel( + node: Node, + maxLevelSize: number, + levelSize: number, + configuration: IConfiguration, + containers: Map, + newCounters: Record, + symbols: Map, + configs: Map +): { parent: IContainerModel, pattern: IPattern } | undefined { + if (!('children' in node.containerOrPattern)) { + // Add Container from pattern + const containerConfig: IAvailableContainer = node.containerOrPattern; + const index = maxLevelSize - levelSize; + AddNewContainerToParent( + containerConfig, + configuration, + containers, + node.parent, + index, 0, + newCounters, + symbols + ); + return; + } + + const pattern: IPattern = node.containerOrPattern; + const parent = node.parent; + + if (pattern.wrapper === undefined) { + return { parent, pattern }; + } + + // Add Container from wrapper + // and set the new parent as the child of this parent + const container = configs.get(pattern.wrapper); + if (container === undefined) { + console.warn(`[InitializeChildrenFromPattern] IAvailableContainer from pattern was not found in the configuration: ${pattern.wrapper}. + Process will ignore the container.`); + return { parent, pattern }; + } + + const newChildContainer = AddNewContainerToParent( + container, + configuration, + containers, + parent, + 0, 0, + newCounters, + symbols, + undefined, + false + ); + + // change the parent to be the child of the wrapper + return { parent: newChildContainer, pattern }; +} + +/** + * Return the next node from the given pattern from the configs + * + * @param parent + * @param pattern + * @param i + * @param configs + * @param patterns + * @returns {Node} The next node + */ +function GetNextNode( + parent: IContainerModel, + pattern: IPattern, + i: number, + configs: Map, + patterns: Map +): Node | undefined { + const childId: string = pattern.children[i]; + + const child = GetPattern(childId, configs, patterns); + + if (child === undefined) { + return undefined; + } + + return { + containerOrPattern: child, + parent + }; +} + interface Node { containerOrPattern: ContainerOrPattern parent: IContainerModel