import * as Inputs from "./inputs"; /** * Base interface for draw options - engine-specific implementations extend this */ export interface DrawOptionsBase { updatable?: boolean | undefined; hidden?: boolean | undefined; opacity?: number | undefined; colours?: string | string[] | undefined; size?: number | undefined; } /** * Base class for Draw implementations across all game engines. * Contains entity detection methods and shared validation utilities. */ /** Which of the two draw entry points can resolve a kind. */ export type DrawPhase = "sync" | "async"; /** * One entry of the ordered table a draw call walks to decide what it was handed. * * `kind` is the name a renderer registers its handler under, and the name the order is pinned by. * `phase` says which entry point can resolve it: a kernel shape has to cross to a worker and back, * so it is reachable only from the asynchronous call. */ export interface DrawableKind { readonly kind: string; readonly phase: DrawPhase; matches(entity: unknown): boolean; } export declare class DrawCore { /** * Every kind a draw call can resolve, in the order it tries them. * * The order is the answer to questions the checks cannot answer alone, and it is one list rather * than a chain written out in each renderer because those copies had already drifted. Two cases * make it load-bearing. A two-element list of points is also a segment - `Base.Segment3` is * `[Point3, Point3]` - so `line` before `points` is what decides that a pair of points draws as * a segment. And a JSCAD path carries `points` like a polyline does, so `jscadPath` comes before * `polyline`; that one is now decided by the check as well, but the order still states it. * * A renderer resolves only the kinds it registered a handler for. A renderer with no node concept * skips those entries rather than declaring a check it cannot honour. * @ignore true */ private cachedDrawableKinds; protected drawableKinds(): readonly DrawableKind[]; /** * The first kind of the given phase that matches, among those a handler was registered for. * * The handler is looked up before the check runs, so a renderer that does not draw a kind never * asks about it - which is what the hand-written chains achieved by simply not having the branch. * @ignore true */ protected resolveDrawableKind(entity: unknown, phase: DrawPhase, handled: (kind: string) => boolean): string | undefined; detectPoint(entity: unknown): entity is Inputs.Base.Point3; detectPoints(entity: unknown): entity is Inputs.Base.Point3[]; detectLine(entity: unknown): entity is Inputs.Base.Line3 | Inputs.Base.Segment3; detectLines(entity: unknown): entity is (Inputs.Base.Line3 | Inputs.Base.Segment3)[]; /** * The three-dimensional points a JSCAD path draws as. * * A `Path2` is two-dimensional and its points are `[x, y]` pairs, so drawing one through a * polyline primitive - which is what every renderer here does - needs the third component * supplied rather than left off the end: a two-element point read as a three-element one takes * the next point's x as its own z and the whole line skews. A closed path also has to be closed * explicitly, because its final segment back to the start is implied by `isClosed` rather than * by a repeated point. * * The path's transforms are applied here rather than assumed already applied. JSCAD accumulates * a translate or a rotate into `transforms` and leaves `points` untouched until something asks * for them, so a moved path still carries the coordinates it was built at - and reading `points` * straight off draws it back at its original pose while the solid built from the same path draws * where it was moved to. The matrix is column-major and the path is flat, so only the four terms * that touch x and y are worth multiplying. */ protected pathToPolylinePoints(path: Inputs.JSCAD.JSCADPath2): Inputs.Base.Point3[]; /** * Whether the entity is a JSCAD 2D path. * * It matters because a path also carries `points`, so without this check it is drawn as a * three-dimensional polyline built from two-dimensional points - which draws, and draws the * wrong thing. * * Both fields are load-bearing. `isClosed` is what tells a path from JSCAD's other two kinds, * and is the test the kernel's own narrowing uses - but it is not enough here, because this * repository's own polyline DTO carries `isClosed` too, and matching on it alone flattens every * closed polyline to z = 0. `transforms` is what every JSCAD entity carries and no polyline * does, so the pair identifies a path and nothing else. */ detectJscadPath(entity: unknown): entity is Inputs.JSCAD.JSCADPath2; detectJscadPaths(entity: unknown): entity is Inputs.JSCAD.JSCADPath2[]; /** * Whether the entity is a polyline: an object carrying a `points` array. * * A JSCAD `Path2` also carries `points`, so it is excluded here rather than left to the dispatch * order to catch - a path has its own handler, and a check that decides what something is should * not depend on what was asked first. * * Still not a type predicate: `points` is a shape many objects have, so asserting * `Base.Polyline3` would be a claim this check cannot support, and a predicate that is wrong is * worse than a boolean that is wrong, because the compiler believes it. */ detectPolyline(entity: unknown): boolean; detectPolylines(entity: unknown): boolean; /** * Whether the entity looks like a scene node. * * Deliberately not a type predicate: the check is that `id` is a string containing "node", which * any object can satisfy, so it cannot honestly assert a renderer's node type. Nodes are also a * single renderer's concept, which is why the honest version of this check belongs beside that * renderer rather than here. */ detectNode(entity: unknown): boolean; detectNodes(entity: unknown): boolean; /** * Whether the entity is a Verb NURBS curve, by the degree and knots on its `_data`. * * Deliberately not a type predicate: `Base.VerbCurve` and `Base.VerbSurface` are both the * structural `{ tessellate }`, so `entity is Base.VerbCurve` would be true of a surface as well * and would narrow nothing. That identity is intentional - it is what keeps drawing independent * of the verb library - and `bitbybit.verb` is deprecated, so this stays a boolean rather than * growing types for an area that comes out in the next major. */ detectVerbCurve(entity: unknown): boolean; /** * Whether the entity is a Verb NURBS surface, by the U and V degrees and knots on its `_data`. * * Deliberately not a type predicate, for the reason given on the curve check above. */ detectVerbSurface(entity: unknown): boolean; detectVerbCurves(entity: unknown): boolean; detectVerbSurfaces(entity: unknown): boolean; detectJscadMesh(entity: unknown): entity is Inputs.JSCAD.JSCADGeom2 | Inputs.JSCAD.JSCADGeom3; detectJscadMeshes(entity: unknown): entity is (Inputs.JSCAD.JSCADGeom2 | Inputs.JSCAD.JSCADGeom3)[]; detectOcctShape(entity: unknown): entity is Inputs.OCCT.TopoDSShapePointer; detectOcctShapes(entity: unknown): entity is Inputs.OCCT.TopoDSShapePointer[]; detectManifoldShape(entity: unknown): entity is Inputs.Manifold.ManifoldPointer | Inputs.Manifold.CrossSectionPointer; detectManifoldShapes(entity: unknown): entity is (Inputs.Manifold.ManifoldPointer | Inputs.Manifold.CrossSectionPointer)[]; detectDecomposedMesh(entity: unknown): entity is Inputs.OCCT.DecomposedMeshDto; detectDecomposedMeshes(entity: unknown): entity is Inputs.OCCT.DecomposedMeshDto[]; detectTag(entity: unknown): entity is Inputs.Tag.TagDto; detectTags(entity: unknown): entity is Inputs.Tag.TagDto[]; checkIfElementsInArrayAreNumbers(array: unknown[]): boolean; checkIfElementsInArrayAreArrays(array: unknown[]): boolean; arraysInChildrenArraysContainNumbers(array: unknown[][]): boolean; arraysInChildrenArraysAreOfLength3(array: unknown[][]): boolean; /** * Validate if draw input contains valid entity data * @param entity - Entity to validate * @returns True if valid, false otherwise */ protected isValidDrawInput(entity: unknown): boolean; /** * Type guard for Tag DTO * @param value - Value to check * @returns True if value has text property (TagDto) */ protected isTagDto(value: unknown): value is Inputs.Tag.TagDto; /** * Type guard for Tag DTO array * @param value - Value to check * @returns True if value is array of TagDtos */ protected isTagDtoArray(value: unknown): value is Inputs.Tag.TagDto[]; }