diff --git a/docs/kcl-std/functions/std-sketch-planeOf.md b/docs/kcl-std/functions/std-sketch-planeOf.md new file mode 100644 index 000000000..111a03db3 --- /dev/null +++ b/docs/kcl-std/functions/std-sketch-planeOf.md @@ -0,0 +1,48 @@ +--- +title: "planeOf" +subtitle: "Function in std::sketch" +excerpt: "Find the plane a face lies on. Returns an error if the face doesn't lie on any plane (for example, the curved face of a cylinder)" +layout: manual +--- + +Find the plane a face lies on. Returns an error if the face doesn't lie on any plane (for example, the curved face of a cylinder) + +```kcl +planeOf( + @solid: Solid, + face: TaggedFace, +): Plane +``` + + + +### Arguments + +| Name | Type | Description | Required | +|----------|------|-------------|----------| +| `solid` | [`Solid`](/docs/kcl-std/types/std-types-Solid) | The solid whose face is being queried. | Yes | +| `face` | [`TaggedFace`](/docs/kcl-std/types/std-types-TaggedFace) | Find the plane which this face lies on. | Yes | + +### Returns + +[`Plane`](/docs/kcl-std/types/std-types-Plane) - An abstract plane. + + +### Examples + +```kcl +triangle = startSketchOn(XY) + |> polygon(radius = 3, numSides = 3, center = [0, 0]) + |> extrude(length = 2) + +// Find the plane of the triangle's top face. +topPlane = planeOf(triangle, face = END) + +// Create a new plane, 10 units above the triangle's top face. +startSketchOn(offsetPlane(topPlane, offset = 10)) + +``` + +![Rendered example of planeOf 0](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAAAALQCAYAAADPfd1WAABNq0lEQVR4Ae3AA6AkWZbG8f937o3IzKdyS2Oubdu2bdu2bdu2bWmMnpZKr54yMyLu+Xa3anqmhztr1a8+6EEP4qqrrrrqqquuuuqqq6666qqrrrrqqquu+j+JylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuur/vBd7sRd7bZ6Pf/iHf/htrrrqqquuuuqqq676v4zKVVddddVVV1111VX/p73O67zOe3/4h3/4d128ePF2HuDEiRM3f/3Xf/37/NZv/dZ3c9VVV1111VVXXXXV/1XoQQ96EFddddVVV1111VVX/d90zTXXPPibvumbnv60pz3tD7/lW77lbXmAD/qgD/rJhz70oa/6IR/yIQ+57777buWqq6666qqrrrrqqv+LqFx11VVXXXXVVVdd9X/eiRMnbn7Hd3zHr+EBHvrQh74qV1111VVXXXXVVVf9X0flqquuuuqqq6666qr/077+67/+fT78wz/8u17u5V7unXguP/IjP/LZ9913361cddVVV1111VVXXfV/FXrQgx7EVVddddVVV1111VX/d11zzTUPfrEXe7HX5vn4rd/6re/mqquuuuqqq6666qr/y9CDHvQgrrrqqquuuuqqq6666qqrrrrqqquuuuqq/5Mox48f56qrrrrqqquuuuqq/x8+/MM//Lse/OAHvzSgs2fP3spVV1111VVXXXXVVf/XUbnqqquuuuqqq6666v+Fb/qmb3r6Nddc82Ce6UM+5EMect99993KVVddddVVV1111VX/lxFcddVVV1111VVXXfX/wjXXXPNgHuBzP/dzf5urrrrqqquuuuqqq/6vI7jqqquuuuqqq6666v+Ff/iHf/htnum+++679YM/+IMfzFVXXXXVVVddddVV/9ehBz3oQVx11VVXXXXVVVdd9f/D67zO67z3mTNnHvSjP/qjn8NVV1111VVXXXXVVf8foAc96EFcddVVV1111VVXXXXVVVddddVVV1111VX/J1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/KipXXXXVVVddddVVV1111VVXXXXVVVddddX/VVSuuuqqq6666qqrrrrqqquuuuqqq6666qr/q6hcddVVV1111VVXXXXVVVddddVVV1111VX/V1G56qqrrrrqqquuuuqqq6666qqrrrrqqqv+r6Jy1VVXXXXVVVddddVVV1111VVXXXXVVVf9X0Xlqquuuuqqq6666qqrrrrqqquuuuqqq676v4rKVVddddVVV1111VVXXXXVVVddddVVV131fxWVq6666qqrrrrqqquuuuqqq6666qqrrrrq/yoqV1111VVXXXXVVVddddVVV1111VVXXXXV/1VUrrrqqquuuuqqq6666qqrrrrqqquuuuqq/6uoXHXVVVddddVVV1111VVXXXXVVVddddVV/1dRueqqq6666qqrrrrqqquuuuqqq6666qqr/q+ictVVV1111VVXXXXVVVddddVVV1111VVX/V9F5aqrrrrqqquuuuqqq6666qqrrrrqqquu+r+KylVXXXXVVVddddVVV1111VVXXXXVVVdd9X8Vlauuuuqqq6666qqrrrrqqquuuuqqq6666v8qKlddddVVV1111VVXXXXVVVddddVVV1111f9VVK666qqrrrrqqquuuuqqq6666qqrrrrqqv+rqFx11VVXXXXVVVddddVVV1111VVXXXXVVf9XUbnqqquuuuqqq6666qqrrrrqqquuuuqqq/6vonLVVVddddVVV1111VVXXXXVVVddddVVV/1fReWqq6666qqrrrrqqquuuuqqq6666qqrrvq/ispVV1111VVXXXXVVVddddVVV1111VVXXfV/FZWrrrrqqquuuuqqq6666qqrrrrqqquuuur/Kv4R/WxcCe3yxu8AAAAASUVORK5CYII=) + + diff --git a/docs/kcl-std/index.md b/docs/kcl-std/index.md index 9b7cb37c8..4a31d1d64 100644 --- a/docs/kcl-std/index.md +++ b/docs/kcl-std/index.md @@ -67,6 +67,7 @@ layout: manual * [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d) * [`patternLinear2d`](/docs/kcl-std/functions/std-sketch-patternLinear2d) * [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d) + * [`planeOf`](/docs/kcl-std/functions/std-sketch-planeOf) * [`polygon`](/docs/kcl-std/functions/std-sketch-polygon) * [`profileStart`](/docs/kcl-std/functions/std-sketch-profileStart) * [`profileStartX`](/docs/kcl-std/functions/std-sketch-profileStartX) diff --git a/docs/kcl-std/modules/std-sketch.md b/docs/kcl-std/modules/std-sketch.md index b64f54467..a96536547 100644 --- a/docs/kcl-std/modules/std-sketch.md +++ b/docs/kcl-std/modules/std-sketch.md @@ -32,6 +32,7 @@ This module contains functions for creating and manipulating sketches, and makin * [`patternCircular2d`](/docs/kcl-std/functions/std-sketch-patternCircular2d) * [`patternLinear2d`](/docs/kcl-std/functions/std-sketch-patternLinear2d) * [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d) +* [`planeOf`](/docs/kcl-std/functions/std-sketch-planeOf) * [`polygon`](/docs/kcl-std/functions/std-sketch-polygon) * [`profileStart`](/docs/kcl-std/functions/std-sketch-profileStart) * [`profileStartX`](/docs/kcl-std/functions/std-sketch-profileStartX) diff --git a/rust/justfile b/rust/justfile index f098f05de..b85c94480 100644 --- a/rust/justfile +++ b/rust/justfile @@ -8,6 +8,9 @@ lint: # Ensure we can build without extra feature flags. cargo clippy -p kcl-lib --all-targets -- -D warnings +lint-fix: + cargo clippy --workspace --all-targets --all-features --fix + # Run the stdlib docs generation redo-kcl-stdlib-docs-no-imgs: EXPECTORATE=overwrite {{cnr}} {{kcl_lib_flags}} docs::gen_std_tests::test_generate_stdlib diff --git a/rust/kcl-derive-docs/src/example_tests.rs b/rust/kcl-derive-docs/src/example_tests.rs index 392fc3b91..27ba9fcf9 100644 --- a/rust/kcl-derive-docs/src/example_tests.rs +++ b/rust/kcl-derive-docs/src/example_tests.rs @@ -97,6 +97,7 @@ pub const TEST_NAMES: &[&str] = &[ "std-offsetPlane-2", "std-offsetPlane-3", "std-offsetPlane-4", + "std-sketch-planeOf-0", "std-sketch-circle-0", "std-sketch-circle-1", "std-sketch-patternTransform2d-0", diff --git a/rust/kcl-lib/src/execution/cad_op.rs b/rust/kcl-lib/src/execution/cad_op.rs index 6c277258b..585a50d04 100644 --- a/rust/kcl-lib/src/execution/cad_op.rs +++ b/rust/kcl-lib/src/execution/cad_op.rs @@ -226,10 +226,7 @@ impl From<&KclValue> for OpKclValue { match value { KclValue::Uuid { value, .. } => Self::Uuid { value: *value }, KclValue::Bool { value, .. } => Self::Bool { value: *value }, - KclValue::Number { value, ty, .. } => Self::Number { - value: *value, - ty: ty.clone(), - }, + KclValue::Number { value, ty, .. } => Self::Number { value: *value, ty: *ty }, KclValue::String { value, .. } => Self::String { value: value.clone() }, KclValue::Tuple { value, .. } | KclValue::HomArray { value, .. } => { let value = value.iter().map(Self::from).collect(); diff --git a/rust/kcl-lib/src/execution/exec_ast.rs b/rust/kcl-lib/src/execution/exec_ast.rs index 34639033d..9d2240e30 100644 --- a/rust/kcl-lib/src/execution/exec_ast.rs +++ b/rust/kcl-lib/src/execution/exec_ast.rs @@ -1297,7 +1297,7 @@ impl Node { Ok(KclValue::Number { value: -value, meta, - ty: ty.clone(), + ty: *ty, }) } KclValue::Plane { value } => { @@ -1329,7 +1329,7 @@ impl Node { .map(|v| match v { KclValue::Number { value, ty, meta } => Ok(KclValue::Number { value: *value * -1.0, - ty: ty.clone(), + ty: *ty, meta: meta.clone(), }), _ => Err(err()), @@ -1350,7 +1350,7 @@ impl Node { .map(|v| match v { KclValue::Number { value, ty, meta } => Ok(KclValue::Number { value: *value * -1.0, - ty: ty.clone(), + ty: *ty, meta: meta.clone(), }), _ => Err(err()), @@ -1544,7 +1544,7 @@ impl Node { .into_iter() .map(|num| KclValue::Number { value: num as f64, - ty: start_ty.clone(), + ty: start_ty, meta: meta.clone(), }) .collect(), diff --git a/rust/kcl-lib/src/execution/geometry.rs b/rust/kcl-lib/src/execution/geometry.rs index 2a091be4a..4745c6e94 100644 --- a/rust/kcl-lib/src/execution/geometry.rs +++ b/rust/kcl-lib/src/execution/geometry.rs @@ -939,6 +939,7 @@ impl From for Point3D { Self { x: p.x, y: p.y, z: p.z } } } + impl From for kittycad_modeling_cmds::shared::Point3d { fn from(p: Point3d) -> Self { Self { @@ -1004,12 +1005,12 @@ pub struct BasePath { impl BasePath { pub fn get_to(&self) -> [TyF64; 2] { let ty: NumericType = self.units.into(); - [TyF64::new(self.to[0], ty.clone()), TyF64::new(self.to[1], ty)] + [TyF64::new(self.to[0], ty), TyF64::new(self.to[1], ty)] } pub fn get_from(&self) -> [TyF64; 2] { let ty: NumericType = self.units.into(); - [TyF64::new(self.from[0], ty.clone()), TyF64::new(self.from[1], ty)] + [TyF64::new(self.from[0], ty), TyF64::new(self.from[1], ty)] } } @@ -1225,14 +1226,14 @@ impl Path { pub fn get_from(&self) -> [TyF64; 2] { let p = &self.get_base().from; let ty: NumericType = self.get_base().units.into(); - [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)] + [TyF64::new(p[0], ty), TyF64::new(p[1], ty)] } /// Where does this path segment end? pub fn get_to(&self) -> [TyF64; 2] { let p = &self.get_base().to; let ty: NumericType = self.get_base().units.into(); - [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)] + [TyF64::new(p[0], ty), TyF64::new(p[1], ty)] } /// The path segment start point and its type. diff --git a/rust/kcl-lib/src/execution/kcl_value.rs b/rust/kcl-lib/src/execution/kcl_value.rs index 71c2dba66..9f9a07451 100644 --- a/rust/kcl-lib/src/execution/kcl_value.rs +++ b/rust/kcl-lib/src/execution/kcl_value.rs @@ -415,15 +415,41 @@ impl KclValue { /// Put the point into a KCL value. pub fn from_point2d(p: [f64; 2], ty: NumericType, meta: Vec) -> Self { + let [x, y] = p; Self::Tuple { value: vec![ Self::Number { - value: p[0], + value: x, meta: meta.clone(), - ty: ty.clone(), + ty, }, Self::Number { - value: p[1], + value: y, + meta: meta.clone(), + ty, + }, + ], + meta, + } + } + + /// Put the point into a KCL value. + pub fn from_point3d(p: [f64; 3], ty: NumericType, meta: Vec) -> Self { + let [x, y, z] = p; + Self::Tuple { + value: vec![ + Self::Number { + value: x, + meta: meta.clone(), + ty, + }, + Self::Number { + value: y, + meta: meta.clone(), + ty, + }, + Self::Number { + value: z, meta: meta.clone(), ty, }, @@ -448,7 +474,7 @@ impl KclValue { pub fn as_int_with_ty(&self) -> Option<(i64, NumericType)> { match self { - KclValue::Number { value, ty, .. } => crate::try_f64_to_i64(*value).map(|i| (i, ty.clone())), + KclValue::Number { value, ty, .. } => crate::try_f64_to_i64(*value).map(|i| (i, *ty)), _ => None, } } @@ -562,7 +588,7 @@ impl KclValue { pub fn as_ty_f64(&self) -> Option { match self { - KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, ty.clone())), + KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, *ty)), _ => None, } } diff --git a/rust/kcl-lib/src/execution/types.rs b/rust/kcl-lib/src/execution/types.rs index 5546a6f88..6ea937ab5 100644 --- a/rust/kcl-lib/src/execution/types.rs +++ b/rust/kcl-lib/src/execution/types.rs @@ -460,7 +460,7 @@ impl fmt::Display for PrimitiveType { } } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ts_rs::TS, JsonSchema)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, ts_rs::TS, JsonSchema)] #[ts(export)] #[serde(tag = "type")] pub enum NumericType { @@ -575,7 +575,7 @@ impl NumericType { match (&ty, &i.ty) { (Any, Default { .. }) if i.n == 0.0 => {} (Any, t) => { - ty = t.clone(); + ty = *t; } (_, Unknown) | (Default { .. }, Default { .. }) => return (result, Unknown), @@ -598,7 +598,7 @@ impl NumericType { } if ty == Any && !input.is_empty() { - ty = input[0].ty.clone(); + ty = input[0].ty; } (result, ty) @@ -722,7 +722,7 @@ impl NumericType { if ty.subtype(self) { return Ok(KclValue::Number { value: *value, - ty: ty.clone(), + ty: *ty, meta: meta.clone(), }); } @@ -736,7 +736,7 @@ impl NumericType { (Any, _) => Ok(KclValue::Number { value: *value, - ty: self.clone(), + ty: *self, meta: meta.clone(), }), @@ -744,7 +744,7 @@ impl NumericType { // means accept any number rather than force the current default. (_, Default { .. }) => Ok(KclValue::Number { value: *value, - ty: ty.clone(), + ty: *ty, meta: meta.clone(), }), @@ -1491,7 +1491,7 @@ impl KclValue { pub fn principal_type(&self) -> Option { match self { KclValue::Bool { .. } => Some(RuntimeType::Primitive(PrimitiveType::Boolean)), - KclValue::Number { ty, .. } => Some(RuntimeType::Primitive(PrimitiveType::Number(ty.clone()))), + KclValue::Number { ty, .. } => Some(RuntimeType::Primitive(PrimitiveType::Number(*ty))), KclValue::String { .. } => Some(RuntimeType::Primitive(PrimitiveType::String)), KclValue::Object { value, .. } => { let properties = value diff --git a/rust/kcl-lib/src/simulation_tests.rs b/rust/kcl-lib/src/simulation_tests.rs index 776e364ae..40a507ba0 100644 --- a/rust/kcl-lib/src/simulation_tests.rs +++ b/rust/kcl-lib/src/simulation_tests.rs @@ -3632,3 +3632,24 @@ mod non_english_identifiers { super::execute(TEST_NAME, true).await } } +mod plane_of { + const TEST_NAME: &str = "plane_of"; + + /// Test parsing KCL. + #[test] + fn parse() { + super::parse(TEST_NAME) + } + + /// Test that parsing and unparsing KCL produces the original KCL input. + #[tokio::test(flavor = "multi_thread")] + async fn unparse() { + super::unparse(TEST_NAME).await + } + + /// Test that KCL is executed correctly. + #[tokio::test(flavor = "multi_thread")] + async fn kcl_test_execute() { + super::execute(TEST_NAME, true).await + } +} diff --git a/rust/kcl-lib/src/std/args.rs b/rust/kcl-lib/src/std/args.rs index 4aaecbee3..087a6220c 100644 --- a/rust/kcl-lib/src/std/args.rs +++ b/rust/kcl-lib/src/std/args.rs @@ -340,12 +340,12 @@ impl Args { let x = KclValue::Number { value: p[0], meta: vec![meta], - ty: ty.clone(), + ty, }; let y = KclValue::Number { value: p[1], meta: vec![meta], - ty: ty.clone(), + ty, }; let ty = RuntimeType::Primitive(PrimitiveType::Number(ty)); @@ -1038,7 +1038,7 @@ impl<'a> FromKclValue<'a> for u64 { impl<'a> FromKclValue<'a> for TyF64 { fn from_kcl_val(arg: &'a KclValue) -> Option { match arg { - KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, ty.clone())), + KclValue::Number { value, ty, .. } => Some(TyF64::new(*value, *ty)), _ => None, } } diff --git a/rust/kcl-lib/src/std/mod.rs b/rust/kcl-lib/src/std/mod.rs index 4c124fcbf..152cd4be1 100644 --- a/rust/kcl-lib/src/std/mod.rs +++ b/rust/kcl-lib/src/std/mod.rs @@ -256,6 +256,10 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp |e, a| Box::pin(crate::std::shapes::circle(e, a)), StdFnProps::default("std::sketch::circle"), ), + ("sketch", "planeOf") => ( + |e, a| Box::pin(crate::std::planes::plane_of(e, a)), + StdFnProps::default("std::sketch::planeOf"), + ), ("sketch", "extrude") => ( |e, a| Box::pin(crate::std::extrude::extrude(e, a)), StdFnProps::default("std::sketch::extrude").include_in_feature_tree(), diff --git a/rust/kcl-lib/src/std/patterns.rs b/rust/kcl-lib/src/std/patterns.rs index 454385f83..b1807553b 100644 --- a/rust/kcl-lib/src/std/patterns.rs +++ b/rust/kcl-lib/src/std/patterns.rs @@ -408,7 +408,7 @@ impl GeometryTrait for Sketch { exec_state: &mut ExecState, ) -> Result<[TyF64; 3], KclError> { let [x, y] = array_to_point2d(val, source_ranges, exec_state)?; - let ty = x.ty.clone(); + let ty = x.ty; Ok([x, y, TyF64::new(0.0, ty)]) } diff --git a/rust/kcl-lib/src/std/planes.rs b/rust/kcl-lib/src/std/planes.rs index 59389196e..25fe4cce3 100644 --- a/rust/kcl-lib/src/std/planes.rs +++ b/rust/kcl-lib/src/std/planes.rs @@ -1,15 +1,123 @@ //! Standard library plane helpers. use kcmc::{ModelingCmd, each_cmd as mcmd, length_unit::LengthUnit, shared::Color}; -use kittycad_modeling_cmds as kcmc; +use kittycad_modeling_cmds::{self as kcmc, ok_response::OkModelingCmdResponse, websocket::OkWebSocketResponseData}; -use super::{args::TyF64, sketch::PlaneData}; +use super::{ + args::TyF64, + sketch::{FaceTag, PlaneData}, +}; use crate::{ - errors::KclError, - execution::{ExecState, KclValue, ModelingCmdMeta, Plane, PlaneType, types::RuntimeType}, + UnitLen, + errors::{KclError, KclErrorDetails}, + execution::{ExecState, KclValue, Metadata, ModelingCmdMeta, Plane, PlaneType, types::RuntimeType}, std::Args, }; +/// Find the plane of a given face. +pub async fn plane_of(exec_state: &mut ExecState, args: Args) -> Result { + let solid = args.get_unlabeled_kw_arg("solid", &RuntimeType::solid(), exec_state)?; + let face = args.get_kw_arg("face", &RuntimeType::tagged_face(), exec_state)?; + + inner_plane_of(solid, face, exec_state, &args) + .await + .map(Box::new) + .map(|value| KclValue::Plane { value }) +} + +async fn inner_plane_of( + solid: crate::execution::Solid, + face: FaceTag, + exec_state: &mut ExecState, + args: &Args, +) -> Result { + // Support mock execution + // Return an arbitrary (incorrect) plane and a non-fatal error. + if args.ctx.no_engine_commands().await { + let plane_id = exec_state.id_generator().next_uuid(); + exec_state.err(crate::CompilationError { + source_range: args.source_range, + message: "The engine isn't available, so returning an arbitrary incorrect plane".to_owned(), + suggestion: None, + severity: crate::errors::Severity::Error, + tag: crate::errors::Tag::None, + }); + return Ok(Plane { + artifact_id: plane_id.into(), + id: plane_id, + // Engine doesn't know about the ID we created, so set this to Uninit. + value: PlaneType::Uninit, + info: crate::execution::PlaneInfo { + origin: Default::default(), + x_axis: Default::default(), + y_axis: Default::default(), + }, + meta: vec![Metadata { + source_range: args.source_range, + }], + }); + } + + // Query the engine to learn what plane, if any, this face is on. + let face_id = face.get_face_id(&solid, exec_state, args, true).await?; + let meta = args.into(); + let cmd = ModelingCmd::FaceIsPlanar(mcmd::FaceIsPlanar { object_id: face_id }); + let plane_resp = exec_state.send_modeling_cmd(meta, cmd).await?; + let OkWebSocketResponseData::Modeling { + modeling_response: OkModelingCmdResponse::FaceIsPlanar(planar), + } = plane_resp + else { + return Err(KclError::new_semantic(KclErrorDetails::new( + format!( + "Engine returned invalid response, it should have returned FaceIsPlanar but it returned {plane_resp:#?}" + ), + vec![args.source_range], + ))); + }; + // Destructure engine's response to check if the face was on a plane. + let not_planar: Result<_, KclError> = Err(KclError::new_semantic(KclErrorDetails::new( + "The face you provided doesn't lie on any plane. It might be curved.".to_owned(), + vec![args.source_range], + ))); + let Some(x_axis) = planar.x_axis else { return not_planar }; + let Some(y_axis) = planar.y_axis else { return not_planar }; + let Some(origin) = planar.origin else { return not_planar }; + + // Engine always returns measurements in mm. + let engine_units = UnitLen::Mm; + let x_axis = crate::execution::Point3d { + x: x_axis.x, + y: x_axis.y, + z: x_axis.z, + units: engine_units, + }; + let y_axis = crate::execution::Point3d { + x: y_axis.x, + y: y_axis.y, + z: y_axis.z, + units: engine_units, + }; + let origin = crate::execution::Point3d { + x: origin.x.0, + y: origin.y.0, + z: origin.z.0, + units: engine_units, + }; + + // Engine doesn't send back an ID, so let's just make a new plane ID. + let plane_id = exec_state.id_generator().next_uuid(); + Ok(Plane { + artifact_id: plane_id.into(), + id: plane_id, + // Engine doesn't know about the ID we created, so set this to Uninit. + value: PlaneType::Uninit, + info: crate::execution::PlaneInfo { origin, x_axis, y_axis }, + meta: vec![Metadata { + source_range: args.source_range, + }], + }) +} + /// Offset a plane by a distance along its normal. pub async fn offset_plane(exec_state: &mut ExecState, args: Args) -> Result { let std_plane = args.get_unlabeled_kw_arg("plane", &RuntimeType::plane(), exec_state)?; diff --git a/rust/kcl-lib/src/std/segment.rs b/rust/kcl-lib/src/std/segment.rs index 42d40bf42..02b873c79 100644 --- a/rust/kcl-lib/src/std/segment.rs +++ b/rust/kcl-lib/src/std/segment.rs @@ -18,7 +18,7 @@ pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result Result<[TyF64; 2], KclError> { @@ -31,7 +31,7 @@ fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args })?; let (p, ty) = path.end_point_components(); // Docs generation isn't smart enough to handle ([f64; 2], NumericType). - let point = [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)]; + let point = [TyF64::new(p[0], ty), TyF64::new(p[1], ty)]; Ok(point) } @@ -81,7 +81,7 @@ pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result Result<[TyF64; 2], KclError> { @@ -94,7 +94,7 @@ fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar })?; let (p, ty) = path.start_point_components(); // Docs generation isn't smart enough to handle ([f64; 2], NumericType). - let point = [TyF64::new(p[0], ty.clone()), TyF64::new(p[1], ty)]; + let point = [TyF64::new(p[0], ty), TyF64::new(p[1], ty)]; Ok(point) } diff --git a/rust/kcl-lib/src/std/shapes.rs b/rust/kcl-lib/src/std/shapes.rs index 74685e392..5518f228b 100644 --- a/rust/kcl-lib/src/std/shapes.rs +++ b/rust/kcl-lib/src/std/shapes.rs @@ -71,7 +71,7 @@ async fn inner_circle( let radius = get_radius(radius, diameter, args.source_range)?; let from = [center_u[0] + radius.to_length_units(units), center_u[1]]; - let from_t = [TyF64::new(from[0], ty.clone()), TyF64::new(from[1], ty)]; + let from_t = [TyF64::new(from[0], ty), TyF64::new(from[1], ty)]; let sketch = crate::std::sketch::inner_start_profile(sketch_surface, from_t, None, exec_state, args.clone()).await?; @@ -156,7 +156,7 @@ async fn inner_circle_three_point( exec_state: &mut ExecState, args: Args, ) -> Result { - let ty = p1[0].ty.clone(); + let ty = p1[0].ty; let units = ty.expect_length(); let p1 = point_to_len_unit(p1, units); @@ -172,10 +172,7 @@ async fn inner_circle_three_point( SketchOrSurface::Sketch(group) => group.on, }; - let from = [ - TyF64::new(center[0] + radius, ty.clone()), - TyF64::new(center[1], ty.clone()), - ]; + let from = [TyF64::new(center[0] + radius, ty), TyF64::new(center[1], ty)]; let sketch = crate::std::sketch::inner_start_profile(sketch_surface, from.clone(), None, exec_state, args.clone()).await?; diff --git a/rust/kcl-lib/src/std/sketch.rs b/rust/kcl-lib/src/std/sketch.rs index cd09df518..8b67c7096 100644 --- a/rust/kcl-lib/src/std/sketch.rs +++ b/rust/kcl-lib/src/std/sketch.rs @@ -599,7 +599,7 @@ async fn inner_angled_line_of_x_length( } let to = get_y_component(Angle::from_degrees(angle_degrees), length.n); - let to = [TyF64::new(to[0], length.ty.clone()), TyF64::new(to[1], length.ty)]; + let to = [TyF64::new(to[0], length.ty), TyF64::new(to[1], length.ty)]; let new_sketch = straight_line(StraightLineParams::relative(to, sketch, tag), exec_state, args).await?; @@ -666,7 +666,7 @@ async fn inner_angled_line_of_y_length( } let to = get_x_component(Angle::from_degrees(angle_degrees), length.n); - let to = [TyF64::new(to[0], length.ty.clone()), TyF64::new(to[1], length.ty)]; + let to = [TyF64::new(to[0], length.ty), TyF64::new(to[1], length.ty)]; let new_sketch = straight_line(StraightLineParams::relative(to, sketch, tag), exec_state, args).await?; diff --git a/rust/kcl-lib/std/sketch.kcl b/rust/kcl-lib/std/sketch.kcl index 9c1e59b67..864b0246e 100644 --- a/rust/kcl-lib/std/sketch.kcl +++ b/rust/kcl-lib/std/sketch.kcl @@ -1941,3 +1941,24 @@ export fn subtract2d( /// The shape(s) which should be cut out of the sketch. tool: [Sketch; 1+], ): Sketch {} + +/// Find the plane a face lies on. +/// Returns an error if the face doesn't lie on any plane (for example, the curved face of a cylinder) +///```kcl +/// triangle = startSketchOn(XY) +/// |> polygon(radius = 3, numSides = 3, center = [0, 0]) +/// |> extrude(length = 2) +/// +/// // Find the plane of the triangle's top face. +/// topPlane = planeOf(triangle, face = END) +/// +/// // Create a new plane, 10 units above the triangle's top face. +/// startSketchOn(offsetPlane(topPlane, offset = 10)) +/// ``` +@(impl = std_rust) +export fn planeOf( + /// The solid whose face is being queried. + @solid: Solid, + /// Find the plane which this face lies on. + face: TaggedFace, +): Plane {} diff --git a/rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-planeOf0.png b/rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-planeOf0.png new file mode 100644 index 000000000..df07af627 Binary files /dev/null and b/rust/kcl-lib/tests/outputs/serial_test_example_fn_std-sketch-planeOf0.png differ diff --git a/rust/kcl-lib/tests/plane_of/artifact_commands.snap b/rust/kcl-lib/tests/plane_of/artifact_commands.snap new file mode 100644 index 000000000..8a38a1a13 --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/artifact_commands.snap @@ -0,0 +1,381 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact commands plane_of.kcl +--- +{ + "rust/kcl-lib/tests/plane_of/input.kcl": [ + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "make_plane", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "x_axis": { + "x": 1.0, + "y": 0.0, + "z": 0.0 + }, + "y_axis": { + "x": 0.0, + "y": 1.0, + "z": 0.0 + }, + "size": 60.0, + "clobber": false, + "hide": true + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "start_path" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "move_path_pen", + "path": "[uuid]", + "to": { + "x": 2743.2, + "y": 0.0, + "z": 0.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -1371.5999999999995, + "y": 2375.680887661472, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -1371.6000000000013, + "y": -2375.680887661472, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 2743.2, + "y": 0.0, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "close_path", + "path_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extrude", + "target": "[uuid]", + "distance": 1828.8, + "faces": null, + "opposite": "None" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_bring_to_front", + "object_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_extrusion_face_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "solid3d_get_adjacency_info", + "object_id": "[uuid]", + "edge_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "face_is_planar", + "object_id": "[uuid]" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "make_plane", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 3657.6 + }, + "x_axis": { + "x": 1.0, + "y": 0.0, + "z": 0.0 + }, + "y_axis": { + "x": 0.0, + "y": 1.0, + "z": 0.0 + }, + "size": 100.0, + "clobber": false, + "hide": false + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "plane_set_color", + "plane_id": "[uuid]", + "color": { + "r": 0.6, + "g": 0.6, + "b": 0.6, + "a": 0.3 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "object_visible", + "object_id": "[uuid]", + "hidden": true + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "enable_sketch_mode", + "entity_id": "[uuid]", + "ortho": false, + "animated": false, + "adjust_camera": false, + "planar_normal": { + "x": 0.0, + "y": 0.0, + "z": 1.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "start_path" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "move_path_pen", + "path": "[uuid]", + "to": { + "x": 1828.8, + "y": 0.0, + "z": 0.0 + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "sketch_mode_disable" + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 0.00000000000011198170331403397, + "y": 1828.8, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -1828.8, + "y": 0.00000000000022396340662806795, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": -0.0000000000003359451099421019, + "y": -1828.8, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "extend_path", + "path": "[uuid]", + "segment": { + "type": "line", + "end": { + "x": 1828.8, + "y": 0.0, + "z": 0.0 + }, + "relative": false + } + } + }, + { + "cmdId": "[uuid]", + "range": [], + "command": { + "type": "close_path", + "path_id": "[uuid]" + } + } + ], + "std::appearance": [], + "std::array": [], + "std::math": [], + "std::prelude": [], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap b/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap new file mode 100644 index 000000000..4d1e0089e --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap @@ -0,0 +1,6 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Artifact graph flowchart plane_of.kcl +extension: md +snapshot_kind: binary +--- diff --git a/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap.md b/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap.md new file mode 100644 index 000000000..17cc9b7e7 --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/artifact_graph_flowchart.snap.md @@ -0,0 +1,105 @@ +```mermaid +flowchart LR + subgraph path2 [Path] + 2["Path
[64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 3["Segment
[64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 4["Segment
[64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 5["Segment
[64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 6["Segment
[64, 114, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }] + 7[Solid2d] + end + subgraph path21 [Path] + 21["Path
[311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 22["Segment
[311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 23["Segment
[311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 24["Segment
[311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 25["Segment
[311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 26["Segment
[311, 361, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }] + 27[Solid2d] + end + 1["Plane
[41, 58, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 0 }] + 8["Sweep Extrusion
[120, 139, 0]"] + %% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 2 }] + 9[Wall] + %% face_code_ref=Missing NodePath + 10[Wall] + %% face_code_ref=Missing NodePath + 11[Wall] + %% face_code_ref=Missing NodePath + 12["Cap Start"] + %% face_code_ref=Missing NodePath + 13["Cap End"] + %% face_code_ref=Missing NodePath + 14["SweepEdge Opposite"] + 15["SweepEdge Adjacent"] + 16["SweepEdge Opposite"] + 17["SweepEdge Adjacent"] + 18["SweepEdge Opposite"] + 19["SweepEdge Adjacent"] + 20["Plane
[277, 304, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 0 }, CallKwUnlabeledArg] + 28["StartSketchOnPlane
[263, 305, 0]"] + %% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 0 }] + 1 --- 2 + 2 --- 3 + 2 --- 4 + 2 --- 5 + 2 --- 6 + 2 --- 7 + 2 ---- 8 + 3 --- 9 + 3 x--> 12 + 3 --- 14 + 3 --- 15 + 4 --- 10 + 4 x--> 12 + 4 --- 16 + 4 --- 17 + 5 --- 11 + 5 x--> 12 + 5 --- 18 + 5 --- 19 + 8 --- 9 + 8 --- 10 + 8 --- 11 + 8 --- 12 + 8 --- 13 + 8 --- 14 + 8 --- 15 + 8 --- 16 + 8 --- 17 + 8 --- 18 + 8 --- 19 + 9 --- 14 + 9 --- 15 + 19 <--x 9 + 15 <--x 10 + 10 --- 16 + 10 --- 17 + 17 <--x 11 + 11 --- 18 + 11 --- 19 + 14 <--x 13 + 16 <--x 13 + 18 <--x 13 + 20 --- 21 + 20 <--x 28 + 21 --- 22 + 21 --- 23 + 21 --- 24 + 21 --- 25 + 21 --- 26 + 21 --- 27 +``` diff --git a/rust/kcl-lib/tests/plane_of/ast.snap b/rust/kcl-lib/tests/plane_of/ast.snap new file mode 100644 index 000000000..7db45f037 --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/ast.snap @@ -0,0 +1,705 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of parsing plane_of.kcl +--- +{ + "Ok": { + "body": [ + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "tri", + "start": 0, + "type": "Identifier" + }, + "init": { + "body": [ + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startSketchOn", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "XY", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "radius", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "3", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 3.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "numSides", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "3", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 3.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "center", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + }, + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "polygon", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "length", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "extrude", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "nonCodeMeta": { + "nonCodeNodes": { + "2": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "NonCodeNode", + "value": { + "type": "newLineBlockComment", + "value": "Get the plane which `tri` ends on.", + "style": "line" + } + } + ] + }, + "startNodes": [] + }, + "start": 0, + "type": "PipeExpression", + "type": "PipeExpression" + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + }, + { + "commentStart": 0, + "declaration": { + "commentStart": 0, + "end": 0, + "id": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "p0", + "start": 0, + "type": "Identifier" + }, + "init": { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "face", + "start": 0, + "type": "Identifier" + }, + "arg": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "END", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "planeOf", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "tri", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + }, + "moduleId": 0, + "start": 0, + "type": "VariableDeclarator" + }, + "end": 0, + "kind": "const", + "moduleId": 0, + "start": 0, + "type": "VariableDeclaration", + "type": "VariableDeclaration" + }, + { + "commentStart": 0, + "end": 0, + "expression": { + "body": [ + { + "arguments": [], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "startSketchOn", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "offset", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "offsetPlane", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "p0", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + } + }, + { + "arguments": [ + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "radius", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "2", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 2.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "numSides", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "4", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 4.0, + "suffix": "None" + } + } + }, + { + "type": "LabeledArg", + "label": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "center", + "start": 0, + "type": "Identifier" + }, + "arg": { + "commentStart": 0, + "elements": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + }, + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "raw": "0", + "start": 0, + "type": "Literal", + "type": "Literal", + "value": { + "value": 0.0, + "suffix": "None" + } + } + ], + "end": 0, + "moduleId": 0, + "start": 0, + "type": "ArrayExpression", + "type": "ArrayExpression" + } + } + ], + "callee": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "polygon", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name" + }, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "CallExpressionKw", + "type": "CallExpressionKw", + "unlabeled": null + } + ], + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "PipeExpression", + "type": "PipeExpression" + }, + "moduleId": 0, + "preComments": [ + "", + "", + "// Offset that plane by 2, then draw a square on it." + ], + "start": 0, + "type": "ExpressionStatement", + "type": "ExpressionStatement" + } + ], + "commentStart": 0, + "end": 0, + "innerAttrs": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "settings", + "start": 0, + "type": "Identifier" + }, + "properties": [ + { + "commentStart": 0, + "end": 0, + "key": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "defaultLengthUnit", + "start": 0, + "type": "Identifier" + }, + "moduleId": 0, + "start": 0, + "type": "ObjectProperty", + "value": { + "abs_path": false, + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "name": "yd", + "start": 0, + "type": "Identifier" + }, + "path": [], + "start": 0, + "type": "Name", + "type": "Name" + } + } + ], + "start": 0, + "type": "Annotation" + } + ], + "moduleId": 0, + "nonCodeMeta": { + "nonCodeNodes": { + "2": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "NonCodeNode", + "value": { + "type": "newLine" + } + } + ] + }, + "startNodes": [ + { + "commentStart": 0, + "end": 0, + "moduleId": 0, + "start": 0, + "type": "NonCodeNode", + "value": { + "type": "newLine" + } + } + ] + }, + "start": 0 + } +} diff --git a/rust/kcl-lib/tests/plane_of/input.kcl b/rust/kcl-lib/tests/plane_of/input.kcl new file mode 100644 index 000000000..bca0bfa3a --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/input.kcl @@ -0,0 +1,13 @@ +@settings(defaultLengthUnit = yd) + +tri = startSketchOn(XY) + |> polygon(radius = 3, numSides = 3, center = [0, 0]) + |> extrude(length = 2) + +// Get the plane which `tri` ends on. +p0 = planeOf(tri, face = END) + +// Offset that plane by 2, then draw a square on it. +startSketchOn(offsetPlane(p0, offset = 2)) + |> polygon(radius = 2, numSides = 4, center = [0, 0]) + diff --git a/rust/kcl-lib/tests/plane_of/ops.snap b/rust/kcl-lib/tests/plane_of/ops.snap new file mode 100644 index 000000000..adfad681b --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/ops.snap @@ -0,0 +1,254 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Operations executed plane_of.kcl +--- +{ + "rust/kcl-lib/tests/plane_of/input.kcl": [ + { + "type": "StdLibCall", + "name": "startSketchOn", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + }, + "labeledArgs": {}, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 0 + }, + { + "type": "VariableDeclarationDeclaration" + }, + { + "type": "VariableDeclarationInit" + }, + { + "type": "PipeBodyItem", + "index": 0 + } + ] + }, + "sourceRange": [] + }, + { + "type": "StdLibCall", + "name": "extrude", + "unlabeledArg": { + "value": { + "type": "Sketch", + "value": { + "artifactId": "[uuid]" + } + }, + "sourceRange": [] + }, + "labeledArgs": { + "length": { + "value": { + "type": "Number", + "value": 2.0, + "ty": { + "type": "Default", + "len": { + "type": "Yards" + }, + "angle": { + "type": "Degrees" + } + } + }, + "sourceRange": [] + } + }, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 0 + }, + { + "type": "VariableDeclarationDeclaration" + }, + { + "type": "VariableDeclarationInit" + }, + { + "type": "PipeBodyItem", + "index": 2 + } + ] + }, + "sourceRange": [] + }, + { + "type": "StdLibCall", + "name": "offsetPlane", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + }, + "labeledArgs": { + "offset": { + "value": { + "type": "Number", + "value": 2.0, + "ty": { + "type": "Default", + "len": { + "type": "Yards" + }, + "angle": { + "type": "Degrees" + } + } + }, + "sourceRange": [] + } + }, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 2 + }, + { + "type": "ExpressionStatementExpr" + }, + { + "type": "PipeBodyItem", + "index": 0 + }, + { + "type": "CallKwUnlabeledArg" + } + ] + }, + "sourceRange": [] + }, + { + "type": "StdLibCall", + "name": "startSketchOn", + "unlabeledArg": { + "value": { + "type": "Plane", + "artifact_id": "[uuid]" + }, + "sourceRange": [] + }, + "labeledArgs": {}, + "nodePath": { + "steps": [ + { + "type": "ProgramBodyItem", + "index": 2 + }, + { + "type": "ExpressionStatementExpr" + }, + { + "type": "PipeBodyItem", + "index": 0 + } + ] + }, + "sourceRange": [] + } + ], + "std::appearance": [], + "std::array": [], + "std::math": [ + { + "type": "VariableDeclaration", + "name": "PI", + "value": { + "type": "Number", + "value": 3.141592653589793, + "ty": { + "type": "Unknown" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "E", + "value": { + "type": "Number", + "value": 2.718281828459045, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "TAU", + "value": { + "type": "Number", + "value": 6.283185307179586, + "ty": { + "type": "Known", + "type": "Count" + } + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::prelude": [ + { + "type": "VariableDeclaration", + "name": "START", + "value": { + "type": "String", + "value": "start" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + }, + { + "type": "VariableDeclaration", + "name": "END", + "value": { + "type": "String", + "value": "end" + }, + "visibility": "export", + "nodePath": { + "steps": [] + }, + "sourceRange": [] + } + ], + "std::sketch": [], + "std::solid": [], + "std::sweep": [], + "std::transform": [], + "std::turns": [], + "std::types": [], + "std::units": [] +} diff --git a/rust/kcl-lib/tests/plane_of/program_memory.snap b/rust/kcl-lib/tests/plane_of/program_memory.snap new file mode 100644 index 000000000..ddd84bc7c --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/program_memory.snap @@ -0,0 +1,192 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Variables in memory after executing plane_of.kcl +--- +{ + "p0": { + "type": "Plane", + "value": { + "artifactId": "[uuid]", + "id": "[uuid]", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 1828.8, + "units": { + "type": "Mm" + } + }, + "value": "Uninit", + "xAxis": { + "x": 1.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Mm" + } + }, + "yAxis": { + "x": 0.0, + "y": 1.0, + "z": 0.0, + "units": { + "type": "Mm" + } + } + } + }, + "tri": { + "type": "Solid", + "value": { + "type": "Solid", + "id": "[uuid]", + "artifactId": "[uuid]", + "value": [ + { + "faceId": "[uuid]", + "id": "[uuid]", + "sourceRange": [], + "tag": null, + "type": "extrudePlane" + }, + { + "faceId": "[uuid]", + "id": "[uuid]", + "sourceRange": [], + "tag": null, + "type": "extrudePlane" + }, + { + "faceId": "[uuid]", + "id": "[uuid]", + "sourceRange": [], + "tag": null, + "type": "extrudePlane" + } + ], + "sketch": { + "type": "Sketch", + "id": "[uuid]", + "paths": [ + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + 3.0, + 0.0 + ], + "tag": null, + "to": [ + -1.4999999999999993, + 2.598076211353316 + ], + "type": "ToPoint", + "units": { + "type": "Yards" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + -1.4999999999999993, + 2.598076211353316 + ], + "tag": null, + "to": [ + -1.5000000000000013, + -2.5980762113533156 + ], + "type": "ToPoint", + "units": { + "type": "Yards" + } + }, + { + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + }, + "from": [ + -1.5000000000000013, + -2.5980762113533156 + ], + "tag": null, + "to": [ + 3.0, + 0.0 + ], + "type": "ToPoint", + "units": { + "type": "Yards" + } + } + ], + "on": { + "artifactId": "[uuid]", + "id": "[uuid]", + "origin": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Mm" + } + }, + "type": "plane", + "value": "XY", + "xAxis": { + "x": 1.0, + "y": 0.0, + "z": 0.0, + "units": { + "type": "Unknown" + } + }, + "yAxis": { + "x": 0.0, + "y": 1.0, + "z": 0.0, + "units": { + "type": "Unknown" + } + } + }, + "start": { + "from": [ + 3.0, + 0.0 + ], + "to": [ + 3.0, + 0.0 + ], + "units": { + "type": "Yards" + }, + "tag": null, + "__geoMeta": { + "id": "[uuid]", + "sourceRange": [] + } + }, + "artifactId": "[uuid]", + "originalId": "[uuid]", + "units": { + "type": "Yards" + } + }, + "height": 2.0, + "startCapId": "[uuid]", + "endCapId": "[uuid]", + "units": { + "type": "Yards" + }, + "sectional": false + } + } +} diff --git a/rust/kcl-lib/tests/plane_of/rendered_model.png b/rust/kcl-lib/tests/plane_of/rendered_model.png new file mode 100644 index 000000000..441e64b83 Binary files /dev/null and b/rust/kcl-lib/tests/plane_of/rendered_model.png differ diff --git a/rust/kcl-lib/tests/plane_of/unparsed.snap b/rust/kcl-lib/tests/plane_of/unparsed.snap new file mode 100644 index 000000000..56ef43432 --- /dev/null +++ b/rust/kcl-lib/tests/plane_of/unparsed.snap @@ -0,0 +1,16 @@ +--- +source: kcl-lib/src/simulation_tests.rs +description: Result of unparsing plane_of.kcl +--- +@settings(defaultLengthUnit = yd) + +tri = startSketchOn(XY) + |> polygon(radius = 3, numSides = 3, center = [0, 0]) + |> extrude(length = 2) + +// Get the plane which `tri` ends on. +p0 = planeOf(tri, face = END) + +// Offset that plane by 2, then draw a square on it. +startSketchOn(offsetPlane(p0, offset = 2)) + |> polygon(radius = 2, numSides = 4, center = [0, 0])