Compare commits
43 Commits
derive-doc
...
nightly-v2
Author | SHA1 | Date | |
---|---|---|---|
099c48cd63 | |||
f35cd3ef26 | |||
695c432d1e | |||
2835665a6a | |||
45707d2974 | |||
b2e1d21d45 | |||
b98f5605b6 | |||
c050e03df1 | |||
b6fa4325f0 | |||
0804aecc63 | |||
3dfc2c86e1 | |||
71647ede29 | |||
cd679f4be3 | |||
18d87b99bd | |||
70a2202877 | |||
f5c9f84ae9 | |||
71f701dec7 | |||
bffbed1d42 | |||
9f60ed8e75 | |||
57b366b2d0 | |||
6f3f5dbda9 | |||
8dd25715fb | |||
834f7133d8 | |||
8c5662e458 | |||
f37fc357af | |||
e27e9ecc63 | |||
78b42ea191 | |||
5d02a27122 | |||
49d52ce94b | |||
a572d7b0db | |||
1f405b9327 | |||
0874891dd0 | |||
59d0e079a1 | |||
b9862baed0 | |||
592c5259c6 | |||
950f5cebfd | |||
4c0ea136e0 | |||
81c0035adc | |||
c68e5d7774 | |||
ed8a0e4aaa | |||
322f398049 | |||
bc4d254297 | |||
10b7a772bf |
13
.gitattributes
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
* text=auto
|
||||
|
||||
# Force batch scripts to always use CRLF line endings so that if a repo is accessed
|
||||
# in Windows via a file share from Linux, the scripts will work.
|
||||
*.{cmd,[cC][mM][dD]} text working-tree-encoding=UTF-16LE eol=CRLF
|
||||
*.{bat,[bB][aA][tT]} text working-tree-encoding=UTF-16LE eol=CRLF
|
||||
*.{ics,[iI][cC][sS]} text working-tree-encoding=UTF-16LE eol=CRLF
|
||||
*.{ps1,[iP][sS][1]} text working-tree-encoding=UTF-16LE eol=CRLF
|
||||
|
||||
# Force bash scripts to always use LF line endings so that if a repo is accessed
|
||||
# in Unix via a file share from Windows, the scripts will work.
|
||||
*.sh text eol=lfol=lf
|
@ -17,7 +17,7 @@ lastSegX(sketch: Sketch) -> number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
|
||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | The sketch whose line segment is being queried | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -17,7 +17,7 @@ lastSegY(sketch: Sketch) -> number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
|
||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | The sketch whose line segment is being queried | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -57,3 +57,55 @@ Imported symbols can be renamed for convenience or to avoid name collisions.
|
||||
```
|
||||
import increment as inc, decrement as dec from "util.kcl"
|
||||
```
|
||||
|
||||
## Importing files from other CAD systems
|
||||
|
||||
`import` can also be used to import files from other CAD systems. The format of the statement is the
|
||||
same as for KCL files. You can only import the whole file, not items from it. E.g.,
|
||||
|
||||
```
|
||||
import "tests/inputs/cube.obj"
|
||||
|
||||
// Use `cube` just like a KCL object.
|
||||
```
|
||||
|
||||
```
|
||||
import "tests/inputs/cube-2.sldprt" as cube
|
||||
|
||||
// Use `cube` just like a KCL object.
|
||||
```
|
||||
|
||||
You can make the file format explicit using a format attribute (useful if using a different
|
||||
extension), e.g.,
|
||||
|
||||
```
|
||||
@(format = obj)
|
||||
import "tests/inputs/cube"
|
||||
```
|
||||
|
||||
For formats lacking unit data (such as STL, OBJ, or PLY files), the default
|
||||
unit of measurement is millimeters. Alternatively you may specify the unit
|
||||
by using an attirbute. Likewise, you can also specify a coordinate system. E.g.,
|
||||
|
||||
```
|
||||
@(unitLength = ft, coords = opengl)
|
||||
import "tests/inputs/cube.obj"
|
||||
```
|
||||
|
||||
When importing a GLTF file, the bin file will be imported as well.
|
||||
|
||||
Import paths are relative to the current project directory. Imports currently only work when
|
||||
using the native Modeling App, not in the browser.
|
||||
|
||||
### Supported values
|
||||
|
||||
File formats: `fbx`, `gltf`/`glb`, `obj`+, `ply`+, `sldprt`, `step`/`stp`, `stl`+. (Those marked with a
|
||||
'+' support customising the length unit and coordinate system).
|
||||
|
||||
Length units: `mm` (the default), `cm`, `m`, `inch`, `ft`, `yd`.
|
||||
|
||||
Coordinate systems:
|
||||
|
||||
- `zoo` (the default), forward: -Y, up: +Z, handedness: right
|
||||
- `opengl`, forward: +Z, up: +Y, handedness: right
|
||||
- `vulkan`, forward: +Z, up: -Y, handedness: left
|
||||
|
@ -9,7 +9,7 @@ Repeat a 2-dimensional sketch some number of times along a partial or
|
||||
complete circle some specified number of times. Each object may additionally be rotated along the circle, ensuring orentation of the solid with respect to the center of the circle is maintained.
|
||||
|
||||
```js
|
||||
patternCircular2d(data: CircularPattern2dData, sketch_set: SketchSet) -> [Sketch]
|
||||
patternCircular2d(sketch_set: SketchSet, instances: integer, center: [number], arc_degrees: number, rotate_duplicates: bool, use_original?: bool) -> [Sketch]
|
||||
```
|
||||
|
||||
|
||||
@ -17,8 +17,12 @@ patternCircular2d(data: CircularPattern2dData, sketch_set: SketchSet) -> [Sketch
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `data` | [`CircularPattern2dData`](/docs/kcl/types/CircularPattern2dData) | Data for a circular pattern on a 2D sketch. | Yes |
|
||||
| `sketch_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |
|
||||
| `sketch_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | Which sketch(es) to pattern | Yes |
|
||||
| `instances` | `integer` | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
|
||||
| `center` | `[number]` | The center about which to make the pattern. This is a 2D vector. | Yes |
|
||||
| `arc_degrees` | `number` | The arc angle (in degrees) to place the repetitions. Must be greater than 0. | Yes |
|
||||
| `rotate_duplicates` | `bool` | Whether or not to rotate the duplicates as they are copied. | Yes |
|
||||
| `use_original` | `bool` | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false. | No |
|
||||
|
||||
### Returns
|
||||
|
||||
@ -34,12 +38,12 @@ exampleSketch = startSketchOn('XZ')
|
||||
|> line(end = [-1, 0])
|
||||
|> line(end = [0, -5])
|
||||
|> close()
|
||||
|> patternCircular2d({
|
||||
|> patternCircular2d(
|
||||
center = [0, 0],
|
||||
instances = 13,
|
||||
arcDegrees = 360,
|
||||
rotateDuplicates = true
|
||||
}, %)
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
example = extrude(exampleSketch, length = 1)
|
||||
```
|
||||
|
@ -17,7 +17,7 @@ segEnd(tag: TagIdentifier) -> [number]
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | | Yes |
|
||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -17,7 +17,7 @@ segEndX(tag: TagIdentifier) -> number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | | Yes |
|
||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -17,7 +17,7 @@ segStartX(tag: TagIdentifier) -> number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | | Yes |
|
||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
@ -17,7 +17,7 @@ segStartY(tag: TagIdentifier) -> number
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | | Yes |
|
||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
|
||||
|
||||
### Returns
|
||||
|
||||
|
104320
docs/kcl/std.json
@ -18,6 +18,7 @@ A base path.
|
||||
|----------|------|-------------|----------|
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A base path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
|
16
docs/kcl/types/EnvironmentRef.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "EnvironmentRef"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
[`SnapshotRef`](/docs/kcl/types/SnapshotRef)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -19,8 +19,8 @@ A face.
|
||||
| `id` |`string`| The id of the face. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `value` |`string`| The tag of the face. | No |
|
||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face’s X axis be? | No |
|
||||
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face’s Y axis be? | No |
|
||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face's X axis be? | No |
|
||||
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face's Y axis be? | No |
|
||||
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
|
||||
| `solid` |[`Solid`](/docs/kcl/types/Solid)| The solid the face is on. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A face. | No |
|
||||
|
@ -59,23 +59,7 @@ Any KCL value.
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Number`| | No |
|
||||
| `value` |`number`| | No |
|
||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Int`| | No |
|
||||
| `value` |`integer`| | No |
|
||||
| `ty` |[`NumericType`](/docs/kcl/types/NumericType)| Any KCL value. | No |
|
||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
||||
|
||||
|
||||
@ -311,7 +295,7 @@ Data for an imported geometry.
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Function`| | No |
|
||||
| `memory` |[`ProgramMemory`](/docs/kcl/types/ProgramMemory)| Any KCL value. | No |
|
||||
| `memory` |[`EnvironmentRef`](/docs/kcl/types/EnvironmentRef)| Any KCL value. | No |
|
||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
||||
|
||||
|
||||
@ -351,6 +335,23 @@ Data for an imported geometry.
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Tombstone`| | No |
|
||||
| `value` |`null`| | No |
|
||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
||||
|
252
docs/kcl/types/NumericType.md
Normal file
@ -0,0 +1,252 @@
|
||||
---
|
||||
title: "NumericType"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**This schema accepts exactly one of the following:**
|
||||
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
**This schema accepts exactly one of the following:**
|
||||
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Count`| | No |
|
||||
|
||||
|
||||
----
|
||||
A unit of length.
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
**This schema accepts exactly one of the following:**
|
||||
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Mm`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Cm`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `M`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Inches`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Feet`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Yards`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Length`| | No |
|
||||
|
||||
|
||||
----
|
||||
A unit of angle.
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
**This schema accepts exactly one of the following:**
|
||||
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Degrees`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Radians`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Angle`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Known`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Default`| | No |
|
||||
| `len` |[`UnitLen`](/docs/kcl/types/UnitLen)| | No |
|
||||
| `angle` |[`UnitAngle`](/docs/kcl/types/UnitAngle)| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Unknown`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Any`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
@ -27,6 +27,7 @@ A path that goes to a point.
|
||||
| `type` |enum: `ToPoint`| | No |
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
@ -49,6 +50,7 @@ A arc that is tangential to the last path segment that goes to a point
|
||||
| `ccw` |`boolean`| arc's direction | No |
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
@ -71,6 +73,7 @@ A arc that is tangential to the last path segment
|
||||
| `ccw` |`boolean`| arc's direction | No |
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
@ -94,6 +97,31 @@ a complete arc
|
||||
| `ccw` |`boolean`| arc's direction This is used to compute the tangential angle. | No |
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
|
||||
----
|
||||
A base path.
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `CircleThreePoint`| | No |
|
||||
| `p1` |`[number, number]`| Point 1 of the circle | No |
|
||||
| `p2` |`[number, number]`| Point 2 of the circle | No |
|
||||
| `p3` |`[number, number]`| Point 3 of the circle | No |
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
@ -115,6 +143,7 @@ A path that is horizontal.
|
||||
| `x` |`number`| The x coordinate. | No |
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
@ -137,6 +166,7 @@ An angled line to.
|
||||
| `y` |`number`| The y coordinate. | No |
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
@ -157,6 +187,7 @@ A base path.
|
||||
| `type` |enum: `Base`| | No |
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
@ -180,6 +211,7 @@ A circular arc, not necessarily tangential to the current point.
|
||||
| `ccw` |`boolean`| True if the arc is counterclockwise. | No |
|
||||
| `from` |`[number, number]`| The from point. | No |
|
||||
| `to` |`[number, number]`| The to point. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A path. | No |
|
||||
| `tag` |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag of the path. | No |
|
||||
| `__geoMeta` |[`GeoMeta`](/docs/kcl/types/GeoMeta)| Metadata. | No |
|
||||
|
||||
|
@ -20,8 +20,8 @@ A plane.
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `value` |[`PlaneType`](/docs/kcl/types/PlaneType)| A plane. | No |
|
||||
| `origin` |[`Point3d`](/docs/kcl/types/Point3d)| Origin of the plane. | No |
|
||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane’s X axis be? | No |
|
||||
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane’s Y axis be? | No |
|
||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane's X axis be? | No |
|
||||
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane's Y axis be? | No |
|
||||
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A plane. | No |
|
||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
||||
|
@ -17,6 +17,5 @@ layout: manual
|
||||
|----------|------|-------------|----------|
|
||||
| `environments` |`[` [`Environment`](/docs/kcl/types/Environment) `]`| | No |
|
||||
| `currentEnv` |`integer`| | No |
|
||||
| `return` |[`KclValue`](/docs/kcl/types/KclValue)| | No |
|
||||
|
||||
|
||||
|
@ -6,6 +6,40 @@ layout: manual
|
||||
|
||||
A sketch is a collection of paths.
|
||||
|
||||
When you define a sketch to a variable like:
|
||||
|
||||
```kcl
|
||||
mySketch = startSketchOn('XY')
|
||||
|> startProfileAt([-12, 12], %)
|
||||
|> line(end = [24, 0])
|
||||
|> line(end = [0, -24])
|
||||
|> line(end = [-24, 0])
|
||||
|> close()
|
||||
```
|
||||
|
||||
The `mySketch` variable will be an executed [`Sketch`](/docs/kcl/types/Sketch) object. Executed being past tense, because the engine has already executed the commands to create the sketch.
|
||||
|
||||
The previous sketch commands will never be executed again, in this case.
|
||||
|
||||
If you would like to encapsulate the commands to create the sketch any time you call it, you can use a function.
|
||||
|
||||
```kcl
|
||||
fn createSketch() {
|
||||
return startSketchOn('XY')
|
||||
|> startProfileAt([-12, 12], %)
|
||||
|> line(end = [24, 0])
|
||||
|> line(end = [0, -24])
|
||||
|> line(end = [-24, 0])
|
||||
|> close()
|
||||
}
|
||||
```
|
||||
|
||||
Now, every time you call `createSketch()`, the commands will be executed and a new sketch will be created.
|
||||
|
||||
When you assign the result of `createSketch()` to a variable (`mySketch = createSketch()`), you are assigning the executed sketch to that variable. Meaning that the sketch `mySketch` will not be executed again.
|
||||
|
||||
You can still execute _new_ commands on the sketch like `extrude`, `revolve`, `loft`, etc. and the sketch will be updated.
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
@ -14,6 +14,40 @@ A sketch or a group of sketches.
|
||||
|
||||
A sketch is a collection of paths.
|
||||
|
||||
When you define a sketch to a variable like:
|
||||
|
||||
```kcl
|
||||
mySketch = startSketchOn('XY')
|
||||
|> startProfileAt([-12, 12], %)
|
||||
|> line(end = [24, 0])
|
||||
|> line(end = [0, -24])
|
||||
|> line(end = [-24, 0])
|
||||
|> close()
|
||||
```
|
||||
|
||||
The `mySketch` variable will be an executed [`Sketch`](/docs/kcl/types/Sketch) object. Executed being past tense, because the engine has already executed the commands to create the sketch.
|
||||
|
||||
The previous sketch commands will never be executed again, in this case.
|
||||
|
||||
If you would like to encapsulate the commands to create the sketch any time you call it, you can use a function.
|
||||
|
||||
```kcl
|
||||
fn createSketch() {
|
||||
return startSketchOn('XY')
|
||||
|> startProfileAt([-12, 12], %)
|
||||
|> line(end = [24, 0])
|
||||
|> line(end = [0, -24])
|
||||
|> line(end = [-24, 0])
|
||||
|> close()
|
||||
}
|
||||
```
|
||||
|
||||
Now, every time you call `createSketch()`, the commands will be executed and a new sketch will be created.
|
||||
|
||||
When you assign the result of `createSketch()` to a variable (`mySketch = createSketch()`), you are assigning the executed sketch to that variable. Meaning that the sketch `mySketch` will not be executed again.
|
||||
|
||||
You can still execute _new_ commands on the sketch like `extrude`, `revolve`, `loft`, etc. and the sketch will be updated.
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
@ -29,8 +29,8 @@ A plane.
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `value` |[`PlaneType`](/docs/kcl/types/PlaneType)| A sketch type. | No |
|
||||
| `origin` |[`Point3d`](/docs/kcl/types/Point3d)| Origin of the plane. | No |
|
||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane’s X axis be? | No |
|
||||
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane’s Y axis be? | No |
|
||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane's X axis be? | No |
|
||||
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane's Y axis be? | No |
|
||||
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch type. | No |
|
||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
|
||||
@ -53,8 +53,8 @@ A face.
|
||||
| `id` |`string`| The id of the face. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `value` |`string`| The tag of the face. | No |
|
||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face’s X axis be? | No |
|
||||
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face’s Y axis be? | No |
|
||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face's X axis be? | No |
|
||||
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face's Y axis be? | No |
|
||||
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
|
||||
| `solid` |[`Solid`](/docs/kcl/types/Solid)| The solid the face is on. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch type. | No |
|
||||
|
16
docs/kcl/types/SnapshotRef.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "SnapshotRef"
|
||||
excerpt: "An index pointing to a snapshot within a specific (unspecified) environment."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
An index pointing to a snapshot within a specific (unspecified) environment.
|
||||
|
||||
**Type:** `integer` (`uint`)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,10 +1,46 @@
|
||||
---
|
||||
title: "Solid"
|
||||
excerpt: "An solid is a collection of extrude surfaces."
|
||||
excerpt: "A solid is a collection of extrude surfaces."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
An solid is a collection of extrude surfaces.
|
||||
A solid is a collection of extrude surfaces.
|
||||
|
||||
When you define a solid to a variable like:
|
||||
|
||||
```kcl
|
||||
myPart = startSketchOn('XY')
|
||||
|> startProfileAt([-12, 12], %)
|
||||
|> line(end = [24, 0])
|
||||
|> line(end = [0, -24])
|
||||
|> line(end = [-24, 0])
|
||||
|> close()
|
||||
|> extrude(length = 6)
|
||||
```
|
||||
|
||||
The `myPart` variable will be an executed [`Solid`](/docs/kcl/types/Solid) object. Executed being past tense, because the engine has already executed the commands to create the solid.
|
||||
|
||||
The previous solid commands will never be executed again, in this case.
|
||||
|
||||
If you would like to encapsulate the commands to create the solid any time you call it, you can use a function.
|
||||
|
||||
```kcl
|
||||
fn createPart() {
|
||||
return startSketchOn('XY')
|
||||
|> startProfileAt([-12, 12], %)
|
||||
|> line(end = [24, 0])
|
||||
|> line(end = [0, -24])
|
||||
|> line(end = [-24, 0])
|
||||
|> close()
|
||||
|> extrude(length = 6)
|
||||
}
|
||||
```
|
||||
|
||||
Now, every time you call `createPart()`, the commands will be executed and a new solid will be created.
|
||||
|
||||
When you assign the result of `createPart()` to a variable (`myPart = createPart()`), you are assigning the executed solid to that variable. Meaning that the solid `myPart` will not be executed again.
|
||||
|
||||
You can still execute _new_ commands on the solid like `shell`, `fillet`, `chamfer`, etc. and the solid will be updated.
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
@ -24,7 +60,7 @@ An solid is a collection of extrude surfaces.
|
||||
| `startCapId` |`string`| The id of the extrusion start cap | No |
|
||||
| `endCapId` |`string`| The id of the extrusion end cap | No |
|
||||
| `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| An solid is a collection of extrude surfaces. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A solid is a collection of extrude surfaces. | No |
|
||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |
|
||||
|
||||
|
||||
|
@ -12,7 +12,43 @@ A solid or a group of solids.
|
||||
|
||||
**This schema accepts exactly one of the following:**
|
||||
|
||||
An solid is a collection of extrude surfaces.
|
||||
A solid is a collection of extrude surfaces.
|
||||
|
||||
When you define a solid to a variable like:
|
||||
|
||||
```kcl
|
||||
myPart = startSketchOn('XY')
|
||||
|> startProfileAt([-12, 12], %)
|
||||
|> line(end = [24, 0])
|
||||
|> line(end = [0, -24])
|
||||
|> line(end = [-24, 0])
|
||||
|> close()
|
||||
|> extrude(length = 6)
|
||||
```
|
||||
|
||||
The `myPart` variable will be an executed [`Solid`](/docs/kcl/types/Solid) object. Executed being past tense, because the engine has already executed the commands to create the solid.
|
||||
|
||||
The previous solid commands will never be executed again, in this case.
|
||||
|
||||
If you would like to encapsulate the commands to create the solid any time you call it, you can use a function.
|
||||
|
||||
```kcl
|
||||
fn createPart() {
|
||||
return startSketchOn('XY')
|
||||
|> startProfileAt([-12, 12], %)
|
||||
|> line(end = [24, 0])
|
||||
|> line(end = [0, -24])
|
||||
|> line(end = [-24, 0])
|
||||
|> close()
|
||||
|> extrude(length = 6)
|
||||
}
|
||||
```
|
||||
|
||||
Now, every time you call `createPart()`, the commands will be executed and a new solid will be created.
|
||||
|
||||
When you assign the result of `createPart()` to a variable (`myPart = createPart()`), you are assigning the executed solid to that variable. Meaning that the solid `myPart` will not be executed again.
|
||||
|
||||
You can still execute _new_ commands on the solid like `shell`, `fillet`, `chamfer`, etc. and the solid will be updated.
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
48
docs/kcl/types/UnitAngle.md
Normal file
@ -0,0 +1,48 @@
|
||||
---
|
||||
title: "UnitAngle"
|
||||
excerpt: "A unit of angle."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
A unit of angle.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**This schema accepts exactly one of the following:**
|
||||
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Degrees`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Radians`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
---
|
||||
title: "UnitLen"
|
||||
excerpt: ""
|
||||
excerpt: "A unit of length."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
A unit of length.
|
||||
|
||||
|
||||
|
||||
|
186
docs/kcl/types/UnitType.md
Normal file
@ -0,0 +1,186 @@
|
||||
---
|
||||
title: "UnitType"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**This schema accepts exactly one of the following:**
|
||||
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Count`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
**This schema accepts exactly one of the following:**
|
||||
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Mm`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Cm`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `M`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Inches`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Feet`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Yards`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Length`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
**This schema accepts exactly one of the following:**
|
||||
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Degrees`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Radians`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `Angle`| | No |
|
||||
|
||||
|
||||
----
|
||||
|
||||
|
||||
|
||||
|
@ -54,23 +54,26 @@ async function doBasicSketch(
|
||||
const startXPx = 600
|
||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||
if (openPanes.includes('code')) {
|
||||
await expect(u.codeLocator).toHaveText(`sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt(${commonPoints.startAt}, %)`)
|
||||
await expect(u.codeLocator).toContainText(
|
||||
`sketch001 = startSketchOn('XZ')profile001 = startProfileAt(${commonPoints.startAt}, sketch001)`
|
||||
)
|
||||
}
|
||||
await page.waitForTimeout(500)
|
||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
if (openPanes.includes('code')) {
|
||||
await expect(u.codeLocator).toHaveText(`sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt(${commonPoints.startAt}, %)
|
||||
await expect(u.codeLocator)
|
||||
.toHaveText(`sketch001 = startSketchOn('XZ')profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|
||||
|> xLine(${commonPoints.num1}, %)`)
|
||||
}
|
||||
await page.waitForTimeout(500)
|
||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
||||
if (openPanes.includes('code')) {
|
||||
await expect(u.codeLocator).toHaveText(`sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt(${commonPoints.startAt}, %)
|
||||
await expect(u.codeLocator)
|
||||
.toHaveText(`sketch001 = startSketchOn('XZ')profile001 = startProfileAt(${
|
||||
commonPoints.startAt
|
||||
}, sketch001)
|
||||
|> xLine(${commonPoints.num1}, %)
|
||||
|> yLine(${commonPoints.num1 + 0.01}, %)`)
|
||||
} else {
|
||||
@ -79,8 +82,10 @@ async function doBasicSketch(
|
||||
await page.waitForTimeout(200)
|
||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
||||
if (openPanes.includes('code')) {
|
||||
await expect(u.codeLocator).toHaveText(`sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt(${commonPoints.startAt}, %)
|
||||
await expect(u.codeLocator)
|
||||
.toHaveText(`sketch001 = startSketchOn('XZ')profile001 = startProfileAt(${
|
||||
commonPoints.startAt
|
||||
}, sketch001)
|
||||
|> xLine(${commonPoints.num1}, %)
|
||||
|> yLine(${commonPoints.num1 + 0.01}, %)
|
||||
|> xLine(${commonPoints.num2 * -1}, %)`)
|
||||
@ -137,8 +142,10 @@ async function doBasicSketch(
|
||||
|
||||
// Open the code pane.
|
||||
await u.openKclCodePanel()
|
||||
await expect(u.codeLocator).toHaveText(`sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt(${commonPoints.startAt}, %)
|
||||
await expect(u.codeLocator)
|
||||
.toHaveText(`sketch001 = startSketchOn('XZ')profile001 = startProfileAt(${
|
||||
commonPoints.startAt
|
||||
}, sketch001)
|
||||
|> xLine(${commonPoints.num1}, %, $seg01)
|
||||
|> yLine(${commonPoints.num1 + 0.01}, %)
|
||||
|> xLine(-segLen(seg01), %)`)
|
||||
|
@ -43,8 +43,7 @@ test.describe(
|
||||
},
|
||||
}
|
||||
|
||||
const code = `sketch001 = startSketchOn('${plane}')
|
||||
|> startProfileAt([0.9, -1.22], %)`
|
||||
const code = `sketch001 = startSketchOn('${plane}')profile001 = startProfileAt([0.9, -1.22], sketch001)`
|
||||
|
||||
await u.openDebugPanel()
|
||||
|
||||
|
@ -24,7 +24,7 @@ sketch001 = startSketchOn('XZ')
|
||||
revolve001 = revolve({ axis = "X" }, sketch001)
|
||||
triangle()
|
||||
|> extrude(length = 30)
|
||||
plane001 = offsetPlane('XY', 10)
|
||||
plane001 = offsetPlane('XY', offset = 10)
|
||||
sketch002 = startSketchOn(plane001)
|
||||
|> startProfileAt([-20, 0], %)
|
||||
|> line(end = [5, -15])
|
||||
@ -35,7 +35,7 @@ sketch002 = startSketchOn(plane001)
|
||||
extrude001 = extrude(sketch002, length = 10)
|
||||
`
|
||||
|
||||
const FEAUTRE_TREE_SKETCH_CODE = `sketch001 = startSketchOn('XZ')
|
||||
const FEATURE_TREE_SKETCH_CODE = `sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLine([0, 4], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
@ -54,7 +54,7 @@ sketch002 = startSketchOn(extrude001, rectangleSegmentB001)
|
||||
center = [-1, 2],
|
||||
radius = .5
|
||||
}, %)
|
||||
plane001 = offsetPlane('XZ', -5)
|
||||
plane001 = offsetPlane('XZ', offset = -5)
|
||||
sketch003 = startSketchOn(plane001)
|
||||
|> circle({ center = [0, 0], radius = 5 }, %)
|
||||
`
|
||||
@ -116,7 +116,7 @@ test.describe('Feature Tree pane', () => {
|
||||
await testViewSource({
|
||||
operationName: 'Offset Plane',
|
||||
operationIndex: 0,
|
||||
expectedActiveLine: "plane001 = offsetPlane('XY', 10)",
|
||||
expectedActiveLine: "plane001 = offsetPlane('XY', offset = 10)",
|
||||
})
|
||||
await testViewSource({
|
||||
operationName: 'Extrude',
|
||||
@ -153,33 +153,16 @@ test.describe('Feature Tree pane', () => {
|
||||
`User can edit sketch (but not on offset plane yet) from the feature tree`,
|
||||
{ tag: '@electron' },
|
||||
async ({ context, homePage, scene, editor, toolbar, page }) => {
|
||||
const unavailableToastMessage = page.getByText(
|
||||
'Editing sketches on faces or offset planes through the feature tree is not yet supported'
|
||||
)
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, FEATURE_TREE_SKETCH_CODE)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'test-sample')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
await fsp.writeFile(
|
||||
join(bracketDir, 'main.kcl'),
|
||||
FEAUTRE_TREE_SKETCH_CODE,
|
||||
'utf-8'
|
||||
)
|
||||
})
|
||||
|
||||
await test.step('setup test', async () => {
|
||||
await homePage.expectState({
|
||||
projectCards: [
|
||||
{
|
||||
title: 'test-sample',
|
||||
fileCount: 1,
|
||||
},
|
||||
],
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
await toolbar.openFeatureTreePane()
|
||||
await test.step('force re-exe', async () => {
|
||||
await page.waitForTimeout(1000)
|
||||
await editor.replaceCode('90', '91')
|
||||
await page.waitForTimeout(1500)
|
||||
})
|
||||
|
||||
await test.step('On a default plane should work', async () => {
|
||||
@ -199,24 +182,23 @@ test.describe('Feature Tree pane', () => {
|
||||
await test.step('On an extrude face should *not* work', async () => {
|
||||
// Tooltip is getting in the way of clicking, so I'm first closing the pane
|
||||
await toolbar.closeFeatureTreePane()
|
||||
await page.waitForTimeout(1000)
|
||||
await editor.replaceCode('91', '90')
|
||||
await page.waitForTimeout(2000)
|
||||
await (await toolbar.getFeatureTreeOperation('Sketch', 1)).dblclick()
|
||||
|
||||
await expect(
|
||||
unavailableToastMessage,
|
||||
'We should see a toast message about this'
|
||||
toolbar.exitSketchBtn,
|
||||
'We should be in sketch mode now'
|
||||
).toBeVisible()
|
||||
await unavailableToastMessage.waitFor({ state: 'detached' })
|
||||
// TODO - turn on once we update the artifactGraph in Rust
|
||||
// to include the proper source location for the extrude face
|
||||
// await expect(
|
||||
// toolbar.exitSketchBtn,
|
||||
// 'We should be in sketch mode now'
|
||||
// ).toBeVisible()
|
||||
// await editor.expectState({
|
||||
// highlightedCode: '',
|
||||
// diagnostics: [],
|
||||
// activeLines: ['|>circle({center=[-1,2],radius=.5},%)'],
|
||||
// })
|
||||
// await toolbar.exitSketchBtn.click()
|
||||
await editor.expectState({
|
||||
highlightedCode: '',
|
||||
diagnostics: [],
|
||||
activeLines: [
|
||||
'sketch002=startSketchOn(extrude001,rectangleSegmentB001)',
|
||||
],
|
||||
})
|
||||
await toolbar.exitSketchBtn.click()
|
||||
})
|
||||
|
||||
await test.step('On an offset plane should *not* work', async () => {
|
||||
@ -226,7 +208,7 @@ test.describe('Feature Tree pane', () => {
|
||||
await editor.expectState({
|
||||
highlightedCode: '',
|
||||
diagnostics: [],
|
||||
activeLines: ['|>circle({center=[0,0],radius=5},%)'],
|
||||
activeLines: ['sketch003=startSketchOn(plane001)'],
|
||||
})
|
||||
await expect(
|
||||
toolbar.exitSketchBtn,
|
||||
@ -342,7 +324,8 @@ test.describe('Feature Tree pane', () => {
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const testCode = (value: string) => `p = offsetPlane('XY', ${value})`
|
||||
const testCode = (value: string) =>
|
||||
`p = offsetPlane('XY', offset = ${value})`
|
||||
const initialInput = '10'
|
||||
const initialCode = testCode(initialInput)
|
||||
const newInput = '5 + 10'
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { Page, Locator } from '@playwright/test'
|
||||
import { expect } from '@playwright/test'
|
||||
import { uuidv4 } from 'lib/utils'
|
||||
import { isArray, uuidv4 } from 'lib/utils'
|
||||
import {
|
||||
closeDebugPanel,
|
||||
doAndWaitForImageDiff,
|
||||
@ -9,13 +9,15 @@ import {
|
||||
sendCustomCmd,
|
||||
} from '../test-utils'
|
||||
|
||||
type mouseParams = {
|
||||
type MouseParams = {
|
||||
pixelDiff?: number
|
||||
shouldDbClick?: boolean
|
||||
delay?: number
|
||||
}
|
||||
type mouseDragToParams = mouseParams & {
|
||||
type MouseDragToParams = MouseParams & {
|
||||
fromPoint: { x: number; y: number }
|
||||
}
|
||||
type mouseDragFromParams = mouseParams & {
|
||||
type MouseDragFromParams = MouseParams & {
|
||||
toPoint: { x: number; y: number }
|
||||
}
|
||||
|
||||
@ -26,12 +28,12 @@ type SceneSerialised = {
|
||||
}
|
||||
}
|
||||
|
||||
type ClickHandler = (clickParams?: mouseParams) => Promise<void | boolean>
|
||||
type MoveHandler = (moveParams?: mouseParams) => Promise<void | boolean>
|
||||
type DblClickHandler = (clickParams?: mouseParams) => Promise<void | boolean>
|
||||
type DragToHandler = (dragParams: mouseDragToParams) => Promise<void | boolean>
|
||||
type ClickHandler = (clickParams?: MouseParams) => Promise<void | boolean>
|
||||
type MoveHandler = (moveParams?: MouseParams) => Promise<void | boolean>
|
||||
type DblClickHandler = (clickParams?: MouseParams) => Promise<void | boolean>
|
||||
type DragToHandler = (dragParams: MouseDragToParams) => Promise<void | boolean>
|
||||
type DragFromHandler = (
|
||||
dragParams: mouseDragFromParams
|
||||
dragParams: MouseDragFromParams
|
||||
) => Promise<void | boolean>
|
||||
|
||||
export class SceneFixture {
|
||||
@ -77,17 +79,26 @@ export class SceneFixture {
|
||||
{ steps }: { steps: number } = { steps: 20 }
|
||||
): [ClickHandler, MoveHandler, DblClickHandler] =>
|
||||
[
|
||||
(clickParams?: mouseParams) => {
|
||||
(clickParams?: MouseParams) => {
|
||||
if (clickParams?.pixelDiff) {
|
||||
return doAndWaitForImageDiff(
|
||||
this.page,
|
||||
() => this.page.mouse.click(x, y),
|
||||
() =>
|
||||
clickParams?.shouldDbClick
|
||||
? this.page.mouse.dblclick(x, y, {
|
||||
delay: clickParams?.delay || 0,
|
||||
})
|
||||
: this.page.mouse.click(x, y, {
|
||||
delay: clickParams?.delay || 0,
|
||||
}),
|
||||
clickParams.pixelDiff
|
||||
)
|
||||
}
|
||||
return this.page.mouse.click(x, y)
|
||||
return clickParams?.shouldDbClick
|
||||
? this.page.mouse.dblclick(x, y, { delay: clickParams?.delay || 0 })
|
||||
: this.page.mouse.click(x, y, { delay: clickParams?.delay || 0 })
|
||||
},
|
||||
(moveParams?: mouseParams) => {
|
||||
(moveParams?: MouseParams) => {
|
||||
if (moveParams?.pixelDiff) {
|
||||
return doAndWaitForImageDiff(
|
||||
this.page,
|
||||
@ -97,7 +108,7 @@ export class SceneFixture {
|
||||
}
|
||||
return this.page.mouse.move(x, y, { steps })
|
||||
},
|
||||
(clickParams?: mouseParams) => {
|
||||
(clickParams?: MouseParams) => {
|
||||
if (clickParams?.pixelDiff) {
|
||||
return doAndWaitForImageDiff(
|
||||
this.page,
|
||||
@ -114,7 +125,7 @@ export class SceneFixture {
|
||||
{ steps }: { steps: number } = { steps: 20 }
|
||||
): [DragToHandler, DragFromHandler] =>
|
||||
[
|
||||
(dragToParams: mouseDragToParams) => {
|
||||
(dragToParams: MouseDragToParams) => {
|
||||
if (dragToParams?.pixelDiff) {
|
||||
return doAndWaitForImageDiff(
|
||||
this.page,
|
||||
@ -131,7 +142,7 @@ export class SceneFixture {
|
||||
targetPosition: { x, y },
|
||||
})
|
||||
},
|
||||
(dragFromParams: mouseDragFromParams) => {
|
||||
(dragFromParams: MouseDragFromParams) => {
|
||||
if (dragFromParams?.pixelDiff) {
|
||||
return doAndWaitForImageDiff(
|
||||
this.page,
|
||||
@ -219,7 +230,7 @@ export class SceneFixture {
|
||||
}
|
||||
|
||||
expectPixelColor = async (
|
||||
colour: [number, number, number],
|
||||
colour: [number, number, number] | [number, number, number][],
|
||||
coords: { x: number; y: number },
|
||||
diff: number
|
||||
) => {
|
||||
@ -241,22 +252,36 @@ export class SceneFixture {
|
||||
}
|
||||
}
|
||||
|
||||
function isColourArray(
|
||||
colour: [number, number, number] | [number, number, number][]
|
||||
): colour is [number, number, number][] {
|
||||
return isArray(colour[0])
|
||||
}
|
||||
|
||||
export async function expectPixelColor(
|
||||
page: Page,
|
||||
colour: [number, number, number],
|
||||
colour: [number, number, number] | [number, number, number][],
|
||||
coords: { x: number; y: number },
|
||||
diff: number
|
||||
) {
|
||||
let finalValue = colour
|
||||
await expect
|
||||
.poll(async () => {
|
||||
const pixel = (await getPixelRGBs(page)(coords, 1))[0]
|
||||
if (!pixel) return null
|
||||
finalValue = pixel
|
||||
return pixel.every(
|
||||
(channel, index) => Math.abs(channel - colour[index]) < diff
|
||||
)
|
||||
})
|
||||
.poll(
|
||||
async () => {
|
||||
const pixel = (await getPixelRGBs(page)(coords, 1))[0]
|
||||
if (!pixel) return null
|
||||
finalValue = pixel
|
||||
if (!isColourArray(colour)) {
|
||||
return pixel.every(
|
||||
(channel, index) => Math.abs(channel - colour[index]) < diff
|
||||
)
|
||||
}
|
||||
return colour.some((c) =>
|
||||
c.every((channel, index) => Math.abs(pixel[index] - channel) < diff)
|
||||
)
|
||||
},
|
||||
{ timeout: 10_000 }
|
||||
)
|
||||
.toBeTruthy()
|
||||
.catch((cause) => {
|
||||
throw new Error(
|
||||
|
@ -23,7 +23,10 @@ export class ToolbarFixture {
|
||||
helixButton!: Locator
|
||||
startSketchBtn!: Locator
|
||||
lineBtn!: Locator
|
||||
tangentialArcBtn!: Locator
|
||||
circleBtn!: Locator
|
||||
rectangleBtn!: Locator
|
||||
lengthConstraintBtn!: Locator
|
||||
exitSketchBtn!: Locator
|
||||
editSketchBtn!: Locator
|
||||
fileTreeBtn!: Locator
|
||||
@ -53,7 +56,10 @@ export class ToolbarFixture {
|
||||
this.helixButton = page.getByTestId('helix')
|
||||
this.startSketchBtn = page.getByTestId('sketch')
|
||||
this.lineBtn = page.getByTestId('line')
|
||||
this.tangentialArcBtn = page.getByTestId('tangential-arc')
|
||||
this.circleBtn = page.getByTestId('circle-center')
|
||||
this.rectangleBtn = page.getByTestId('corner-rectangle')
|
||||
this.lengthConstraintBtn = page.getByTestId('constraint-length')
|
||||
this.exitSketchBtn = page.getByTestId('sketch-exit')
|
||||
this.editSketchBtn = page.getByText('Edit Sketch')
|
||||
this.fileTreeBtn = page.locator('[id="files-button-holder"]')
|
||||
@ -119,6 +125,25 @@ export class ToolbarFixture {
|
||||
await expect(this.exeIndicator).toBeVisible({ timeout: 15_000 })
|
||||
}
|
||||
}
|
||||
selectCenterRectangle = async () => {
|
||||
await this.page
|
||||
.getByRole('button', { name: 'caret down Corner rectangle:' })
|
||||
.click()
|
||||
await expect(
|
||||
this.page.getByTestId('dropdown-center-rectangle')
|
||||
).toBeVisible()
|
||||
await this.page.getByTestId('dropdown-center-rectangle').click()
|
||||
}
|
||||
|
||||
selectCircleThreePoint = async () => {
|
||||
await this.page
|
||||
.getByRole('button', { name: 'caret down Center circle:' })
|
||||
.click()
|
||||
await expect(
|
||||
this.page.getByTestId('dropdown-circle-three-points')
|
||||
).toBeVisible()
|
||||
await this.page.getByTestId('dropdown-circle-three-points').click()
|
||||
}
|
||||
|
||||
async closePane(paneId: SidebarType) {
|
||||
return closePane(this.page, paneId + SIDEBAR_BUTTON_SUFFIX)
|
||||
|
@ -5,6 +5,7 @@ import { ToolbarFixture } from './fixtures/toolbarFixture'
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { getUtils } from './test-utils'
|
||||
import { Locator } from '@playwright/test'
|
||||
|
||||
// test file is for testing point an click code gen functionality that's not sketch mode related
|
||||
|
||||
@ -219,18 +220,13 @@ test.describe('Point-and-click tests', { tag: ['@skipWin'] }, () => {
|
||||
|
||||
afterChamferSelectSnippet:
|
||||
'sketch002 = startSketchOn(extrude001, seg03)',
|
||||
afterRectangle1stClickSnippet: 'startProfileAt([205.96, 254.59], %)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0, 11.39], %, $rectangleSegmentA002)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002) - 90,
|
||||
105.26
|
||||
], %, $rectangleSegmentB001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002),
|
||||
-segLen(rectangleSegmentA002)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()`,
|
||||
afterRectangle1stClickSnippet:
|
||||
'startProfileAt([205.96, 254.59], sketch002)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0,11.39],%,$rectangleSegmentA002)
|
||||
|>angledLine([segAng(rectangleSegmentA002)-90,105.26],%)
|
||||
|>angledLine([segAng(rectangleSegmentA002),-segLen(rectangleSegmentA002)],%)
|
||||
|>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|
||||
|>close()`,
|
||||
})
|
||||
|
||||
await sketchOnAChamfer({
|
||||
@ -251,19 +247,15 @@ test.describe('Point-and-click tests', { tag: ['@skipWin'] }, () => {
|
||||
|
||||
afterChamferSelectSnippet:
|
||||
'sketch003 = startSketchOn(extrude001, seg04)',
|
||||
afterRectangle1stClickSnippet: 'startProfileAt([-209.64, 255.28], %)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0, 11.56], %, $rectangleSegmentA003)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA003) - 90,
|
||||
106.84
|
||||
], %, $rectangleSegmentB002)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA003),
|
||||
-segLen(rectangleSegmentA003)
|
||||
], %, $rectangleSegmentC002)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()`,
|
||||
afterRectangle1stClickSnippet:
|
||||
'startProfileAt([-209.64, 255.28], sketch003)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0,11.56],%,$rectangleSegmentA003)
|
||||
|>angledLine([segAng(rectangleSegmentA003)-90,106.84],%)
|
||||
|>angledLine([segAng(rectangleSegmentA003),-segLen(rectangleSegmentA003)],%)
|
||||
|>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|
||||
|>close()`,
|
||||
})
|
||||
|
||||
await sketchOnAChamfer({
|
||||
clickCoords: { x: 677, y: 87 },
|
||||
cameraPos: { x: -6200, y: 1500, z: 6200 },
|
||||
@ -276,19 +268,14 @@ test.describe('Point-and-click tests', { tag: ['@skipWin'] }, () => {
|
||||
]
|
||||
}, %)`,
|
||||
afterChamferSelectSnippet:
|
||||
'sketch003 = startSketchOn(extrude001, seg04)',
|
||||
afterRectangle1stClickSnippet: 'startProfileAt([75.8, 317.2], %)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0, 11.56], %, $rectangleSegmentA003)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA003) - 90,
|
||||
106.84
|
||||
], %, $rectangleSegmentB002)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA003),
|
||||
-segLen(rectangleSegmentA003)
|
||||
], %, $rectangleSegmentC002)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()`,
|
||||
'sketch004 = startSketchOn(extrude001, seg05)',
|
||||
afterRectangle1stClickSnippet:
|
||||
'startProfileAt([82.57, 322.96], sketch004)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0,11.16],%,$rectangleSegmentA004)
|
||||
|>angledLine([segAng(rectangleSegmentA004)-90,103.07],%)
|
||||
|>angledLine([segAng(rectangleSegmentA004),-segLen(rectangleSegmentA004)],%)
|
||||
|>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|
||||
|>close()`,
|
||||
})
|
||||
/// last one
|
||||
await sketchOnAChamfer({
|
||||
@ -301,104 +288,98 @@ test.describe('Point-and-click tests', { tag: ['@skipWin'] }, () => {
|
||||
}, %)`,
|
||||
afterChamferSelectSnippet:
|
||||
'sketch005 = startSketchOn(extrude001, seg06)',
|
||||
afterRectangle1stClickSnippet: 'startProfileAt([-23.43, 19.69], %)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0, 9.1], %, $rectangleSegmentA005)
|
||||
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA005) - 90,
|
||||
84.07
|
||||
], %, $rectangleSegmentB004)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA005),
|
||||
-segLen(rectangleSegmentA005)
|
||||
], %, $rectangleSegmentC004)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()`,
|
||||
afterRectangle1stClickSnippet:
|
||||
'startProfileAt([-23.43, 19.69], sketch005)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0,9.1],%,$rectangleSegmentA005)
|
||||
|>angledLine([segAng(rectangleSegmentA005)-90,84.07],%)
|
||||
|>angledLine([segAng(rectangleSegmentA005),-segLen(rectangleSegmentA005)],%)
|
||||
|>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|
||||
|>close()`,
|
||||
})
|
||||
|
||||
await test.step('verify at the end of the test that final code is what is expected', async () => {
|
||||
await editor.expectEditor.toContain(
|
||||
`sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag]
|
||||
|> angledLine([0, 268.43], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001) - 90,
|
||||
217.26
|
||||
], %, $seg01)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001),
|
||||
-segLen(rectangleSegmentA001)
|
||||
], %, $yo)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|
||||
|> close()
|
||||
extrude001 = extrude(sketch001, length = 100)
|
||||
|> chamfer({
|
||||
length = 30,
|
||||
tags = [getOppositeEdge(seg01)]
|
||||
}, %, $seg03)
|
||||
|> chamfer({ length = 30, tags = [seg01] }, %, $seg04)
|
||||
|> chamfer({
|
||||
length = 30,
|
||||
tags = [getNextAdjacentEdge(seg02)]
|
||||
}, %, $seg05)
|
||||
|> chamfer({
|
||||
length = 30,
|
||||
tags = [getNextAdjacentEdge(yo)]
|
||||
}, %, $seg06)
|
||||
sketch005 = startSketchOn(extrude001, seg06)
|
||||
profile004 = startProfileAt([-23.43, 19.69], sketch005)
|
||||
|> angledLine([0, 9.1], %, $rectangleSegmentA005)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA005) - 90,
|
||||
84.07
|
||||
], %)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA005),
|
||||
-segLen(rectangleSegmentA005)
|
||||
], %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
sketch004 = startSketchOn(extrude001, seg05)
|
||||
profile003 = startProfileAt([82.57, 322.96], sketch004)
|
||||
|> angledLine([0, 11.16], %, $rectangleSegmentA004)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA004) - 90,
|
||||
103.07
|
||||
], %)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA004),
|
||||
-segLen(rectangleSegmentA004)
|
||||
], %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
sketch003 = startSketchOn(extrude001, seg04)
|
||||
profile002 = startProfileAt([-209.64, 255.28], sketch003)
|
||||
|> angledLine([0, 11.56], %, $rectangleSegmentA003)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA003) - 90,
|
||||
106.84
|
||||
], %)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA003),
|
||||
-segLen(rectangleSegmentA003)
|
||||
], %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
sketch002 = startSketchOn(extrude001, seg03)
|
||||
profile001 = startProfileAt([205.96, 254.59], sketch002)
|
||||
|> angledLine([0, 11.39], %, $rectangleSegmentA002)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002) - 90,
|
||||
105.26
|
||||
], %)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002),
|
||||
-segLen(rectangleSegmentA002)
|
||||
], %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
|> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag]
|
||||
|> angledLine([0, 268.43], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001) - 90,
|
||||
217.26
|
||||
], %, $seg01)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001),
|
||||
-segLen(rectangleSegmentA001)
|
||||
], %, $yo)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|
||||
|> close()
|
||||
extrude001 = extrude(sketch001, length = 100)
|
||||
|> chamfer({
|
||||
length = 30,
|
||||
tags = [getOppositeEdge(seg01)]
|
||||
}, %, $seg03)
|
||||
|> chamfer({ length = 30, tags = [seg01] }, %, $seg04)
|
||||
|> chamfer({
|
||||
length = 30,
|
||||
tags = [getNextAdjacentEdge(seg02)]
|
||||
}, %, $seg05)
|
||||
|> chamfer({
|
||||
length = 30,
|
||||
tags = [getNextAdjacentEdge(yo)]
|
||||
}, %, $seg06)
|
||||
sketch005 = startSketchOn(extrude001, seg06)
|
||||
|> startProfileAt([-23.43,19.69], %)
|
||||
|> angledLine([0, 9.1], %, $rectangleSegmentA005)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA005) - 90,
|
||||
84.07
|
||||
], %, $rectangleSegmentB004)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA005),
|
||||
-segLen(rectangleSegmentA005)
|
||||
], %, $rectangleSegmentC004)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
sketch004 = startSketchOn(extrude001, seg05)
|
||||
|> startProfileAt([82.57,322.96], %)
|
||||
|> angledLine([0, 11.16], %, $rectangleSegmentA004)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA004) - 90,
|
||||
103.07
|
||||
], %, $rectangleSegmentB003)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA004),
|
||||
-segLen(rectangleSegmentA004)
|
||||
], %, $rectangleSegmentC003)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
sketch003 = startSketchOn(extrude001, seg04)
|
||||
|> startProfileAt([-209.64,255.28], %)
|
||||
|> angledLine([0, 11.56], %, $rectangleSegmentA003)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA003) - 90,
|
||||
106.84
|
||||
], %, $rectangleSegmentB002)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA003),
|
||||
-segLen(rectangleSegmentA003)
|
||||
], %, $rectangleSegmentC002)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
sketch002 = startSketchOn(extrude001, seg03)
|
||||
|> startProfileAt([205.96,254.59], %)
|
||||
|> angledLine([0, 11.39], %, $rectangleSegmentA002)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002) - 90,
|
||||
105.26
|
||||
], %, $rectangleSegmentB001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002),
|
||||
-segLen(rectangleSegmentA002)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
`,
|
||||
`,
|
||||
{ shouldNormalise: true }
|
||||
)
|
||||
})
|
||||
@ -443,18 +424,13 @@ test.describe('Point-and-click tests', { tag: ['@skipWin'] }, () => {
|
||||
beforeChamferSnippetEnd: '}, extrude001)',
|
||||
afterChamferSelectSnippet:
|
||||
'sketch002 = startSketchOn(extrude001, seg03)',
|
||||
afterRectangle1stClickSnippet: 'startProfileAt([205.96, 254.59], %)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0, 11.39], %, $rectangleSegmentA002)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002) - 90,
|
||||
105.26
|
||||
], %, $rectangleSegmentB001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002),
|
||||
-segLen(rectangleSegmentA002)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()`,
|
||||
afterRectangle1stClickSnippet:
|
||||
'startProfileAt([205.96, 254.59], sketch002)',
|
||||
afterRectangle2ndClickSnippet: `angledLine([0,11.39],%,$rectangleSegmentA002)
|
||||
|>angledLine([segAng(rectangleSegmentA002)-90,105.26],%)
|
||||
|>angledLine([segAng(rectangleSegmentA002),-segLen(rectangleSegmentA002)],%)
|
||||
|>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|
||||
|>close()`,
|
||||
})
|
||||
await editor.expectEditor.toContain(
|
||||
`sketch001 = startSketchOn('XZ')
|
||||
@ -484,17 +460,17 @@ chamf = chamfer({
|
||||
]
|
||||
}, %)
|
||||
sketch002 = startSketchOn(extrude001, seg03)
|
||||
|> startProfileAt([205.96, 254.59], %)
|
||||
profile001 = startProfileAt([205.96, 254.59], sketch002)
|
||||
|> angledLine([0, 11.39], %, $rectangleSegmentA002)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002) - 90,
|
||||
105.26
|
||||
], %, $rectangleSegmentB001)
|
||||
], %)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA002),
|
||||
-segLen(rectangleSegmentA002)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
], %)
|
||||
|> line(endAbsolute=[profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
`,
|
||||
{ shouldNormalise: true }
|
||||
@ -561,10 +537,10 @@ sketch002 = startSketchOn(extrude001, seg03)
|
||||
|
||||
const expectedCodeSnippets = {
|
||||
sketchOnXzPlane: `sketch001 = startSketchOn('XZ')`,
|
||||
pointAtOrigin: `startProfileAt([${originSloppy.kcl[0]}, ${originSloppy.kcl[1]}], %)`,
|
||||
pointAtOrigin: `startProfileAt([${originSloppy.kcl[0]}, ${originSloppy.kcl[1]}], sketch001)`,
|
||||
segmentOnXAxis: `xLine(${xAxisSloppy.kcl[0]}, %)`,
|
||||
afterSegmentDraggedOffYAxis: `startProfileAt([${offYAxis.kcl[0]}, ${offYAxis.kcl[1]}], %)`,
|
||||
afterSegmentDraggedOnYAxis: `startProfileAt([${yAxisSloppy.kcl[0]}, ${yAxisSloppy.kcl[1]}], %)`,
|
||||
afterSegmentDraggedOffYAxis: `startProfileAt([${offYAxis.kcl[0]}, ${offYAxis.kcl[1]}], sketch001)`,
|
||||
afterSegmentDraggedOnYAxis: `startProfileAt([${yAxisSloppy.kcl[0]}, ${yAxisSloppy.kcl[1]}], sketch001)`,
|
||||
}
|
||||
|
||||
await test.step(`Start a sketch on the XZ plane`, async () => {
|
||||
@ -605,6 +581,7 @@ sketch002 = startSketchOn(extrude001, seg03)
|
||||
expectedCodeSnippets.afterSegmentDraggedOnYAxis
|
||||
)
|
||||
})
|
||||
await editor.page.waitForTimeout(1000)
|
||||
})
|
||||
|
||||
test(`Verify user can double-click to edit a sketch`, async ({
|
||||
@ -1052,7 +1029,7 @@ openSketch = startSketchOn('XY')
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 700, y: 150 }
|
||||
const [clickOnXzPlane] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||
const expectedOutput = `plane001 = offsetPlane('XZ', 5)`
|
||||
const expectedOutput = `plane001 = offsetPlane('XZ', offset = 5)`
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
// FIXME: Since there is no KCL code loaded. We need to wait for the scene to load before we continue.
|
||||
@ -1117,13 +1094,14 @@ openSketch = startSketchOn('XY')
|
||||
}) => {
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 620, y: 257 }
|
||||
const expectedOutput = `helix001 = helix(revolutions = 1, angleStart = 360, counterClockWise = false, radius = 5, axis = 'X', length = 5)`
|
||||
const expectedOutput = `helix001 = helix( revolutions = 1, angleStart = 360, counterClockWise = false, radius = 5, axis = 'X', length = 5,)`
|
||||
const expectedLine = `revolutions=1,`
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await test.step(`Look for the red of the default plane`, async () => {
|
||||
await scene.expectPixelColor([96, 52, 52], testPoint, 15)
|
||||
})
|
||||
// await test.step(`Look for the red of the default plane`, async () => {
|
||||
// await scene.expectPixelColor([96, 52, 52], testPoint, 15)
|
||||
// })
|
||||
await test.step(`Go through the command bar flow`, async () => {
|
||||
await toolbar.helixButton.click()
|
||||
await cmdBar.expectState({
|
||||
@ -1154,7 +1132,7 @@ openSketch = startSketchOn('XY')
|
||||
await editor.expectEditor.toContain(expectedOutput)
|
||||
await editor.expectState({
|
||||
diagnostics: [],
|
||||
activeLines: [expectedOutput],
|
||||
activeLines: [expectedLine],
|
||||
highlightedCode: '',
|
||||
})
|
||||
// Red plane is now gone, white helix is there
|
||||
@ -1187,7 +1165,7 @@ openSketch = startSketchOn('XY')
|
||||
}) => {
|
||||
const initialCode = `sketch001 = startSketchOn('XZ')
|
||||
|> circle({ center = [0, 0], radius = 30 }, %)
|
||||
plane001 = offsetPlane('XZ', 50)
|
||||
plane001 = offsetPlane('XZ', offset = 50)
|
||||
sketch002 = startSketchOn(plane001)
|
||||
|> circle({ center = [0, 0], radius = 20 }, %)
|
||||
`
|
||||
@ -1273,7 +1251,7 @@ openSketch = startSketchOn('XY')
|
||||
}) => {
|
||||
const initialCode = `sketch001 = startSketchOn('XZ')
|
||||
|> circle({ center = [0, 0], radius = 30 }, %)
|
||||
plane001 = offsetPlane('XZ', 50)
|
||||
plane001 = offsetPlane('XZ', offset = 50)
|
||||
sketch002 = startSketchOn(plane001)
|
||||
|> circle({ center = [0, 0], radius = 20 }, %)
|
||||
loft001 = loft([sketch001, sketch002])
|
||||
@ -1320,7 +1298,7 @@ loft001 = loft([sketch001, sketch002])
|
||||
await page.waitForTimeout(1000)
|
||||
await clickOnSketch2()
|
||||
await expect(page.locator('.cm-activeLine')).toHaveText(`
|
||||
plane001 = offsetPlane('XZ', 50)
|
||||
plane001 = offsetPlane('XZ', offset = 50)
|
||||
`)
|
||||
await page.keyboard.press('Backspace')
|
||||
// Check for sketch 1
|
||||
@ -1396,12 +1374,12 @@ sketch002 = startSketchOn('XZ')
|
||||
await clickOnSketch2()
|
||||
await page.waitForTimeout(500)
|
||||
await cmdBar.progressCmdBar()
|
||||
await toolbar.openPane('code')
|
||||
await page.waitForTimeout(500)
|
||||
})
|
||||
|
||||
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
|
||||
await scene.expectPixelColor([135, 64, 73], testPoint, 15)
|
||||
await toolbar.openPane('code')
|
||||
await editor.expectEditor.toContain(sweepDeclaration)
|
||||
await editor.expectState({
|
||||
diagnostics: [],
|
||||
@ -2471,19 +2449,18 @@ extrude002 = extrude(sketch002, length = 50)
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 550, y: 295 }
|
||||
const testPoint = { x: 580, y: 320 }
|
||||
const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||
const shellTarget = hasExtrudesInPipe ? 'sketch002' : 'extrude002'
|
||||
const shellDeclaration = `shell001 = shell(${shellTarget}, faces = ['end'], thickness = 5)`
|
||||
|
||||
await test.step(`Look for the grey of the shape`, async () => {
|
||||
await toolbar.closePane('code')
|
||||
await scene.expectPixelColor([128, 128, 128], testPoint, 15)
|
||||
await scene.expectPixelColor([113, 113, 113], testPoint, 15)
|
||||
})
|
||||
|
||||
await test.step(`Go through the command bar flow, selecting a cap and keeping default thickness`, async () => {
|
||||
@ -2530,6 +2507,94 @@ extrude002 = extrude(sketch002, length = 50)
|
||||
})
|
||||
})
|
||||
|
||||
const shellPointAndClickDeletionCases = [
|
||||
{ shouldUseKeyboard: true },
|
||||
{ shouldUseKeyboard: false },
|
||||
]
|
||||
shellPointAndClickDeletionCases.forEach(({ shouldUseKeyboard }) => {
|
||||
test(`Shell point-and-click deletion (shouldUseKeyboard: ${shouldUseKeyboard})`, async ({
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const sketchCode = `sketch001 = startSketchOn('XY')
|
||||
profile001 = startProfileAt([-20, 20], sketch001)
|
||||
|> xLine(40, %)
|
||||
|> yLine(-60, %)
|
||||
|> xLine(-40, %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
`
|
||||
const extrudeCode = `extrude001 = extrude(profile001, length = 40)
|
||||
`
|
||||
const shellCode = `shell001 = shell(extrude001, faces = ['end'], thickness = 5)
|
||||
`
|
||||
const initialCode = sketchCode + extrudeCode + shellCode
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await toolbar.openPane('feature-tree')
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 590, y: 400 }
|
||||
const extrudeColor: [number, number, number] = [100, 100, 100]
|
||||
const sketchColor: [number, number, number] = [140, 140, 140]
|
||||
const defaultPlaneColor: [number, number, number] = [50, 50, 100]
|
||||
|
||||
const deleteOperation = async (operationButton: Locator) => {
|
||||
if (shouldUseKeyboard) {
|
||||
await operationButton.click({ button: 'left' })
|
||||
await page.keyboard.press('Backspace')
|
||||
} else {
|
||||
await operationButton.click({ button: 'right' })
|
||||
const editButton = page.getByTestId('context-menu-delete')
|
||||
await editButton.click()
|
||||
}
|
||||
}
|
||||
|
||||
await test.step(`Look for the grey of the extrude shape`, async () => {
|
||||
await scene.expectPixelColor(extrudeColor, testPoint, 20)
|
||||
})
|
||||
|
||||
await test.step('Delete shell and confirm deletion', async () => {
|
||||
const operationButton = await toolbar.getFeatureTreeOperation(
|
||||
'Shell',
|
||||
0
|
||||
)
|
||||
await deleteOperation(operationButton)
|
||||
await scene.expectPixelColor(extrudeColor, testPoint, 20)
|
||||
await editor.expectEditor.not.toContain(shellCode)
|
||||
})
|
||||
|
||||
await test.step('Delete extrude and confirm deletion', async () => {
|
||||
const operationButton = await toolbar.getFeatureTreeOperation(
|
||||
'Extrude',
|
||||
0
|
||||
)
|
||||
await deleteOperation(operationButton)
|
||||
await editor.expectEditor.not.toContain(extrudeCode)
|
||||
await scene.expectPixelColor(sketchColor, testPoint, 20)
|
||||
})
|
||||
|
||||
await test.step('Delete sketch and confirm empty scene', async () => {
|
||||
const operationButton = await toolbar.getFeatureTreeOperation(
|
||||
'Sketch',
|
||||
0
|
||||
)
|
||||
await deleteOperation(operationButton)
|
||||
await editor.expectEditor.toContain('')
|
||||
await scene.expectPixelColor(defaultPlaneColor, testPoint, 20)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test(`Shell dry-run validation rejects sweeps`, async ({
|
||||
context,
|
||||
page,
|
||||
|
@ -192,11 +192,11 @@ extrude001 = extrude(sketch001, length = 50)
|
||||
|> line(end = [0, -1])
|
||||
|> close()
|
||||
|> extrude(length = 1)
|
||||
|> patternLinear3d({
|
||||
axis: [1, 0, 1],
|
||||
repetitions: 3,
|
||||
distance: 6
|
||||
}, %)`
|
||||
|> patternLinear3d(
|
||||
axis = [1, 0, 1],
|
||||
repetitions = 3,
|
||||
distance = 6,
|
||||
)`
|
||||
)
|
||||
})
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
|
@ -444,8 +444,7 @@ test(
|
||||
|
||||
const startXPx = 600
|
||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||
code += `
|
||||
|> startProfileAt([7.19, -9.7], %)`
|
||||
code += `profile001 = startProfileAt([7.19, -9.7], sketch001)`
|
||||
await expect(page.locator('.cm-content')).toHaveText(code)
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
@ -456,7 +455,9 @@ test(
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
})
|
||||
|
||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
||||
const lineEndClick = () =>
|
||||
page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
||||
await lineEndClick()
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
code += `
|
||||
@ -467,6 +468,15 @@ test(
|
||||
.getByRole('button', { name: 'arc Tangential Arc', exact: true })
|
||||
.click()
|
||||
|
||||
// click on the end of the profile to continue it
|
||||
await page.waitForTimeout(300)
|
||||
await lineEndClick()
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
// click to continue profile
|
||||
await page.mouse.move(813, 392, { steps: 10 })
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 })
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
@ -589,8 +599,7 @@ test(
|
||||
mask: [page.getByTestId('model-state-indicator')],
|
||||
})
|
||||
await expect(page.locator('.cm-content')).toHaveText(
|
||||
`sketch001 = startSketchOn('XZ')
|
||||
|> circle({ center = [14.44, -2.44], radius = 1 }, %)`
|
||||
`sketch001 = startSketchOn('XZ')profile001 = circle({ center = [14.44, -2.44], radius = 1 }, sketch001)`
|
||||
)
|
||||
}
|
||||
)
|
||||
@ -634,8 +643,7 @@ test.describe(
|
||||
|
||||
const startXPx = 600
|
||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||
code += `
|
||||
|> startProfileAt([7.19, -9.7], %)`
|
||||
code += `profile001 = startProfileAt([7.19, -9.7], sketch001)`
|
||||
await expect(u.codeLocator).toHaveText(code)
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
@ -653,6 +661,10 @@ test.describe(
|
||||
.click()
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
// click to continue profile
|
||||
await page.mouse.click(813, 392)
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
|
||||
|
||||
code += `
|
||||
@ -739,8 +751,7 @@ test.describe(
|
||||
|
||||
const startXPx = 600
|
||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
||||
code += `
|
||||
|> startProfileAt([182.59, -246.32], %)`
|
||||
code += `profile001 = startProfileAt([182.59, -246.32], sketch001)`
|
||||
await expect(u.codeLocator).toHaveText(code)
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
@ -758,6 +769,10 @@ test.describe(
|
||||
.click()
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
// click to continue profile
|
||||
await page.mouse.click(813, 392)
|
||||
await page.waitForTimeout(100)
|
||||
|
||||
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
|
||||
|
||||
code += `
|
||||
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 143 KiB |
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |