<!DOCTYPE html>
<html>
<head>
    <title>3D polygon sampler</title>
    <meta charset="UTF-8" />
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/jsxgraph/distrib/jsxgraph.css" />
    <script type="text/javascript" charset="UTF-8" src="https://cdn.jsdelivr.net/npm/jsxgraph/distrib/jsxgraphcore.js"></script>
</head>
<body>

<h1>3D polygon sampler</h1>

<h2>Creating a polygon</h2>
<p>A polygon is created from a list of vertices. Each vertex is given either in coordinates or as a <a href="https://jsxgraph.org/docs/symbols/Point3D.html#constructor"><code>Point3D</code></a> element. The vertices that are created from coordinates are styled according to the <code>vertices</code> attribute. The edges of the polygon are styled according to the <code>borders</code> attribute.</p>
<p>To make the layout of the vertices easier to see, I’ve set the view’s <code>depthOrderPoints</code> attribute to <code>true</code>.
<div id="polygon-homog-board" class="jxgbox" style="width:600px; height:600px"></div>

<h2>Mixing coordinates and <code>Point3D</code> elements</h2>
<p>This example shows how you can mix coordinates and <a href="https://jsxgraph.org/docs/symbols/Point3D.html#constructor"><code>Point3D</code></a> elements in a polygon’s vertex list.</p>
<div id="polygon-mixed-board" class="jxgbox" style="width:600px; height:600px"></div>

<h2>Filling a polygon</h2>
<p>You can set the fill and opacity of a 3D polygon just like you would with a 2D polygon. I recommend only filling polygons that are guaranteed to stay planar. In this example, the polygons are always planar because they’re triangles.</p>
<div id="planar-fill-board" class="jxgbox" style="width:600px; height:600px"></div>

<h2>The pitalls of filling a non-planar polygon</h2>
<p>Make the polygon below non-planar by dragging its vertices. This will probably make the fill look really weird from certain angles.</p>
<div id="non-planar-fill-board" class="jxgbox" style="width:600px; height:600px"></div>

<!-- creating a polygon -->
<script type="text/javascript">
// to prevent variable name conflicts, we define variables locally using `let`
// and put the code for each board in its own block
{
    // create a JSXGraph board and draw a 3D view on it
    let board = JXG.JSXGraph.initBoard(
        'polygon-homog-board',
        {
            boundingbox: [-8, 8, 8,-8],
            axis: false,
            showCopyright: false,
            showNavigation: false
        }
    );
    let view = board.create(
        'view3d',
        [[-4.5, -4.5], [9, 9],
        [[0, 3], [0, 3], [0, 3]]],
        {
            xPlaneRear: {fillOpacity: 0.2, gradient: null},
            yPlaneRear: {fillOpacity: 0.2, gradient: null},
            zPlaneRear: {fillOpacity: 0.2, gradient: null},
            depthOrderPoints: true
        }
    );
    
    // create a list of individually styled Point3D elements to use as the
    // vertices of a polygon
    let vertices1 = [];
    coords1 = [
        [2, 1, 1],
        [2, 2, 1],
        [1, 2, 1],
        [1, 2, 2],
        [1, 1, 2],
        [1, 1, 1]
    ];
    colors1 = [
        'orangered',
        'gold',
        'mediumseagreen',
        'darkturquoise',
        'purple',
        'deeppink'
    ];
    for (i in coords1) {
        vertices1.push(view.create(
            'point3d',
            coords1[i],
            {
                withLabel: false,
                size: 5,
                strokeColor: 'none',
                fillColor: 'white',
                gradientSecondColor: colors1[i],
                highlightStrokeWidth: 1,
                highlightStrokeColor: '#777'
            }
        ));
    }
    
    // create a polygon from a list of vertices (given as Point3D elements)
    let polygon1 = view.create(
        'polygon3d',
        vertices1,
        {
            borders: {
                strokeColor: '#777',
                highlightStrokeColor: '#999'
            }
        }
    );
    
    // create a polygon from a list of vertices (given in coordinates)
    let coords2 = [
        [0.5, 1.5, 1.5],
        [1.5, 1.5, 1.5],
        [1.5, 2.5, 1.5],
        [0.5, 2.5, 1.5]
    ];
    let polygon2 = view.create(
        'polygon3d',
        coords2,
        {
            vertices: {
                withLabel: false,
                strokeColor: 'none',
                fillColor: 'white',
                gradientSecondColor: '#444',
                highlightStrokeWidth: 1,
                highlightStrokeColor: 'black'
            },
            borders: {
                strokeColor: 'black',
                highlightStrokeColor: 'gray'
            }
        }
    );
}
</script>

