# domain/converters/learning.route.converter.ts

> 35 lines of code and 11 definitions.

Tree: Bane's Lab Site
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/tree#file-domain-converters-learning-route-converter-ts
Source text: https://banes-lab.com/source/tree/domain/converters/learning.route.converter.ts.txt

Listed in [domain/converters](https://banes-lab.com/api/source/tree/domain/converters.md), after [domain/converters/learning.grid.converter.ts](https://banes-lab.com/source/tree/domain/converters/learning.grid.converter.ts.md) and before [domain/converters/lexicon.converter.ts](https://banes-lab.com/source/tree/domain/converters/lexicon.converter.ts.md).

## Definitions

- `isSpur` (lexical_declaration, line 15)
- `turnsBack` (lexical_declaration, line 8)
- `unfold` (lexical_declaration, line 24, exported)
- `RailStop` (interface_declaration, line 3)
- `upright` (lexical_declaration, line 9)
- `level` (lexical_declaration, line 10)
- `along` (lexical_declaration, line 11)
- `[before, here, after]` (lexical_declaration, line 16)
- `atStop` (lexical_declaration, line 20)
- `held` (lexical_declaration, line 28, exported)
- `index` (lexical_declaration, line 29, exported)

## Contained in

- [domain/converters](https://banes-lab.com/anatomy/tree/folder-domain-converters.md)

## Linked from

- [domain/converters](https://banes-lab.com/anatomy/tree/folder-domain-converters.md)

## Source

```typescript
import type { LearningPoint } from "#types/learning.types";

interface RailStop {
    readonly cx: number;
    readonly cy: number;
}

const turnsBack = function turnsBack(before: LearningPoint, here: LearningPoint, after: LearningPoint): boolean {
    const upright = before.x === here.x && here.x === after.x;
    const level = before.y === here.y && here.y === after.y;
    const along = (here.x - before.x) * (after.x - here.x) + (here.y - before.y) * (after.y - here.y);
    return (upright || level) && along < 0;
};

const isSpur = function isSpur(rail: readonly LearningPoint[], index: number, stops: readonly RailStop[]): boolean {
    const [before, here, after] = rail.slice(index - 1, index + 2);
    if (before === undefined || here === undefined || after === undefined) {
        return false;
    }
    const atStop = stops.some((stop) => stop.cx === here.x && stop.cy === here.y);
    return !atStop && turnsBack(before, here, after);
};

export const unfold = function unfold(
    rail: readonly LearningPoint[],
    stops: readonly RailStop[],
): readonly LearningPoint[] {
    const held = [...rail];
    let index = 1;
    while (index < held.length - 1) {
        if (isSpur(held, index, stops)) {
            held.splice(index, 1);
            index = Math.max(1, index - 1);
        } else {
            index += 1;
        }
    }
    return held;
};
```
