当前位置: 首页 > Web前端 > HTML5

CSG构建立体几何书架

时间:2023-04-05 23:09:05 HTML5

CSG基于HTML5Canvas构建立体几何构建立体几何的概念在工业水利水电建设和游戏中已经被很多人使用。最简单的实体表示称为体素,通常是具有简单形状的物体,例如立方体、圆柱体、棱柱体、棱锥体、球体、圆锥体等。这些体素每个包也不同,有些包可以使用弯曲的物体用于CSG处理,其他不支持这些功能。构造一个物体就是按照集合论的布尔逻辑组合体素。这些操作包括:并集、交集和补集。我们一般可以使用CSG将简单的模型组合起来生成复杂的模型,这样在构建模型的时候就省了很多功夫。HT中的ht.CSGNode原语类型是引用CSG包的函数。ht.CSGNode继承自ht.Node。当style的shape3d属性为空时,会显示六面体效果。如果通过setHost将CSGNode吸附到宿主CSGNode或CSGShape上,则宿主CSGNode或CSGShape可以与吸附的CSGNode图元进行CSG的联合建模。详情请参考《HTforWebModelingManual》CSGNode章节。这里我用CSG的概念写了一个例子,方便大家更好的理解这个概念。本例演示地址:http://hightopo.com/guide/gui...先来看效果图:从上面的效果图可以看出,我们把界面分为三部分,第一部分就是右边部分上下拆分,然后左右拆分整个界面,HT使用封装好的ht.widget.SplitView进行界面拆分,然后在底层div中添加拆分组件:dm=newht.DataModel();//数据模型treeView=newht.widget.TreeView(dm);//树组件gv1=newht.graph3d.Graph3dView(dm);//3D组件gv2=newht.graph3d.Graph3dView(dm);splitView=newht.widget.SplitView(gv1,gv2,'v',0.6);//拆分组件mainSplit=newht.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);以上代码是一种很常见的在HTML中添加HT组件的方式,具体可以参考HTforWeb入门手册的组件章节。在这种方式添加HT组件的时候有一个需要注意的地方,因为HT一般使用设置position为absolute的绝对定位方式,必须设置left,right,top,bottom等基本的css样式,比如这个:.main{保证金:0px;填充:0px;位置:绝对;顶部:0px;底部:0px;左:0px;right:0px;}所以为了方便加载最外层组件填满窗口,HT的所有组件都有addToDOM函数,其逻辑如下,其中iv是invalidate的缩写:addToDOM=function(){varself=this,view=self.getView(),style=view.style;document.body.appendChild(视图);style.left='0';style.right='0';style.top='0';style.bottom='0';window.addEventListener('resize',function(){self.iv();},false);以后我们可以直接在代码中调用addToDOM函数,不用写很多代码。上面的代码用addToDOM代替,代码如下,不需要绘制css样式:dm=newht.DataModel();//数据模型treeView=newht.widget.TreeView(dm);//树组件gv1=newht.graph3d.Graph3dView(dm);//3D组件gv2=newht.graph3d.Graph3dView(dm);拆分视图=newht.widget.SplitView(gv1,gv2,'v',0.6);//拆分组件mainSplit=newht.widget.SplitView(treeView,splitView,'h',0.27);mainSplit.addToDOM();interfaceallocation之后,我们再往里面添加内容。界面左边部分是HT封装的树组件。正如我在上一篇文章中写到的,树组件是一个非常方便绘制树关系的组件。开发者可以很容易地从数据模型DataModel中获取数据与节点的关系并放到树上,只需要在树组件的声明时将对应的数据模型DataModel放入树组件的参数中即可。当然,我们后续也扩展了很多树组件相关的功能,非常方便实用。这里我们只使用expandAll函数展开所有对象:treeView=newht.widget.TreeView(dm);//树组件treeView.expandAll();右边部分分为上下两部分,都是3D场景,只是设置显示有点不同,其他完全一样。上面的3D场景重载了getVisibleFunc函数。如果元素的showMe属性为true,则可见;如果节点的类型是ht.CSGNode,并且节点的getHost函数的参数为??空,则不可见;否则,它将是可见的:gv1.setVisibleFunc(function(data){if(data.showMe){returntrue;}if(datainstanceofht.CSGNode&&data.getHost()){returnfalse;}returntrue;});我们先给3D场景添加元素对象,我们先解释一下中间的书架,两边的书架缺了再补充首先,我们添加一个ht.CSGNode节点shelf,作为书架的主节点,其他节点依附于这个节点,为这个节点设置六个边的位置、大小、名称和颜色,然后添加到数据模型DataModel:varshelf=newht.CSGNode();shelf.s3(500,400,120);shelf.p3(0,200,0);shelf.setName('shelf1');shelf.s({'all.color':'#E5BB77'});dm.add(shelf);然后在这个书架上添加10个节点,做成书架的网格效果,并设置依附关系和父子关系添加到数据模型中:for(vari=0;i<2;i++){for(varj=0;j<5;j++){varclipNode=newht.CSGNode();clipNode.setHost(架子);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(架子);dm.add(剪辑节点);}}为了让书架更美观,我们在书架的上下左右各添加了ht.CSGNode。添加一本书,实现类似,很简单:varbook=newht.Node();book.setName('CSS3:TheMissingManual');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':'白色','left.color':'white','all.color':'gray'});book.setHost(shelf);book.setParent(shelf);dm.add(book);然后左边的书架也是用类似的方法构造,不同的是这里多了一个ht.CSGBox类型,继承自ht.CSGNode,不仅具有父类CSGNode的镂空功能,还可以旋转,展开和闭合六个面。这里我们的节点只设置了前面可以旋转展开,并设置了一系列样式:clipNode=newht.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面不可见'front.visible':true,//正面可见'front.toggleable':true,//允许正面双击展开'front.reverse.flip':true,//正面反面显示正面内容'front.transparent':true,//正面透明'front.end':Math.PI*0.7,//正面展开状态结束旋转弧度'front.color':'rgba(0,50,50,0.7)'//正面颜色});或许你还想知道下面的地球是怎么做到的?还记得上一篇文章写到HT中设置了shape3d属性。设置这个属性其实就是操作setShape3dModel(name,model)和getShape3dModel(name),通过这个属性可以设置box|sphere|cylinder|cone|torus|star|rect|roundRect|triangle|rightTriangle|parallelogram|trapezoid和其他型号,这些型号也是HT封装的是的,你想用的时候直接把shape3d设置成其中一个值就可以了。例如,本例中使用的“shape3d:sphere”设置为球体。我们只是将地图图像包裹在球体的外部。当然,这张地图图片是先通过ht.Default.setImage注册的,然后通过shape3d.image把图片附加到这个节点上:earth=newht.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);右边的书架也有一个主节点,其他节点依附于它,但是我们看到一个新的节点类型ht.DoorWindow,ht.DoorWindow继承自ht.CSGNode,除了具有父类CSGNode的镂空功能外,还可以进行整体的旋转、展开、关闭操作。常用作门窗业务对象,作为图元墙附着在CSGNode或CSGShape的宿主上。此节点类型是ht.CSGNode的扩展。相对来说,增加不同的样式参数来区分实际应用。更多的属性请去HTforWebModelingManual的DoorWindow章节添加到节点中玩:photos=newht.DoorWindow();photos.setName('DoorWindow-Photos');photos.setIcon('ben12');photos.s3(110,100,130);photos.p3(5,180,0);照片.setHost(货架);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],'dw.s3':[0.8,0.9,0.05],'dw.t3':[0,-5,0],'dw.axis':'v','dw.toggleable':false,'front.image':'ben1','back.image':'ben2','all.color':'#F8CE8B'});photos.setParent(货架);dm.add(照片);最后,我们在左边旋转地球,在右边旋转照片:varangle=0;setInterval(function(){angle+=Math.PI/40;earth.r3(0,angle,0);photos.s('dw.angle',角度);},50);我们看到,其实HT虽然封装了很多不同的CSG节点类型,但是实际应用都是大同小异,内容也没有特别大的区别。区别在于样式参数,但是在实际开发中,这种区别会很大程度上加快开发速度,毕竟名字一目了然,知道使用哪些样式属性向上