<!-- mixing coordinates and Point3D elements -->
<script type="text/javascript">
// to prevent variable name conflicts, we define variables locally using `let`
// and put the code for each board in its own block
{
    // create a JSXGraph board and draw a 3D view on it
    let board = JXG.JSXGraph.initBoard(
        'polygon-mixed-board',
        {
            boundingbox: [-8, 8, 8,-8],
            axis: false,
            showCopyright: false,
            showNavigation: false
        }
    );
    let view = board.create(
        'view3d',
        [[-4.5, -4.5], [9, 9],
        [[0, 3], [0, 3], [0, 3]]],
        {
            xPlaneRear: {fillOpacity: 0.2, gradient: null},
            yPlaneRear: {fillOpacity: 0.2, gradient: null},
            zPlaneRear: {fillOpacity: 0.2, gradient: null},
            depthOrderPoints: true
        }
    );
    
    // create a list of individually styled Point3D elements to use as some
    // vertices of a polygon
    let vertices1 = [];
    coords1 = [
        [2, 1, 1],
        [2, 2, 1],
        [1, 2, 1],
        [1, 2, 2],
        [1, 1, 2],
        [1, 1, 1]
    ];
    colors1 = [
        'orangered',
        'gold',
        'mediumseagreen',
        'darkturquoise',
        'purple',
        'deeppink'
    ];
    for (i in coords1) {
        vertices1.push(view.create(
            'point3d',
            coords1[i],
            {
                withLabel: false,
                size: 5,
                strokeColor: 'none',
                fillColor: 'white',
                gradientSecondColor: colors1[i],
                highlightStrokeWidth: 1,
                highlightStrokeColor: '#777'
            }
        ));
    }
    
    // list the coordinates of the other vertices of the polygon
    let coords2 = [
        [0.5, 1.5, 1.5],
        [1.5, 1.5, 1.5],
        [1.5, 2.5, 1.5],
        [0.5, 2.5, 1.5]
    ];

    // create a polygon from a list of vertices (some given in coordinates, and
    // others given as Point3D elements)
    let polygon = view.create(
        'polygon3d',
        vertices1.slice(0, 3).concat(coords2, vertices1.slice(3, 6)),
        {
            vertices: {
                withLabel: false,
                strokeColor: 'none',
                fillColor: 'white',
                gradientSecondColor: '#444',
                highlightStrokeWidth: 1,
                highlightStrokeColor: 'black'
            },
            borders: {
                strokeColor: 'black',
                highlightStrokeColor: 'gray'
            }
        }
    );
}
</script>

<!-- filling a polygon -->
<script type="text/javascript">
// to prevent variable name conflicts, we define variables locally using `let`
// and put the code for each board in its own block
{
    // create a JSXGraph board and draw a 3D view on it
    let board = JXG.JSXGraph.initBoard(
        'planar-fill-board',
        {
            boundingbox: [-8, 8, 8,-8],
            axis: false,
            showCopyright: false,
            showNavigation: false
        }
    );
    let view = board.create(
        'view3d',
        [[-4.5, -4.5], [9, 9],
        [[0, 3], [0, 3], [0, 3]]],
        {
            xPlaneRear: {fillOpacity: 0.2, gradient: null},
            yPlaneRear: {fillOpacity: 0.2, gradient: null},
            zPlaneRear: {fillOpacity: 0.2, gradient: null},
            depthOrderPoints: true
        }
    );
    
    // create a list of individually styled Point3D elements to use as polygon
    // vertices
    let vertices = [];
    coords = [
        [2, 0.5, 0.5],
        [0.5, 2, 0.5],
        [0.5, 0.5, 2],
        [0.5, 1.25, 1.25],
        [1.25, 0.5, 1.25],
        [1.25, 1.25, 0.5]
    ];
    colors = [
        '#f08',
        '#fb0',
        '#0af',
        '#4f0',
        '#80f',
        '#f60'
    ];
    for (i in coords) {
        vertices.push(view.create(
            'point3d',
            coords[i],
            {
                withLabel: false,
                size: 5,
                strokeColor: 'none',
                fillColor: 'white',
                gradientSecondColor: colors[i],
                highlightStrokeWidth: 1,
                highlightStrokeColor: '#777'
            }
        ));
    }
    
    // create some filled triangles
    view.create(
        'polygon3d',
        [vertices[0], vertices[5], vertices[4]],
        {
            fillColor: '#f85',
            fillOpacity: 0.4,
            borders: {strokeColor: 'none'}
        }
    );
    view.create(
        'polygon3d',
        [vertices[1], vertices[3], vertices[5]],
        {
            fillColor: '#af0',
            fillOpacity: 0.4,
            borders: {strokeColor: 'none'}
        }
    );
    view.create(
        'polygon3d',
        [vertices[2], vertices[3], vertices[4]],
        {
            fillColor: '#64f',
            fillOpacity: 0.4,
            borders: {strokeColor: 'none'}
        }
    );
    view.create(
        'polygon3d',
        [vertices[3], vertices[4], vertices[5]],
        {
            fillColor: '#a87',
            fillOpacity: 0.4,
            borders: {strokeColor: 'none'}
        }
    );
    
}
</script>

<!-- the pitfalls of filling a non-planar polygon -->
<script type="text/javascript">
// to prevent variable name conflicts, we define variables locally using `let`
// and put the code for each board in its own block
{
    // create a JSXGraph board and draw a 3D view on it
    let board = JXG.JSXGraph.initBoard(
        'non-planar-fill-board',
        {
            boundingbox: [-8, 8, 8,-8],
            axis: false,
            showCopyright: false,
            showNavigation: false
        }
    );
    let view = board.create(
        'view3d',
        [[-4.5, -4.5], [9, 9],
        [[0, 3], [0, 3], [0, 3]]],
        {
            xPlaneRear: {fillOpacity: 0.2, gradient: null},
            yPlaneRear: {fillOpacity: 0.2, gradient: null},
            zPlaneRear: {fillOpacity: 0.2, gradient: null},
            depthOrderPoints: true
        }
    );
    
    // create a list of individually styled Point3D elements to use as polygon
    // vertices
    let vertices = [];
    coords = [
        [2, 0.5, 0.5],
        [0.5, 2, 0.5],
        [0.5, 0.5, 2],
        [0.5, 1.25, 1.25],
        [1.25, 0.5, 1.25],
        [1.25, 1.25, 0.5]
    ];
    colors = [
        '#f08',
        '#fb0',
        '#0af',
        '#4f0',
        '#80f',
        '#f60'
    ];
    for (i in coords) {
        vertices.push(view.create(
            'point3d',
            coords[i],
            {
                withLabel: false,
                size: 5,
                strokeColor: 'none',
                fillColor: 'white',
                gradientSecondColor: colors[i],
                highlightStrokeWidth: 1,
                highlightStrokeColor: '#777'
            }
        ));
    }
    
    // create a filled polygon that can become non-planar
    view.create(
        'polygon3d',
        [vertices[0], vertices[5], vertices[1], vertices[3], vertices[2], vertices[4]],
        {
            fillColor: '#a87',
            fillOpacity: 0.4,
            borders: {strokeColor: 'none'}
        }
    );
    
}
</script>
</body>
</html>