Merge branch 'main' into coredump-clientstate
This commit is contained in:
		@ -1,7 +1,7 @@
 | 
			
		||||
import { test, expect, Page } from '@playwright/test'
 | 
			
		||||
import { makeTemplate, getUtils, doExport } from './test-utils'
 | 
			
		||||
import waitOn from 'wait-on'
 | 
			
		||||
import { roundOff, uuidv4 } from 'lib/utils'
 | 
			
		||||
import { XOR, roundOff, uuidv4 } from 'lib/utils'
 | 
			
		||||
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
 | 
			
		||||
import { secrets } from './secrets'
 | 
			
		||||
import {
 | 
			
		||||
@ -2440,6 +2440,245 @@ test('Extrude from command bar selects extrude line after', async ({
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test.describe('Testing constraints', () => {
 | 
			
		||||
  test(`Test remove constraints`, async ({ page }) => {
 | 
			
		||||
    await page.addInitScript(async () => {
 | 
			
		||||
      localStorage.setItem(
 | 
			
		||||
        'persistCode',
 | 
			
		||||
        `const yo = 79
 | 
			
		||||
const part001 = startSketchOn('XZ')
 | 
			
		||||
  |> startProfileAt([-7.54, -26.74], %)
 | 
			
		||||
  |> line([74.36, 130.4], %, 'seg01')
 | 
			
		||||
  |> line([78.92, -120.11], %)
 | 
			
		||||
  |> angledLine([segAng('seg01', %), yo], %)
 | 
			
		||||
  |> line([41.19, 28.97 + 5], %)
 | 
			
		||||
const part002 = startSketchOn('XZ')
 | 
			
		||||
  |> startProfileAt([299.05, 231.45], %)
 | 
			
		||||
  |> xLine(-425.34, %, 'seg-what')
 | 
			
		||||
  |> yLine(-264.06, %)
 | 
			
		||||
  |> xLine(segLen('seg-what', %), %)
 | 
			
		||||
  |> lineTo([profileStartX(%), profileStartY(%)], %)`
 | 
			
		||||
      )
 | 
			
		||||
    })
 | 
			
		||||
    const u = await getUtils(page)
 | 
			
		||||
    await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
    await page.goto('/')
 | 
			
		||||
    await u.waitForAuthSkipAppStart()
 | 
			
		||||
 | 
			
		||||
    await page.getByText("line([74.36, 130.4], %, 'seg01')").click()
 | 
			
		||||
    await page.getByRole('button', { name: 'Edit Sketch' }).click()
 | 
			
		||||
 | 
			
		||||
    const line3 = await u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`)
 | 
			
		||||
 | 
			
		||||
    // await page.mouse.click(line1.x, line1.y)
 | 
			
		||||
    // await page.keyboard.down('Shift')
 | 
			
		||||
    await page.mouse.click(line3.x, line3.y)
 | 
			
		||||
    await page.waitForTimeout(100) // this wait is needed for webkit - not sure why
 | 
			
		||||
    // await page.keyboard.up('Shift')
 | 
			
		||||
    await page
 | 
			
		||||
      .getByRole('button', {
 | 
			
		||||
        name: 'Constrain',
 | 
			
		||||
      })
 | 
			
		||||
      .click()
 | 
			
		||||
    await page
 | 
			
		||||
      .getByRole('button', { name: 'remove constraints', exact: true })
 | 
			
		||||
      .click()
 | 
			
		||||
 | 
			
		||||
    const activeLinesContent = await page.locator('.cm-activeLine').all()
 | 
			
		||||
    await expect(activeLinesContent).toHaveLength(1)
 | 
			
		||||
    await expect(activeLinesContent[0]).toHaveText('|> line([39.13, 68.63], %)')
 | 
			
		||||
 | 
			
		||||
    // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state
 | 
			
		||||
    await expect(page.getByTestId('segment-overlay')).toHaveCount(4)
 | 
			
		||||
  })
 | 
			
		||||
  test.describe('Test perpendicular distance constraint', () => {
 | 
			
		||||
    const cases = [
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'Add variable',
 | 
			
		||||
        offset: '-offset001',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'No variable',
 | 
			
		||||
        offset: '-128.05',
 | 
			
		||||
      },
 | 
			
		||||
    ] as const
 | 
			
		||||
    for (const { testName, offset } of cases) {
 | 
			
		||||
      test(`${testName}`, async ({ page }) => {
 | 
			
		||||
        await page.addInitScript(async () => {
 | 
			
		||||
          localStorage.setItem(
 | 
			
		||||
            'persistCode',
 | 
			
		||||
            `const yo = 5
 | 
			
		||||
const part001 = startSketchOn('XZ')
 | 
			
		||||
  |> startProfileAt([-7.54, -26.74], %)
 | 
			
		||||
  |> line([74.36, 130.4], %, 'seg01')
 | 
			
		||||
  |> line([78.92, -120.11], %)
 | 
			
		||||
  |> angledLine([segAng('seg01', %), 78.33], %)
 | 
			
		||||
  |> line([41.19, 28.97], %)
 | 
			
		||||
const part002 = startSketchOn('XZ')
 | 
			
		||||
  |> startProfileAt([299.05, 231.45], %)
 | 
			
		||||
  |> xLine(-425.34, %, 'seg-what')
 | 
			
		||||
  |> yLine(-264.06, %)
 | 
			
		||||
  |> xLine(segLen('seg-what', %), %)
 | 
			
		||||
  |> lineTo([profileStartX(%), profileStartY(%)], %)`
 | 
			
		||||
          )
 | 
			
		||||
        })
 | 
			
		||||
        const u = await getUtils(page)
 | 
			
		||||
        await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
        await page.goto('/')
 | 
			
		||||
        await u.waitForAuthSkipAppStart()
 | 
			
		||||
 | 
			
		||||
        await page.getByText("line([74.36, 130.4], %, 'seg01')").click()
 | 
			
		||||
        await page.getByRole('button', { name: 'Edit Sketch' }).click()
 | 
			
		||||
 | 
			
		||||
        const [line1, line3] = await Promise.all([
 | 
			
		||||
          u.getSegmentBodyCoords(`[data-overlay-index="${0}"]`),
 | 
			
		||||
          u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
        await page.mouse.click(line1.x, line1.y)
 | 
			
		||||
        await page.keyboard.down('Shift')
 | 
			
		||||
        await page.mouse.click(line3.x, line3.y)
 | 
			
		||||
        await page.waitForTimeout(100) // this wait is needed for webkit - not sure why
 | 
			
		||||
        await page.keyboard.up('Shift')
 | 
			
		||||
        await page
 | 
			
		||||
          .getByRole('button', {
 | 
			
		||||
            name: 'Constrain',
 | 
			
		||||
          })
 | 
			
		||||
          .click()
 | 
			
		||||
        await page
 | 
			
		||||
          .getByRole('button', { name: 'perpendicular distance', exact: true })
 | 
			
		||||
          .click()
 | 
			
		||||
 | 
			
		||||
        const createNewVariableCheckbox = page.getByTestId(
 | 
			
		||||
          'create-new-variable-checkbox'
 | 
			
		||||
        )
 | 
			
		||||
        const isChecked = await createNewVariableCheckbox.isChecked()
 | 
			
		||||
        const addVariable = testName === 'Add variable'
 | 
			
		||||
        XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct
 | 
			
		||||
          (await createNewVariableCheckbox.click())
 | 
			
		||||
 | 
			
		||||
        await page
 | 
			
		||||
          .getByRole('button', { name: 'Add constraining value' })
 | 
			
		||||
          .click()
 | 
			
		||||
 | 
			
		||||
        const activeLinesContent = await page.locator('.cm-activeLine').all()
 | 
			
		||||
        await expect(activeLinesContent[0]).toHaveText(
 | 
			
		||||
          `|> line([74.36, 130.4], %, 'seg01')`
 | 
			
		||||
        )
 | 
			
		||||
        await expect(activeLinesContent[1]).toHaveText(`}, %)`)
 | 
			
		||||
        await expect(page.locator('.cm-content')).toContainText(`angle: -57,`)
 | 
			
		||||
        await expect(page.locator('.cm-content')).toContainText(
 | 
			
		||||
          `offset: ${offset},`
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state
 | 
			
		||||
        await expect(page.getByTestId('segment-overlay')).toHaveCount(4)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  test.describe('Test distance between constraint', () => {
 | 
			
		||||
    const cases = [
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'Add variable',
 | 
			
		||||
        constraint: 'horizontal distance',
 | 
			
		||||
        value: "segEndX('seg01', %) + xDis001, 61.34",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'No variable',
 | 
			
		||||
        constraint: 'horizontal distance',
 | 
			
		||||
        value: "segEndX('seg01', %) + 88.08, 61.34",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'Add variable',
 | 
			
		||||
        constraint: 'vertical distance',
 | 
			
		||||
        value: "154.9, segEndY('seg01', %) - yDis001",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'No variable',
 | 
			
		||||
        constraint: 'vertical distance',
 | 
			
		||||
        value: "154.9, segEndY('seg01', %) - 42.32",
 | 
			
		||||
      },
 | 
			
		||||
    ] as const
 | 
			
		||||
    for (const { testName, value, constraint } of cases) {
 | 
			
		||||
      test(`${constraint} - ${testName}`, async ({ page }) => {
 | 
			
		||||
        await page.addInitScript(async () => {
 | 
			
		||||
          localStorage.setItem(
 | 
			
		||||
            'persistCode',
 | 
			
		||||
            `const yo = 5
 | 
			
		||||
const part001 = startSketchOn('XZ')
 | 
			
		||||
  |> startProfileAt([-7.54, -26.74], %)
 | 
			
		||||
  |> line([74.36, 130.4], %)
 | 
			
		||||
  |> line([78.92, -120.11], %)
 | 
			
		||||
  |> line([9.16, 77.79], %)
 | 
			
		||||
  |> line([41.19, 28.97], %)
 | 
			
		||||
const part002 = startSketchOn('XZ')
 | 
			
		||||
  |> startProfileAt([299.05, 231.45], %)
 | 
			
		||||
  |> xLine(-425.34, %, 'seg-what')
 | 
			
		||||
  |> yLine(-264.06, %)
 | 
			
		||||
  |> xLine(segLen('seg-what', %), %)
 | 
			
		||||
  |> lineTo([profileStartX(%), profileStartY(%)], %)`
 | 
			
		||||
          )
 | 
			
		||||
        })
 | 
			
		||||
        const u = await getUtils(page)
 | 
			
		||||
        await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
        await page.goto('/')
 | 
			
		||||
        await u.waitForAuthSkipAppStart()
 | 
			
		||||
 | 
			
		||||
        await page.getByText('line([74.36, 130.4], %)').click()
 | 
			
		||||
        await page.getByRole('button', { name: 'Edit Sketch' }).click()
 | 
			
		||||
 | 
			
		||||
        const [line1, line3] = await Promise.all([
 | 
			
		||||
          u.getSegmentBodyCoords(`[data-overlay-index="${0}"]`),
 | 
			
		||||
          u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`),
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
        await page.mouse.click(line1.x, line1.y)
 | 
			
		||||
        await page.keyboard.down('Shift')
 | 
			
		||||
        await page.mouse.click(line3.x, line3.y)
 | 
			
		||||
        await page.waitForTimeout(100) // this wait is needed for webkit - not sure why
 | 
			
		||||
        await page.keyboard.up('Shift')
 | 
			
		||||
        await page
 | 
			
		||||
          .getByRole('button', {
 | 
			
		||||
            name: 'Constrain',
 | 
			
		||||
          })
 | 
			
		||||
          .click()
 | 
			
		||||
        await page
 | 
			
		||||
          .getByRole('button', { name: constraint, exact: true })
 | 
			
		||||
          .click()
 | 
			
		||||
 | 
			
		||||
        const createNewVariableCheckbox = page.getByTestId(
 | 
			
		||||
          'create-new-variable-checkbox'
 | 
			
		||||
        )
 | 
			
		||||
        const isChecked = await createNewVariableCheckbox.isChecked()
 | 
			
		||||
        const addVariable = testName === 'Add variable'
 | 
			
		||||
        XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct
 | 
			
		||||
          (await createNewVariableCheckbox.click())
 | 
			
		||||
 | 
			
		||||
        await page
 | 
			
		||||
          .getByRole('button', { name: 'Add constraining value' })
 | 
			
		||||
          .click()
 | 
			
		||||
 | 
			
		||||
        // checking activeLines assures the cursors are where they should be
 | 
			
		||||
        const codeAfter = [
 | 
			
		||||
          `|> line([74.36, 130.4], %, 'seg01')`,
 | 
			
		||||
          `|> lineTo([${value}], %)`,
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        const activeLinesContent = await page.locator('.cm-activeLine').all()
 | 
			
		||||
        await Promise.all(
 | 
			
		||||
          activeLinesContent.map(async (line, i) => {
 | 
			
		||||
            await expect(page.locator('.cm-content')).toContainText(
 | 
			
		||||
              codeAfter[i]
 | 
			
		||||
            )
 | 
			
		||||
            // if the code is an active line then the cursor should be on that line
 | 
			
		||||
            await expect(line).toHaveText(codeAfter[i])
 | 
			
		||||
          })
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state
 | 
			
		||||
        await expect(page.getByTestId('segment-overlay')).toHaveCount(4)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  test.describe('Test ABS distance constraint', () => {
 | 
			
		||||
    const cases = [
 | 
			
		||||
      {
 | 
			
		||||
@ -2521,7 +2760,7 @@ const part002 = startSketchOn('XZ')
 | 
			
		||||
          'create-new-variable-checkbox'
 | 
			
		||||
        )
 | 
			
		||||
        const isChecked = await createNewVariableCheckbox.isChecked()
 | 
			
		||||
        ;((isChecked && !addVariable) || (!isChecked && addVariable)) &&
 | 
			
		||||
        XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct
 | 
			
		||||
          (await createNewVariableCheckbox.click())
 | 
			
		||||
 | 
			
		||||
        await page
 | 
			
		||||
@ -2627,7 +2866,7 @@ const part002 = startSketchOn('XZ')
 | 
			
		||||
          'create-new-variable-checkbox'
 | 
			
		||||
        )
 | 
			
		||||
        const isChecked = await createNewVariableCheckbox.isChecked()
 | 
			
		||||
        ;((isChecked && !addVariable) || (!isChecked && addVariable)) &&
 | 
			
		||||
        XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct
 | 
			
		||||
          (await createNewVariableCheckbox.click())
 | 
			
		||||
 | 
			
		||||
        await page
 | 
			
		||||
@ -2657,37 +2896,51 @@ const part002 = startSketchOn('XZ')
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  test.describe('Test Angle constraint single selection', () => {
 | 
			
		||||
  test.describe('Test Angle/Length constraint single selection', () => {
 | 
			
		||||
    const cases = [
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'Add variable',
 | 
			
		||||
        testName: 'Angle - Add variable',
 | 
			
		||||
        addVariable: true,
 | 
			
		||||
        value: 'angle001',
 | 
			
		||||
        constraint: 'angle',
 | 
			
		||||
        value: 'angle001, 78.33',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'No variable',
 | 
			
		||||
        testName: 'Angle - No variable',
 | 
			
		||||
        addVariable: false,
 | 
			
		||||
        value: '83',
 | 
			
		||||
        constraint: 'angle',
 | 
			
		||||
        value: '83, 78.33',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'Length - Add variable',
 | 
			
		||||
        addVariable: true,
 | 
			
		||||
        constraint: 'length',
 | 
			
		||||
        value: '83, length001',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        testName: 'Length - No variable',
 | 
			
		||||
        addVariable: false,
 | 
			
		||||
        constraint: 'length',
 | 
			
		||||
        value: '83, 78.33',
 | 
			
		||||
      },
 | 
			
		||||
    ] as const
 | 
			
		||||
    for (const { testName, addVariable, value } of cases) {
 | 
			
		||||
    for (const { testName, addVariable, value, constraint } of cases) {
 | 
			
		||||
      test(`${testName}`, async ({ page }) => {
 | 
			
		||||
        await page.addInitScript(async () => {
 | 
			
		||||
          localStorage.setItem(
 | 
			
		||||
            'persistCode',
 | 
			
		||||
            `const yo = 5
 | 
			
		||||
    const part001 = startSketchOn('XZ')
 | 
			
		||||
      |> startProfileAt([-7.54, -26.74], %)
 | 
			
		||||
      |> line([74.36, 130.4], %)
 | 
			
		||||
      |> line([78.92, -120.11], %)
 | 
			
		||||
      |> line([9.16, 77.79], %)
 | 
			
		||||
      |> line([41.19, 28.97], %)
 | 
			
		||||
    const part002 = startSketchOn('XZ')
 | 
			
		||||
      |> startProfileAt([299.05, 231.45], %)
 | 
			
		||||
      |> xLine(-425.34, %, 'seg-what')
 | 
			
		||||
      |> yLine(-264.06, %)
 | 
			
		||||
      |> xLine(segLen('seg-what', %), %)
 | 
			
		||||
      |> lineTo([profileStartX(%), profileStartY(%)], %)`
 | 
			
		||||
const part001 = startSketchOn('XZ')
 | 
			
		||||
  |> startProfileAt([-7.54, -26.74], %)
 | 
			
		||||
  |> line([74.36, 130.4], %)
 | 
			
		||||
  |> line([78.92, -120.11], %)
 | 
			
		||||
  |> line([9.16, 77.79], %)
 | 
			
		||||
  |> line([41.19, 28.97], %)
 | 
			
		||||
const part002 = startSketchOn('XZ')
 | 
			
		||||
  |> startProfileAt([299.05, 231.45], %)
 | 
			
		||||
  |> xLine(-425.34, %, 'seg-what')
 | 
			
		||||
  |> yLine(-264.06, %)
 | 
			
		||||
  |> xLine(segLen('seg-what', %), %)
 | 
			
		||||
  |> lineTo([profileStartX(%), profileStartY(%)], %)`
 | 
			
		||||
          )
 | 
			
		||||
        })
 | 
			
		||||
        const u = await getUtils(page)
 | 
			
		||||
@ -2708,7 +2961,7 @@ const part002 = startSketchOn('XZ')
 | 
			
		||||
            name: 'Constrain',
 | 
			
		||||
          })
 | 
			
		||||
          .click()
 | 
			
		||||
        await page.getByTestId('angle').click()
 | 
			
		||||
        await page.getByTestId(constraint).click()
 | 
			
		||||
 | 
			
		||||
        if (!addVariable) {
 | 
			
		||||
          await page.getByTestId('create-new-variable-checkbox').click()
 | 
			
		||||
@ -2717,7 +2970,7 @@ const part002 = startSketchOn('XZ')
 | 
			
		||||
          .getByRole('button', { name: 'Add constraining value' })
 | 
			
		||||
          .click()
 | 
			
		||||
 | 
			
		||||
        const changedCode = `|> angledLine([${value}, 78.33], %)`
 | 
			
		||||
        const changedCode = `|> angledLine([${value}], %)`
 | 
			
		||||
        await expect(page.locator('.cm-content')).toContainText(changedCode)
 | 
			
		||||
        // checking active assures the cursor is where it should be
 | 
			
		||||
        await expect(page.locator('.cm-activeLine')).toHaveText(changedCode)
 | 
			
		||||
@ -2748,7 +3001,7 @@ const part002 = startSketchOn('XZ')
 | 
			
		||||
    ] as const
 | 
			
		||||
    for (const { codeAfter, constraintName } of cases) {
 | 
			
		||||
      test(`${constraintName}`, async ({ page }) => {
 | 
			
		||||
        await page.addInitScript(async () => {
 | 
			
		||||
        await page.addInitScript(async (customCode) => {
 | 
			
		||||
          localStorage.setItem(
 | 
			
		||||
            'persistCode',
 | 
			
		||||
            `const yo = 5
 | 
			
		||||
@ -2774,15 +3027,21 @@ const part002 = startSketchOn('XZ')
 | 
			
		||||
        await page.getByText('line([74.36, 130.4], %)').click()
 | 
			
		||||
        await page.getByRole('button', { name: 'Edit Sketch' }).click()
 | 
			
		||||
 | 
			
		||||
        const line1 = await u.getBoundingBox(`[data-overlay-index="${0}"]`)
 | 
			
		||||
        const line3 = await u.getBoundingBox(`[data-overlay-index="${2}"]`)
 | 
			
		||||
        const line4 = await u.getBoundingBox(`[data-overlay-index="${3}"]`)
 | 
			
		||||
        const line1 = await u.getSegmentBodyCoords(
 | 
			
		||||
          `[data-overlay-index="${0}"]`
 | 
			
		||||
        )
 | 
			
		||||
        const line3 = await u.getSegmentBodyCoords(
 | 
			
		||||
          `[data-overlay-index="${2}"]`
 | 
			
		||||
        )
 | 
			
		||||
        const line4 = await u.getSegmentBodyCoords(
 | 
			
		||||
          `[data-overlay-index="${3}"]`
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // select two segments by holding down shift
 | 
			
		||||
        await page.mouse.click(line1.x - 20, line1.y + 20)
 | 
			
		||||
        await page.mouse.click(line1.x, line1.y)
 | 
			
		||||
        await page.keyboard.down('Shift')
 | 
			
		||||
        await page.mouse.click(line3.x - 3, line3.y + 20)
 | 
			
		||||
        await page.mouse.click(line4.x - 15, line4.y + 15)
 | 
			
		||||
        await page.mouse.click(line3.x, line3.y)
 | 
			
		||||
        await page.mouse.click(line4.x, line4.y)
 | 
			
		||||
        await page.keyboard.up('Shift')
 | 
			
		||||
        const constraintMenuButton = page.getByRole('button', {
 | 
			
		||||
          name: 'Constrain',
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB  | 
@ -508,13 +508,26 @@ export const ModelingMachineProvider = ({
 | 
			
		||||
        },
 | 
			
		||||
        'Get horizontal info': async ({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
          sketchDetails,
 | 
			
		||||
        }): Promise<SetSelections> => {
 | 
			
		||||
          const { modifiedAst, pathToNodeMap } =
 | 
			
		||||
            await applyConstraintHorzVertDistance({
 | 
			
		||||
              constraint: 'setHorzDistance',
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
            })
 | 
			
		||||
          await kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
          const _modifiedAst = parse(recast(modifiedAst))
 | 
			
		||||
          if (!sketchDetails) throw new Error('No sketch details')
 | 
			
		||||
          const updatedPathToNode = updatePathToNodeFromMap(
 | 
			
		||||
            sketchDetails.sketchPathToNode,
 | 
			
		||||
            pathToNodeMap
 | 
			
		||||
          )
 | 
			
		||||
          await sceneEntitiesManager.updateAstAndRejigSketch(
 | 
			
		||||
            updatedPathToNode,
 | 
			
		||||
            _modifiedAst,
 | 
			
		||||
            sketchDetails.zAxis,
 | 
			
		||||
            sketchDetails.yAxis,
 | 
			
		||||
            sketchDetails.origin
 | 
			
		||||
          )
 | 
			
		||||
          return {
 | 
			
		||||
            selectionType: 'completeSelection',
 | 
			
		||||
            selection: pathMapToSelections(
 | 
			
		||||
@ -522,17 +535,31 @@ export const ModelingMachineProvider = ({
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
              pathToNodeMap
 | 
			
		||||
            ),
 | 
			
		||||
            updatedPathToNode,
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        'Get vertical info': async ({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
          sketchDetails,
 | 
			
		||||
        }): Promise<SetSelections> => {
 | 
			
		||||
          const { modifiedAst, pathToNodeMap } =
 | 
			
		||||
            await applyConstraintHorzVertDistance({
 | 
			
		||||
              constraint: 'setVertDistance',
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
            })
 | 
			
		||||
          await kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
          const _modifiedAst = parse(recast(modifiedAst))
 | 
			
		||||
          if (!sketchDetails) throw new Error('No sketch details')
 | 
			
		||||
          const updatedPathToNode = updatePathToNodeFromMap(
 | 
			
		||||
            sketchDetails.sketchPathToNode,
 | 
			
		||||
            pathToNodeMap
 | 
			
		||||
          )
 | 
			
		||||
          await sceneEntitiesManager.updateAstAndRejigSketch(
 | 
			
		||||
            updatedPathToNode,
 | 
			
		||||
            _modifiedAst,
 | 
			
		||||
            sketchDetails.zAxis,
 | 
			
		||||
            sketchDetails.yAxis,
 | 
			
		||||
            sketchDetails.origin
 | 
			
		||||
          )
 | 
			
		||||
          return {
 | 
			
		||||
            selectionType: 'completeSelection',
 | 
			
		||||
            selection: pathMapToSelections(
 | 
			
		||||
@ -540,6 +567,7 @@ export const ModelingMachineProvider = ({
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
              pathToNodeMap
 | 
			
		||||
            ),
 | 
			
		||||
            updatedPathToNode,
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        'Get angle info': async ({
 | 
			
		||||
@ -581,10 +609,23 @@ export const ModelingMachineProvider = ({
 | 
			
		||||
        },
 | 
			
		||||
        'Get length info': async ({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
          sketchDetails,
 | 
			
		||||
        }): Promise<SetSelections> => {
 | 
			
		||||
          const { modifiedAst, pathToNodeMap } =
 | 
			
		||||
            await applyConstraintAngleLength({ selectionRanges })
 | 
			
		||||
          await kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
          const _modifiedAst = parse(recast(modifiedAst))
 | 
			
		||||
          if (!sketchDetails) throw new Error('No sketch details')
 | 
			
		||||
          const updatedPathToNode = updatePathToNodeFromMap(
 | 
			
		||||
            sketchDetails.sketchPathToNode,
 | 
			
		||||
            pathToNodeMap
 | 
			
		||||
          )
 | 
			
		||||
          await sceneEntitiesManager.updateAstAndRejigSketch(
 | 
			
		||||
            updatedPathToNode,
 | 
			
		||||
            _modifiedAst,
 | 
			
		||||
            sketchDetails.zAxis,
 | 
			
		||||
            sketchDetails.yAxis,
 | 
			
		||||
            sketchDetails.origin
 | 
			
		||||
          )
 | 
			
		||||
          return {
 | 
			
		||||
            selectionType: 'completeSelection',
 | 
			
		||||
            selection: pathMapToSelections(
 | 
			
		||||
@ -592,17 +633,31 @@ export const ModelingMachineProvider = ({
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
              pathToNodeMap
 | 
			
		||||
            ),
 | 
			
		||||
            updatedPathToNode,
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        'Get perpendicular distance info': async ({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
          sketchDetails,
 | 
			
		||||
        }): Promise<SetSelections> => {
 | 
			
		||||
          const { modifiedAst, pathToNodeMap } = await applyConstraintIntersect(
 | 
			
		||||
            {
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
            }
 | 
			
		||||
          )
 | 
			
		||||
          await kclManager.updateAst(modifiedAst, true)
 | 
			
		||||
          const _modifiedAst = parse(recast(modifiedAst))
 | 
			
		||||
          if (!sketchDetails) throw new Error('No sketch details')
 | 
			
		||||
          const updatedPathToNode = updatePathToNodeFromMap(
 | 
			
		||||
            sketchDetails.sketchPathToNode,
 | 
			
		||||
            pathToNodeMap
 | 
			
		||||
          )
 | 
			
		||||
          await sceneEntitiesManager.updateAstAndRejigSketch(
 | 
			
		||||
            updatedPathToNode,
 | 
			
		||||
            _modifiedAst,
 | 
			
		||||
            sketchDetails.zAxis,
 | 
			
		||||
            sketchDetails.yAxis,
 | 
			
		||||
            sketchDetails.origin
 | 
			
		||||
          )
 | 
			
		||||
          return {
 | 
			
		||||
            selectionType: 'completeSelection',
 | 
			
		||||
            selection: pathMapToSelections(
 | 
			
		||||
@ -610,6 +665,7 @@ export const ModelingMachineProvider = ({
 | 
			
		||||
              selectionRanges,
 | 
			
		||||
              pathToNodeMap
 | 
			
		||||
            ),
 | 
			
		||||
            updatedPathToNode,
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        'Get ABS X info': async ({
 | 
			
		||||
 | 
			
		||||
@ -140,7 +140,11 @@ export async function applyConstraintIntersect({
 | 
			
		||||
    value: valueUsedInTransform,
 | 
			
		||||
    initialVariableName: 'offset',
 | 
			
		||||
  })
 | 
			
		||||
  if (segName === tagInfo?.tag && Number(value) === valueUsedInTransform) {
 | 
			
		||||
  if (
 | 
			
		||||
    !variableName &&
 | 
			
		||||
    segName === tagInfo?.tag &&
 | 
			
		||||
    Number(value) === valueUsedInTransform
 | 
			
		||||
  ) {
 | 
			
		||||
    return {
 | 
			
		||||
      modifiedAst,
 | 
			
		||||
      pathToNodeMap,
 | 
			
		||||
@ -169,6 +173,10 @@ export async function applyConstraintIntersect({
 | 
			
		||||
      createVariableDeclaration(variableName, valueNode)
 | 
			
		||||
    )
 | 
			
		||||
    _modifiedAst.body = newBody
 | 
			
		||||
    Object.values(_pathToNodeMap).forEach((pathToNode) => {
 | 
			
		||||
      const index = pathToNode.findIndex((a) => a[0] === 'body') + 1
 | 
			
		||||
      pathToNode[index][0] = Number(pathToNode[index][0]) + 1
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
  return {
 | 
			
		||||
    modifiedAst: _modifiedAst,
 | 
			
		||||
 | 
			
		||||
@ -106,7 +106,11 @@ export async function applyConstraintHorzVertDistance({
 | 
			
		||||
    value: valueUsedInTransform,
 | 
			
		||||
    initialVariableName: constraint === 'setHorzDistance' ? 'xDis' : 'yDis',
 | 
			
		||||
  } as any)
 | 
			
		||||
  if (segName === tagInfo?.tag && Number(value) === valueUsedInTransform) {
 | 
			
		||||
  if (
 | 
			
		||||
    !variableName &&
 | 
			
		||||
    segName === tagInfo?.tag &&
 | 
			
		||||
    Number(value) === valueUsedInTransform
 | 
			
		||||
  ) {
 | 
			
		||||
    return {
 | 
			
		||||
      modifiedAst,
 | 
			
		||||
      pathToNodeMap,
 | 
			
		||||
@ -133,6 +137,10 @@ export async function applyConstraintHorzVertDistance({
 | 
			
		||||
        createVariableDeclaration(variableName, valueNode)
 | 
			
		||||
      )
 | 
			
		||||
      _modifiedAst.body = newBody
 | 
			
		||||
      Object.values(pathToNodeMap).forEach((pathToNode) => {
 | 
			
		||||
        const index = pathToNode.findIndex((a) => a[0] === 'body') + 1
 | 
			
		||||
        pathToNode[index][0] = Number(pathToNode[index][0]) + 1
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
      modifiedAst: _modifiedAst,
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,13 @@ export const getRectangleCallExpressions = (
 | 
			
		||||
    createPipeSubstitution(),
 | 
			
		||||
    createLiteral(tags[2]),
 | 
			
		||||
  ]),
 | 
			
		||||
  createCallExpressionStdLib('lineTo', [
 | 
			
		||||
    createArrayExpression([
 | 
			
		||||
      createCallExpressionStdLib('profileStartX', [createPipeSubstitution()]),
 | 
			
		||||
      createCallExpressionStdLib('profileStartY', [createPipeSubstitution()]),
 | 
			
		||||
    ]),
 | 
			
		||||
    createPipeSubstitution(),
 | 
			
		||||
  ]), // close the rectangle
 | 
			
		||||
  createCallExpressionStdLib('close', [createPipeSubstitution()]),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -127,3 +127,7 @@ export function isReducedMotion(): boolean {
 | 
			
		||||
    window.matchMedia('(prefers-reduced-motion)').matches
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function XOR(bool1: boolean, bool2: boolean): boolean {
 | 
			
		||||
  return (bool1 || bool2) && !(bool1 && bool2)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -360,10 +360,8 @@ export const modelingMachine = createMachine(
 | 
			
		||||
              },
 | 
			
		||||
 | 
			
		||||
              'Constrain remove constraints': {
 | 
			
		||||
                target: 'SketchIdle',
 | 
			
		||||
                internal: true,
 | 
			
		||||
                cond: 'Can constrain remove constraints',
 | 
			
		||||
                actions: ['Constrain remove constraints'],
 | 
			
		||||
                target: 'Await constrain remove constraints',
 | 
			
		||||
              },
 | 
			
		||||
 | 
			
		||||
              'Re-execute': {
 | 
			
		||||
@ -586,6 +584,16 @@ export const modelingMachine = createMachine(
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
 | 
			
		||||
          'Await constrain remove constraints': {
 | 
			
		||||
            invoke: {
 | 
			
		||||
              src: 'do-constrain-remove-constraint',
 | 
			
		||||
              id: 'do-constrain-remove-constraint',
 | 
			
		||||
              onDone: {
 | 
			
		||||
                target: 'SketchIdle',
 | 
			
		||||
                actions: 'Set selection',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          'Await constrain horizontally': {
 | 
			
		||||
            invoke: {
 | 
			
		||||
              src: 'do-constrain-horizontally',
 | 
			
		||||
@ -848,21 +856,6 @@ export const modelingMachine = createMachine(
 | 
			
		||||
      'set new sketch metadata': assign((_, { data }) => ({
 | 
			
		||||
        sketchDetails: data,
 | 
			
		||||
      })),
 | 
			
		||||
      // TODO implement source ranges for all of these constraints
 | 
			
		||||
      // need to make the async like the modal constraints
 | 
			
		||||
      'Constrain remove constraints': ({ selectionRanges, sketchDetails }) => {
 | 
			
		||||
        const { modifiedAst } = applyRemoveConstrainingValues({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
        })
 | 
			
		||||
        if (!sketchDetails) return
 | 
			
		||||
        sceneEntitiesManager.updateAstAndRejigSketch(
 | 
			
		||||
          sketchDetails?.sketchPathToNode || [],
 | 
			
		||||
          modifiedAst,
 | 
			
		||||
          sketchDetails.zAxis,
 | 
			
		||||
          sketchDetails.yAxis,
 | 
			
		||||
          sketchDetails.origin
 | 
			
		||||
        )
 | 
			
		||||
      },
 | 
			
		||||
      'AST extrude': async (_, event) => {
 | 
			
		||||
        if (!event.data) return
 | 
			
		||||
        const { selection, distance } = event.data
 | 
			
		||||
@ -1109,6 +1102,38 @@ export const modelingMachine = createMachine(
 | 
			
		||||
    },
 | 
			
		||||
    // end actions
 | 
			
		||||
    services: {
 | 
			
		||||
      'do-constrain-remove-constraint': async ({
 | 
			
		||||
        selectionRanges,
 | 
			
		||||
        sketchDetails,
 | 
			
		||||
      }) => {
 | 
			
		||||
        const { modifiedAst, pathToNodeMap } = applyRemoveConstrainingValues({
 | 
			
		||||
          selectionRanges,
 | 
			
		||||
        })
 | 
			
		||||
        if (!sketchDetails) return
 | 
			
		||||
        sceneEntitiesManager.updateAstAndRejigSketch(
 | 
			
		||||
          sketchDetails?.sketchPathToNode || [],
 | 
			
		||||
          modifiedAst,
 | 
			
		||||
          sketchDetails.zAxis,
 | 
			
		||||
          sketchDetails.yAxis,
 | 
			
		||||
          sketchDetails.origin
 | 
			
		||||
        )
 | 
			
		||||
        if (!sketchDetails) return
 | 
			
		||||
        await sceneEntitiesManager.updateAstAndRejigSketch(
 | 
			
		||||
          sketchDetails.sketchPathToNode,
 | 
			
		||||
          modifiedAst,
 | 
			
		||||
          sketchDetails.zAxis,
 | 
			
		||||
          sketchDetails.yAxis,
 | 
			
		||||
          sketchDetails.origin
 | 
			
		||||
        )
 | 
			
		||||
        return {
 | 
			
		||||
          selectionType: 'completeSelection',
 | 
			
		||||
          selection: updateSelections(
 | 
			
		||||
            pathToNodeMap,
 | 
			
		||||
            selectionRanges,
 | 
			
		||||
            parse(recast(modifiedAst))
 | 
			
		||||
          ),
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      'do-constrain-horizontally': async ({
 | 
			
		||||
        selectionRanges,
 | 
			
		||||
        sketchDetails,
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user