Refactor InitializeChildrenWithPattern

This commit is contained in:
Eric NGUYEN 2022-10-18 16:16:30 +02:00
parent 5acc57cf7f
commit 5bc47d02cb

View file

@ -10,7 +10,7 @@ import { IHistoryState } from '../../../Interfaces/IHistoryState';
import { IPattern, GetPattern, ContainerOrPattern } from '../../../Interfaces/IPattern'; import { IPattern, GetPattern, ContainerOrPattern } from '../../../Interfaces/IPattern';
import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; import { ISymbolModel } from '../../../Interfaces/ISymbolModel';
import { Orientation } from '../../../Enums/Orientation'; 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 { FindContainerById } from '../../../utils/itertools';
import { ApplyMargin } from '../../../utils/svg'; import { ApplyMargin } from '../../../utils/svg';
import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors'; import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
@ -301,9 +301,10 @@ function InitializeChildrenWithPattern(
const configs: Map<string, IAvailableContainer> = new Map(configuration.AvailableContainers.map(config => [config.Type, config])); const configs: Map<string, IAvailableContainer> = new Map(configuration.AvailableContainers.map(config => [config.Type, config]));
const patterns: Map<string, IPattern> = new Map(configuration.Patterns.map(pattern => [pattern.id, pattern])); const patterns: Map<string, IPattern> = new Map(configuration.Patterns.map(pattern => [pattern.id, pattern]));
const containerOrPattern = GetPattern(patternId, configs, patterns); 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; const container = containerOrPattern as IAvailableContainer;
// Add Container // Add Container
AddNewContainerToParent( AddNewContainerToParent(
@ -315,11 +316,38 @@ function InitializeChildrenWithPattern(
newCounters, newCounters,
symbols symbols
); );
return;
} }
// BFS over patterns // 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<string, IContainerModel>,
newCounters: Record<string, number>,
symbols: Map<string, ISymbolModel>,
configs: Map<string, IAvailableContainer>,
patterns: Map<string, IPattern>
): void {
const rootNode: Node = { const rootNode: Node = {
containerOrPattern: pattern, containerOrPattern: rootPattern,
parent: newContainer parent: newContainer
}; };
@ -330,69 +358,131 @@ function InitializeChildrenWithPattern(
while (levelSize-- !== 0) { while (levelSize-- !== 0) {
const node = queue.shift() as Node; 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) { if (newParent === undefined) {
// Add Container // node.pattern is not a IPattern, there is no children to iterate
const containerConfig = node.containerOrPattern as IAvailableContainer;
const index = maxLevelSize - levelSize;
AddNewContainerToParent(
containerConfig,
configuration,
containers,
node.parent,
index, 0,
newCounters,
symbols
);
continue; continue;
} }
let parent = node.parent; for (let i = newParent.pattern.children.length - 1; i >= 0; i--) {
if (pattern.wrapper !== undefined) { const nextNode = GetNextNode(newParent.parent, newParent.pattern, i, configs, patterns);
// 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
);
// iterate if (nextNode === undefined) {
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) {
continue; continue;
} }
const nextNode: Node = {
containerOrPattern: child,
parent
};
queue.push(nextNode); 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<string, IContainerModel>,
newCounters: Record<string, number>,
symbols: Map<string, ISymbolModel>,
configs: Map<string, IAvailableContainer>
): { 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<string, IAvailableContainer>,
patterns: Map<string, IPattern>
): 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 { interface Node {
containerOrPattern: ContainerOrPattern containerOrPattern: ContainerOrPattern
parent: IContainerModel parent: IContainerModel