source-academy/modules

[CSG]: Non-touching unions fail to retain some colours

Closed this issue · 1 comments

CSG currently patches the JSCAD modeling library in order to retain colour data between operations. If I recall correctly, the unmodified library resets colours to its default shade of blue after each operation.

With the patch applied, the union of two Shapes in CSG normally retains their various colours. However, the patch does not cover all cases.

If non-touching Shapes are unioned, one of them reverts to the default blue.

Snippet to reproduce issue:

import {
    silver, crimson, black,
    cube, cone, sphere,
    intersect, union, scale, translate,
    render_grid_axes
} from "csg";

const base = intersect(
    scale(cube(silver), 1, 1, 0.3),
    scale(cone(crimson), 1, 1, 3)
);
const snowglobe = union(
    translate(sphere(black), 0, 0, 0.5),
    base
);
render_grid_axes(snowglobe);

image

Another example snippet that loses colours below. There also seems to be an infinite loop bug involving union() when the Shapes are too far from each other, but I'm not entirely certain (see #231).

image

// Source §1
// Prof Martin's Sierpinski fractals

import { union, translate, scale, render, pyramid, sphere, cube }
from 'csg';

function repeat(n, trans, s) {
    return n === 0
           ? s
           : repeat(n - 1, trans, trans(s));
}

// sierpinski returns a shape transformer
// following Sierpinski's 3D fractal scheme
// v: vertical displacement of original shape
//.   for lower level shapes
// h: horizontal displacement of original shape
//.   for lower level shapes
function sierpinski(v, h) {
    return o => {
        const t1 = translate(o,  h,  h, -v);
        const t2 = translate(o, -h,  h, -v);
        const t3 = translate(o,  h, -h, -v);
        const t4 = translate(o, -h, -h, -v);
        const c = union(o,
                        union(union(t1, t2),
                              union(t3, t4)));
        const c_scaled = scale(c, 0.5, 0.5, 0.5);
        return c_scaled;
    };
}

// spheres are computationally expensive
// only try repeat 2
render(repeat(2,
              sierpinski(0.6, 0.6),
              sphere('#edd4c8')));