Merged PR 175: Implement drag drop
- [x] Implement drag drop to create an element at a specific index - Add Swap behavrior - Implement max contraints with simplex ~~- [ ] Implement drag drop to swap two container that flex~~ - Fixes tries number for simplex it can now go up to 2 * number of containers - Fixes flex calling another flex behavior when not needed (remember that flex behavior is the only behavior that needs to communicate with siblings) - Fix max width being ignored in input group
This commit is contained in:
parent
4d4ecd67d0
commit
353f461f4b
13 changed files with 220 additions and 59 deletions
|
@ -119,6 +119,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
|||
inputClassName=''
|
||||
type='number'
|
||||
min={props.properties.minWidth}
|
||||
max={props.properties.maxWidth}
|
||||
value={(RemoveWidthMargin(props.properties.width, props.properties.margin.left, props.properties.margin.right)).toString()}
|
||||
onChange={(event) => props.onChange('width', ApplyWidthMargin(Number(event.target.value), props.properties.margin.left, props.properties.margin.right))}
|
||||
isDisabled={props.properties.isFlex} />
|
||||
|
|
|
@ -6,7 +6,7 @@ import { GetCurrentHistory, UpdateCounters } from '../Editor';
|
|||
import { AddMethod } from '../../../Enums/AddMethod';
|
||||
import { IAvailableContainer } from '../../../Interfaces/IAvailableContainer';
|
||||
import { GetDefaultContainerProps, DEFAULTCHILDTYPE_ALLOW_CYCLIC, DEFAULTCHILDTYPE_MAX_DEPTH } from '../../../utils/default';
|
||||
import { ApplyBehaviors, ApplyBehaviorsOnSiblings } from '../Behaviors/Behaviors';
|
||||
import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
|
||||
import { ISymbolModel } from '../../../Interfaces/ISymbolModel';
|
||||
import Swal from 'sweetalert2';
|
||||
import { ApplyMargin, TransformX } from '../../../utils/svg';
|
||||
|
@ -83,7 +83,7 @@ export function DeleteContainer(
|
|||
throw new Error('[DeleteContainer] Could not find container among parent\'s children');
|
||||
}
|
||||
|
||||
ApplyBehaviorsOnSiblings(container, current.symbols);
|
||||
ApplyBehaviorsOnSiblingsChildren(container, current.symbols);
|
||||
|
||||
// Select the previous container
|
||||
// or select the one above
|
||||
|
@ -285,7 +285,7 @@ export function AddContainers(
|
|||
ApplyBehaviors(newContainer, current.symbols);
|
||||
|
||||
// Then, apply the behaviors on its siblings (mostly for flex)
|
||||
ApplyBehaviorsOnSiblings(newContainer, current.symbols);
|
||||
ApplyBehaviorsOnSiblingsChildren(newContainer, current.symbols);
|
||||
|
||||
// Sort the parent children by x
|
||||
UpdateParentChildrenList(parentClone);
|
||||
|
@ -547,7 +547,7 @@ function SetContainer(
|
|||
ApplyBehaviors(container, symbols);
|
||||
|
||||
// Apply special behaviors on siblings
|
||||
ApplyBehaviorsOnSiblings(container, symbols);
|
||||
ApplyBehaviorsOnSiblingsChildren(container, symbols);
|
||||
|
||||
// sort the children list by their position
|
||||
UpdateParentChildrenList(container.parent);
|
||||
|
|
|
@ -5,7 +5,7 @@ import { ISymbolModel } from '../../../Interfaces/ISymbolModel';
|
|||
import { GetDefaultSymbolModel } from '../../../utils/default';
|
||||
import { FindContainerById } from '../../../utils/itertools';
|
||||
import { RestoreX } from '../../../utils/svg';
|
||||
import { ApplyBehaviors, ApplyBehaviorsOnSiblings } from '../Behaviors/Behaviors';
|
||||
import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
|
||||
import { GetCurrentHistory, UpdateCounters } from '../Editor';
|
||||
|
||||
export function AddSymbol(
|
||||
|
@ -150,7 +150,7 @@ export function OnPropertyChange(
|
|||
|
||||
ApplyBehaviors(container, newSymbols);
|
||||
|
||||
ApplyBehaviorsOnSiblings(container, newSymbols);
|
||||
ApplyBehaviorsOnSiblingsChildren(container, newSymbols);
|
||||
});
|
||||
|
||||
history.push({
|
||||
|
|
|
@ -44,7 +44,7 @@ export function ApplyAnchor(container: IContainerModel): IContainerModel {
|
|||
* @param containers A list of containers
|
||||
* @returns A list of overlapping containers
|
||||
*/
|
||||
function GetOverlappingContainers(
|
||||
export function GetOverlappingContainers(
|
||||
container: IContainerModel,
|
||||
containers: IContainerModel[]
|
||||
): IContainerModel[] {
|
||||
|
|
|
@ -4,6 +4,7 @@ import { APPLY_BEHAVIORS_ON_CHILDREN } from '../../../utils/default';
|
|||
import { ApplyAnchor } from './AnchorBehaviors';
|
||||
import { Flex } from './FlexBehaviors';
|
||||
import { ApplyRigidBody } from './RigidBodyBehaviors';
|
||||
import { ApplySwap } from './SwapBehaviors';
|
||||
import { ApplySymbol } from './SymbolBehaviors';
|
||||
|
||||
/**
|
||||
|
@ -13,7 +14,6 @@ import { ApplySymbol } from './SymbolBehaviors';
|
|||
* @returns Updated container
|
||||
*/
|
||||
export function ApplyBehaviors(container: IContainerModel, symbols: Map<string, ISymbolModel>): IContainerModel {
|
||||
try {
|
||||
const symbol = symbols.get(container.properties.linkedSymbolId);
|
||||
if (container.properties.linkedSymbolId !== '' && symbol !== undefined) {
|
||||
ApplySymbol(container, symbol);
|
||||
|
@ -23,6 +23,8 @@ export function ApplyBehaviors(container: IContainerModel, symbols: Map<string,
|
|||
ApplyAnchor(container);
|
||||
}
|
||||
|
||||
ApplySwap(container);
|
||||
|
||||
Flex(container);
|
||||
|
||||
ApplyRigidBody(container);
|
||||
|
@ -33,9 +35,6 @@ export function ApplyBehaviors(container: IContainerModel, symbols: Map<string,
|
|||
ApplyBehaviors(child, symbols);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.debug(error);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
@ -46,7 +45,7 @@ export function ApplyBehaviors(container: IContainerModel, symbols: Map<string,
|
|||
* @param symbols
|
||||
* @returns
|
||||
*/
|
||||
export function ApplyBehaviorsOnSiblings(newContainer: IContainerModel, symbols: Map<string, ISymbolModel>): void {
|
||||
export function ApplyBehaviorsOnSiblingsChildren(newContainer: IContainerModel, symbols: Map<string, ISymbolModel>): void {
|
||||
if (newContainer.parent === null || newContainer.parent === undefined) {
|
||||
return;
|
||||
}
|
||||
|
@ -57,6 +56,8 @@ export function ApplyBehaviorsOnSiblings(newContainer: IContainerModel, symbols:
|
|||
return;
|
||||
}
|
||||
|
||||
ApplyBehaviors(container, symbols);
|
||||
for (const child of container.children) {
|
||||
ApplyBehaviors(child, symbols);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Swal from 'sweetalert2';
|
||||
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||
import { Simplex } from '../../../utils/simplex';
|
||||
import { ApplyWidthMargin, ApplyXMargin } from '../../../utils/svg';
|
||||
|
@ -49,16 +50,16 @@ function FlexGroup(flexibleGroup: IFlexibleGroup): void {
|
|||
|
||||
const checkSumMinWidthsIsFitting = minimumPossibleWidth > requiredMaxWidth;
|
||||
if (checkSumMinWidthsIsFitting) {
|
||||
// Swal.fire({
|
||||
// icon: 'error',
|
||||
// title: 'Cannot fit!',
|
||||
// text: 'Cannot fit at all even when squeezing all flex containers to the minimum.'
|
||||
// });
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Cannot fit!',
|
||||
text: 'Cannot fit at all even when squeezing all flex containers to the minimum.'
|
||||
});
|
||||
throw new Error('[FlexBehavior] Cannot fit at all even when squeezing all flex containers to the minimum.');
|
||||
}
|
||||
|
||||
const maxMinWidths = Math.max(...minWidths);
|
||||
if (maxMinWidths * minWidths.length < requiredMaxWidth) {
|
||||
if (maxMinWidths * minWidths.length <= requiredMaxWidth) {
|
||||
const wantedWidth = requiredMaxWidth / minWidths.length;
|
||||
// it fits, flex with maxMinWidths and fixed width
|
||||
let right = flexibleGroup.offset;
|
||||
|
@ -79,7 +80,9 @@ function FlexGroup(flexibleGroup: IFlexibleGroup): void {
|
|||
// does not fit
|
||||
|
||||
/// SIMPLEX ///
|
||||
const solutions: number[] = Simplex(minWidths, requiredMaxWidth);
|
||||
const maxWidths = flexibleContainers
|
||||
.map(sibling => sibling.properties.maxWidth);
|
||||
const solutions: number[] = Simplex(minWidths, maxWidths, requiredMaxWidth);
|
||||
|
||||
// apply the solutions
|
||||
for (let i = 0; i < flexibleContainers.length; i++) {
|
||||
|
|
31
src/Components/Editor/Behaviors/SwapBehaviors.ts
Normal file
31
src/Components/Editor/Behaviors/SwapBehaviors.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Swap two flex container when one is overlapping another
|
||||
*/
|
||||
|
||||
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||
import { GetOverlappingContainers } from './AnchorBehaviors';
|
||||
|
||||
export function ApplySwap(container: IContainerModel): void {
|
||||
if (container.parent === null || container.parent === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const children = container.parent.children;
|
||||
const overlappingContainers = GetOverlappingContainers(container, children);
|
||||
|
||||
if (overlappingContainers.length > 1 || overlappingContainers.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const overlappingContainer = overlappingContainers.pop();
|
||||
|
||||
if (overlappingContainer === null || overlappingContainer === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// swap positions
|
||||
[overlappingContainer.properties.x, container.properties.x] = [container.properties.x, overlappingContainer.properties.x];
|
||||
const indexContainer = children.indexOf(container);
|
||||
const indexOverlapping = children.indexOf(overlappingContainer);
|
||||
[children[indexContainer], children[indexOverlapping]] = [children[indexOverlapping], children[indexContainer]];
|
||||
}
|
|
@ -4,7 +4,7 @@ import { IConfiguration } from '../../Interfaces/IConfiguration';
|
|||
import { SVG } from '../SVG/SVG';
|
||||
import { IHistoryState } from '../../Interfaces/IHistoryState';
|
||||
import { UI } from '../UI/UI';
|
||||
import { SelectContainer, DeleteContainer, AddContainerToSelectedContainer, OnPropertyChange, AddContainers } from './Actions/ContainerOperations';
|
||||
import { SelectContainer, DeleteContainer, AddContainerToSelectedContainer, OnPropertyChange, AddContainer } from './Actions/ContainerOperations';
|
||||
import { SaveEditorAsJSON, SaveEditorAsSVG } from './Actions/Save';
|
||||
import { OnKey } from './Actions/Shortcuts';
|
||||
import { events as EVENTS } from '../../Events/EditorEvents';
|
||||
|
@ -240,6 +240,16 @@ export function Editor(props: IEditorProps): JSX.Element {
|
|||
setNewHistory(newHistory);
|
||||
}
|
||||
}}
|
||||
addContainerAt={(index, type, parent) => setNewHistory(
|
||||
AddContainer(
|
||||
index,
|
||||
type,
|
||||
parent,
|
||||
configuration,
|
||||
history,
|
||||
historyCurrentStep
|
||||
)
|
||||
)}
|
||||
addSymbol={(type) => setNewHistory(
|
||||
AddSymbol(
|
||||
type,
|
||||
|
|
|
@ -22,6 +22,7 @@ describe.concurrent('Elements sidebar', () => {
|
|||
selectedContainer={undefined}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={() => {}}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect(screen.getByText(/Elements/i));
|
||||
|
@ -45,6 +46,7 @@ describe.concurrent('Elements sidebar', () => {
|
|||
selectedContainer={mainContainer}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={() => {}}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect(screen.getByText(/Elements/i));
|
||||
|
@ -149,6 +151,7 @@ describe.concurrent('Elements sidebar', () => {
|
|||
selectedContainer={mainContainer}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={() => {}}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect(screen.getByText(/Elements/i));
|
||||
|
@ -208,6 +211,7 @@ describe.concurrent('Elements sidebar', () => {
|
|||
selectedContainer={selectedContainer}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={selectContainer}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect(screen.getByText(/Elements/i));
|
||||
|
@ -230,6 +234,7 @@ describe.concurrent('Elements sidebar', () => {
|
|||
selectedContainer={selectedContainer}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={selectContainer}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect((propertyId as HTMLInputElement).value === 'main').toBeFalsy();
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as React from 'react';
|
|||
import { FixedSizeList as List } from 'react-window';
|
||||
import { Properties } from '../ContainerProperties/ContainerProperties';
|
||||
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
||||
import { GetDepth, MakeIterator } from '../../utils/itertools';
|
||||
import { FindContainerById, GetDepth, MakeIterator } from '../../utils/itertools';
|
||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
||||
import { PropertyType } from '../../Enums/PropertyType';
|
||||
|
||||
|
@ -18,6 +18,102 @@ interface IElementsSidebarProps {
|
|||
type?: PropertyType
|
||||
) => void
|
||||
selectContainer: (containerId: string) => void
|
||||
addContainer: (index: number, type: string, parent: string) => void
|
||||
}
|
||||
|
||||
function RemoveBorderClasses(target: HTMLButtonElement, exception: string = ''): void {
|
||||
const bordersClasses = ['border-t-8', 'border-8', 'border-b-8'].filter(className => className !== exception);
|
||||
target.classList.remove(...bordersClasses);
|
||||
}
|
||||
|
||||
function HandleDragLeave(event: React.DragEvent): void {
|
||||
const target: HTMLButtonElement = event.target as HTMLButtonElement;
|
||||
RemoveBorderClasses(target);
|
||||
}
|
||||
|
||||
function HandleDragOver(
|
||||
event: React.DragEvent,
|
||||
mainContainer: IContainerModel
|
||||
): void {
|
||||
event.preventDefault();
|
||||
const target: HTMLButtonElement = event.target as HTMLButtonElement;
|
||||
const rect = target.getBoundingClientRect();
|
||||
const y = event.clientY - rect.top; // y position within the element.
|
||||
|
||||
if (target.id === mainContainer.properties.id) {
|
||||
target.classList.add('border-8');
|
||||
return;
|
||||
}
|
||||
|
||||
if (y < 12) {
|
||||
RemoveBorderClasses(target, 'border-t-8');
|
||||
target.classList.add('border-t-8');
|
||||
} else if (y < 24) {
|
||||
RemoveBorderClasses(target, 'border-8');
|
||||
target.classList.add('border-8');
|
||||
} else {
|
||||
RemoveBorderClasses(target, 'border-b-8');
|
||||
target.classList.add('border-b-8');
|
||||
}
|
||||
}
|
||||
|
||||
function HandleOnDrop(
|
||||
event: React.DragEvent,
|
||||
mainContainer: IContainerModel,
|
||||
addContainer: (index: number, type: string, parent: string) => void
|
||||
): void {
|
||||
event.preventDefault();
|
||||
const type = event.dataTransfer.getData('type');
|
||||
const target: HTMLButtonElement = event.target as HTMLButtonElement;
|
||||
RemoveBorderClasses(target);
|
||||
|
||||
const targetContainer: IContainerModel | undefined = FindContainerById(
|
||||
mainContainer,
|
||||
target.id
|
||||
);
|
||||
|
||||
if (targetContainer === undefined) {
|
||||
throw new Error('[handleOnDrop] Tried to drop onto a unknown container!');
|
||||
}
|
||||
|
||||
if (targetContainer === mainContainer) {
|
||||
// if the container is the root, only add type as child
|
||||
addContainer(
|
||||
targetContainer.children.length,
|
||||
type,
|
||||
targetContainer.properties.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetContainer.parent === null ||
|
||||
targetContainer.parent === undefined) {
|
||||
throw new Error('[handleDrop] Tried to drop into a child container without a parent!');
|
||||
}
|
||||
|
||||
const rect = target.getBoundingClientRect();
|
||||
const y = event.clientY - rect.top; // y position within the element.
|
||||
|
||||
// locate the hitboxes
|
||||
if (y < 12) {
|
||||
const index = targetContainer.parent.children.indexOf(targetContainer);
|
||||
addContainer(
|
||||
index,
|
||||
type,
|
||||
targetContainer.parent.properties.id
|
||||
);
|
||||
} else if (y < 24) {
|
||||
addContainer(
|
||||
targetContainer.children.length,
|
||||
type,
|
||||
targetContainer.properties.id);
|
||||
} else {
|
||||
const index = targetContainer.parent.children.indexOf(targetContainer);
|
||||
addContainer(
|
||||
index + 1,
|
||||
type,
|
||||
targetContainer.parent.properties.id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function ElementsSidebar(props: IElementsSidebarProps): JSX.Element {
|
||||
|
@ -55,6 +151,9 @@ export function ElementsSidebar(props: IElementsSidebarProps): JSX.Element {
|
|||
key={key}
|
||||
style={style}
|
||||
onClick={() => props.selectContainer(container.properties.id)}
|
||||
onDrop={(event) => HandleOnDrop(event, props.mainContainer, props.addContainer)}
|
||||
onDragOver={(event) => HandleDragOver(event, props.mainContainer)}
|
||||
onDragLeave={(event) => HandleDragLeave(event)}
|
||||
>
|
||||
{text}
|
||||
</button>
|
||||
|
|
|
@ -12,6 +12,7 @@ interface IInputGroupProps {
|
|||
defaultValue?: string
|
||||
defaultChecked?: boolean
|
||||
min?: number
|
||||
max?: number
|
||||
isDisabled?: boolean
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||
}
|
||||
|
@ -44,6 +45,7 @@ export function InputGroup(props: IInputGroupProps): JSX.Element {
|
|||
defaultChecked={props.defaultChecked}
|
||||
onChange={props.onChange}
|
||||
min={props.min}
|
||||
max={props.max}
|
||||
disabled={props.isDisabled} />
|
||||
</>;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ interface IUIProps {
|
|||
deleteContainer: (containerId: string) => void
|
||||
onPropertyChange: (key: string, value: string | number | boolean, type?: PropertyType) => void
|
||||
addContainer: (type: string) => void
|
||||
addContainerAt: (index: number, type: string, parent: string) => void
|
||||
addSymbol: (type: string) => void
|
||||
onSymbolPropertyChange: (key: string, value: string | number | boolean) => void
|
||||
selectSymbol: (symbolId: string) => void
|
||||
|
@ -87,6 +88,7 @@ export function UI(props: IUIProps): JSX.Element {
|
|||
isHistoryOpen={isHistoryOpen}
|
||||
onPropertyChange={props.onPropertyChange}
|
||||
selectContainer={props.selectContainer}
|
||||
addContainer={props.addContainerAt}
|
||||
/>
|
||||
<SymbolsSidebar
|
||||
selectedSymbolId={props.current.selectedSymbolId}
|
||||
|
|
|
@ -17,20 +17,22 @@
|
|||
* @param requiredMaxWidth
|
||||
* @returns
|
||||
*/
|
||||
export function Simplex(minWidths: number[], requiredMaxWidth: number): number[] {
|
||||
export function Simplex(minWidths: number[], maxWidths: number[], requiredMaxWidth: number): number[] {
|
||||
/// 1) standardized the equations
|
||||
// add the min widths constraints
|
||||
const constraints = minWidths.map(minWidth => minWidth * -1);
|
||||
|
||||
// add the max widths constraint
|
||||
constraints.push(requiredMaxWidth);
|
||||
|
||||
/// 2) Create the initial matrix
|
||||
// get row length (nVariables + nConstraints + 1 (z) + 1 (b))
|
||||
const nVariables = minWidths.length;
|
||||
const nConstraints = constraints.length;
|
||||
const rowlength = nVariables + nConstraints + 2;
|
||||
const matrix = GetInitialMatrix(constraints, rowlength, nVariables);
|
||||
const rowlength =
|
||||
minWidths.length + // min constraints
|
||||
maxWidths.length + // max constraints
|
||||
nConstraints + 1 + // slack variables
|
||||
1 + // z
|
||||
1; // b
|
||||
const matrix = GetInitialMatrix(constraints, maxWidths, requiredMaxWidth, rowlength);
|
||||
|
||||
/// Apply the algorithm
|
||||
const finalMatrix = ApplyMainLoop(matrix, rowlength);
|
||||
|
@ -40,32 +42,35 @@ export function Simplex(minWidths: number[], requiredMaxWidth: number): number[]
|
|||
return solutions;
|
||||
}
|
||||
|
||||
const MAX_TRIES = 10;
|
||||
|
||||
/**
|
||||
* Specific to min widths algorithm
|
||||
* Get the initial matrix from the maximum constraints
|
||||
* and the number of variables
|
||||
* @param maximumConstraints
|
||||
* @param minConstraints
|
||||
* @param rowlength
|
||||
* @param nVariables
|
||||
* @returns
|
||||
*/
|
||||
function GetInitialMatrix(
|
||||
maximumConstraints: number[],
|
||||
rowlength: number,
|
||||
nVariables: number
|
||||
minConstraints: number[],
|
||||
maxConstraints: number[],
|
||||
objectiveConstraint: number,
|
||||
rowlength: number
|
||||
): number[][] {
|
||||
const nConstraints = maximumConstraints.length;
|
||||
const matrix = maximumConstraints.map((maximumConstraint, index) => {
|
||||
const nVariables = maxConstraints.length;
|
||||
const constraints = minConstraints.concat(maxConstraints);
|
||||
constraints.push(objectiveConstraint);
|
||||
const matrix = constraints.map((constraint, index) => {
|
||||
const row: number[] = Array(rowlength).fill(0);
|
||||
|
||||
// insert the variable coefficient a of a*x
|
||||
if (index <= nConstraints - 2) {
|
||||
// insert the the variable coefficient of the minimum widths constraints (negative identity matrix)
|
||||
if (index < nVariables) {
|
||||
// insert the the variable coefficient of the minimum/maximum widths constraints (negative identity matrix)
|
||||
row[index] = -1;
|
||||
} else if (index < (2 * nVariables)) {
|
||||
row[index - (nVariables)] = 1;
|
||||
} else {
|
||||
// insert the the variable coefficient of the maximum width constraint
|
||||
// insert the the variable coefficient of the maximum desired width constraint
|
||||
row.fill(1, 0, nVariables);
|
||||
}
|
||||
|
||||
|
@ -73,7 +78,7 @@ function GetInitialMatrix(
|
|||
row[index + nVariables] = 1;
|
||||
|
||||
// insert the constraint coefficient (b)
|
||||
row[rowlength - 1] = maximumConstraint;
|
||||
row[rowlength - 1] = constraint;
|
||||
return row;
|
||||
});
|
||||
|
||||
|
@ -119,7 +124,8 @@ function GetAllIndexes(arr: number[], val: number): number[] {
|
|||
*/
|
||||
function ApplyMainLoop(oldMatrix: number[][], rowlength: number): number[][] {
|
||||
let matrix = oldMatrix;
|
||||
let tries = MAX_TRIES;
|
||||
const maxTries = oldMatrix.length * 2;
|
||||
let tries = maxTries;
|
||||
const indexesTried: Record<number, number> = {};
|
||||
while (matrix[matrix.length - 1].some((v: number) => v < 0) && tries > 0) {
|
||||
// 1) find the index with smallest coefficient (O(n)+)
|
||||
|
@ -183,9 +189,10 @@ function ApplyMainLoop(oldMatrix: number[][], rowlength: number): number[][] {
|
|||
}
|
||||
|
||||
if (tries === 0) {
|
||||
console.table(matrix);
|
||||
throw new Error('[Flex] Simplexe: Could not find a solution');
|
||||
}
|
||||
|
||||
console.debug(`Simplex was solved in ${maxTries - tries} tries`);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue