The concept of CSG construction solid geometry has been used by many people in industrial water conservancy and hydropower construction and games. The simplest solid representation is called volume element, which is usually an object with simple shape, such as cube, cylinder, prism, pyramid, sphere, cone, etc. These voxels vary from package to package, with some packages allowing CSG processing using curved objects and others not. To construct an object is to group elements together according to the Boolean logic of set theory. These operations include union, intersection, and complement. We can usually use CSG to combine simple models to produce complex models, which saves a lot of effort in constructing models.

The hT. CSGNode primitive type in HT is a reference to the function encapsulated by CSG. Ht. CSGNode inherits from HT. Node, and displays the hexahedron effect when the shape3D property of style is empty. If the CSGNode is adsorbed to the host CSGNode or CSGShape through setHost, the host CSGNode or CSGShape can conduct combined modeling of CSG with the adsorbed CSGNode elements. For details, see the CSGNode section of the HT for Web Modeling Manual. And I’ve written an example here using the concept of CSG, just to give you a better idea of what it means.

The Demo address of this example is hightopo.com/guide/guide…

Take a look at the renderings first:



As can be seen from the above illustration, the interface is divided into three parts. The right part is divided from top to bottom, and the whole interface is divided from left to right. HT is used to divide the interface with the encapsulated HT.Widget. SplitView, and then the split component is added into the underlying div:

dm = new ht.DataModel();// 数据模型            
treeView = new ht.widget.TreeView(dm); //树组件                                                                                                 
gv1 = new ht.graph3d.Graph3dView(dm); //3D 组件  
gv2 = new ht.graph3d.Graph3dView(dm);
splitView = new ht.widget.SplitView(gv1, gv2, 'v', 0.6);//分割组件 
mainSplit = new ht.widget.SplitView(treeView, splitView, 'h', 0.27);   
                
view = mainSplit.getView();  
view.className = 'main';
document.body.appendChild(view);    
window.addEventListener('resize', function (e) {
    mainSplit.invalidate();
}, false);                         Copy the code

The above code is a very common way to add HT components to HTML. See the components section of the HT for Web Starter manual for details. There is one important point to note about this method of adding HT components, because HT components are usually positioned with position set to absolute. Basic CSS styles such as left, right, top, and bottom must be set, like this:

.main {
     margin: 0px;
     padding: 0px;
     position: absolute;
     top: 0px;
     bottom: 0px;
     left: 0px;
     right: 0px;
}Copy the code

[javascript]
view plain
copy
print
?

addToDOM = function(){   
    var self = this,
    view = self.getView(),   
    style = view.style;
    document.body.appendChild(view);            
    style.left = '0';
    style.right = '0';
    style.top = '0';
    style.bottom = '0';      
    window.addEventListener('resize', function () { self.iv(); }, false);            
}  Copy the code

Instead of writing a lot of code, we’ll be able to call addToDOM directly in our code, which looks like this instead of drawing CSS styles:

dm = new ht.DataModel();// 数据模型             
treeView = new ht.widget.TreeView(dm); //树组件                                                             
gv1 = new ht.graph3d.Graph3dView(dm); //3D 组件  
gv2 = new ht.graph3d.Graph3dView(dm);
splitView = new ht.widget.SplitView(gv1, gv2, 'v', 0.6);//分割组件 
mainSplit = new ht.widget.SplitView(treeView, splitView, 'h', 0.27);   
mainSplit.addToDOM();Copy the code

The left side of the interface is the ht-wrapped tree component. As I wrote in a previous article, the tree component is a very convenient component for drawing tree relationships. Developers can easily get the relationship between data and nodes from the DataModel DataModel and put it on the tree. In the process of tree component declaration, we just need to put the corresponding DataModel DataModel into the parameter of tree component. Of course, we also extend many functions related to tree component, very convenient and practical, here we only use expandAll function, expandAll objects:

treeView = new ht.widget.TreeView(dm); Treeview.expandall ();Copy the code

The 3D scene above overloads the getVisibleFunc function. If the element’s showMe attribute is true, it is visible. If the node type is HT. CSGNode and the getHost parameter of the node is empty, the node cannot be viewed. Other circumstances can be seen:

gv1.setVisibleFunc(function(data){
    if(data.showMe){
        return true;
    }
    if(data instanceof ht.CSGNode && data.getHost()){
        return false;
    }
    return true;
});Copy the code

We add element objects to the 3D scene first, we explain the middle bookshelf first, and fill in the missing bookshelves on both sides. First, we added a ht.CSGNode node shelf as the main node of the shelf, and other nodes are attached to this node. We set the position, size, name and color of six sides of this node, and then added it to the DataModel DataModel:

var shelf = new ht.CSGNode();
shelf.s3(500, 400, 120);
shelf.p3(0, 200, 0);
shelf.setName('shelf1');
shelf.s({
    'all.color': '#E5BB77'
});
dm.add(shelf);Copy the code
for(var i=0; i<2; i++){ for(var j=0; j<5; j++){ var clipNode = new ht.CSGNode(); clipNode.setHost(shelf); clipNode.s3(80, 100, 120); clipNode.p3(-200+j*100, 340-i*120, 20); clipNode.setName('substract-'+i+'-'+j); clipNode.s('batch', 'tt'); clipNode.setParent(shelf); dm.add(clipNode); }}Copy the code

To make the bookshelf a little more beautiful, we added hT.csgNode to the top, bottom, left, and right of the bookshelf. Finally, we added a book to make it more concrete.

var book = new ht.Node();
book.setName('CSS3: The Missing Manual');
book.s3(60, 80, 8);
book.p3(-100, 210, 20);
book.r3(-Math.PI/6, Math.PI/5, 0);
book.setIcon('book');
book.s({
    'front.image': 'book',
    'back.color': 'white',
    'left.color': 'white',
    'all.color': 'gray'
});
book.setHost(shelf);
book.setParent(shelf);
dm.add(book);             Copy the code
clipNode = new ht.CSGBox(); clipNode.setName('CSGBox-Expand-Left'); clipNode.s3(100, 100, 120); ClipNode. P3 (0, 65, 0.1); clipNode.setHost(shelf); clipNode.showMe = true; Clipnode. s({'all.visible': false,//6 faces are not visible' front. Visible ': true,// front. 'front. Reverse. Flip ': true,// Front 'front. Math.pi * 0.7,// the end of the rotation of the front state 'color': 'rgba(0, 50, 50, 0.7)'// the front color});Copy the code
earth = new ht.Node();
earth.setName('earth');
earth.s3(70, 70, 70);
earth.p3(0, 50, 0);
earth.s({
    'shape3d': 'sphere',
    'shape3d.image': 'earth'
});
earth.setHost(shelf);  
earth.setParent(shelf);
dm.add(earth);Copy the code

The bookshelf on the right also has a primary node attached to it, but we see a new node type ht.DoorWindow. Ht.DoorWindow inherits from HT. CSGNode. It can also carry out the operation of rotating and closing the whole. It is often used as a business object of a door or window, and the host adsorbed on CSGNode or CSGShape is used as an icon of the wall. This node type is an extension of hT. CSGNode, which is a different style parameter for the actual application. For more properties, please refer to the DoorWindow section of the HT for Web modeling manual and add them to the node.

photos = new ht.DoorWindow(); photos.setName('DoorWindow-Photos'); photos.setIcon('ben12'); photos.s3(110, 100, 130); photos.p3(5, 180, 0); photos.setHost(shelf); photos.showMe = true; Photos. S ({' bottom. Uv: [1, 1, 1, 0, 0, 0, 0, 1], 'bottom. Uv. Scale: [1, 1],' left. Uv. Scale: [3, 3], 'top. Uv. Scale: (2, 2], and 'dw. S3: [0.8, 0.9, 0.05],' the dw. T3: [0, 5, 0], 'the dw. The axis' :' v ', 'the dw. Toggleable: false,' front. Image: 'ben1', 'back.image': 'ben2', 'all.color': '#F8CE8B' }); photos.setParent(shelf); dm.add(photos);Copy the code
var angle = 0;
setInterval(function(){
    angle += Math.PI/40;
    earth.r3(0, angle, 0);
    photos.s('dw.angle', angle);
}, 50);Copy the code