DrawUtil.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import math from './math.js';
  3. import {Line2} from "../../libs/three.js/lines/Line2.js";
  4. import {LineGeometry} from "../../libs/three.js/lines/LineGeometry.js";
  5. import {LineMaterial} from "../../libs/three.js/lines/LineMaterial.js";
  6. //画线等函数--by 许钟文
  7. import {Features} from "../Features.js";
  8. var defaultColor = new THREE.Color(1,1,1);//config.applicationName == "zhiHouse" ? Colors.zhiBlue : Colors.lightGreen;
  9. var LineDraw = {
  10. createLine: function (posArr, o={}) {
  11. //多段普通线 (第二个点和第三个点之间是没有线段的, 所以不用在意线段顺序)
  12. var mat
  13. if(o.mat){
  14. mat = o.mat
  15. }else{
  16. let prop = {
  17. lineWidth: o.lineWidth || 1,
  18. //windows无效。 似乎mac/ios上粗细有效 ?
  19. color: o.color || defaultColor,
  20. transparent: o.dontAlwaysSeen ? false : true,
  21. depthTest: o.dontAlwaysSeen ? true : false,
  22. }
  23. if(o.deshed ){
  24. prop.dashSize = o.dashSize || 0.1,
  25. prop.gapSize = o.gapSize || 0.1
  26. }
  27. mat = new THREE[o.deshed ? "LineDashedMaterial" : "LineBasicMaterial"](prop)
  28. }
  29. var line = new THREE.LineSegments(new THREE.BufferGeometry, mat);
  30. line.renderOrder = o.renderOrder || 4
  31. this.moveLine(line, posArr)
  32. return line;
  33. },
  34. moveLine: function (line, posArr) {
  35. if(posArr.length == 0)return
  36. let position = []
  37. posArr.forEach(e=>position.push(e.x,e.y,e.z))
  38. line.geometry.setAttribute('position', new THREE.Float32BufferAttribute(/* new Float32Array( */position/* ) */, 3));
  39. line.geometry.attributes.position.needsUpdate = true;
  40. line.geometry.computeBoundingSphere();
  41. if(line.material instanceof THREE.LineDashedMaterial){
  42. line.computeLineDistances()
  43. //line.geometry.attributes.lineDistance.needsUpdate = true;
  44. line.geometry.verticesNeedUpdate = true; //没用
  45. }
  46. }
  47. ,
  48. createFatLineMat : function(o){
  49. var supportExtDepth = !!Features.EXT_DEPTH.isSupported()
  50. let params = $.extend({}, {
  51. //默认
  52. lineWidth : 5,
  53. color:0xffffff,
  54. transparent : true, depthWrite:false, depthTest:false,
  55. dashSize : 0.1, gapSize:0.1,
  56. }, o, {
  57. //修正覆盖:
  58. dashed: o.dashWithDepth ? supportExtDepth && !!o.dashed : !!o.dashed ,
  59. dashWithDepth:!!o.dashWithDepth,//只在被遮住的部分显示虚线
  60. useDepth: !!o.useDepth,
  61. supportExtDepth,
  62. })
  63. var mat = new LineMaterial(params)
  64. //if(o.dashed)(mat.defines.USE_DASH = "")
  65. return mat;
  66. },
  67. /*
  68. 创建可以改变粗细的线。
  69. */
  70. createFatLine : function(posArr, o){
  71. var geometry = new LineGeometry();
  72. geometry.setColors( o.color || [1,1,1]);
  73. var matLine = o.material || this.createFatLineMat(o);
  74. var line = new Line2( geometry, matLine );
  75. //line.computeLineDistances();
  76. line.scale.set( 1, 1, 1 );
  77. line.renderOrder = 2;
  78. this.moveFatLine(line, posArr)
  79. return line;
  80. },
  81. moveFatLine: function(line, posArr){
  82. var geometry = line.geometry;
  83. var positions = [];
  84. posArr.forEach(e=>{positions.push(...e.toArray())})
  85. if(positions.length > 0){
  86. if(!geometry){
  87. geometry = line.geometry = new LineGeometry();
  88. }
  89. if(geometry.attributes.instanceEnd && geometry.attributes.instanceEnd.data.array.length != positions.length){//positions个数改变会有部分显示不出来,所以重建
  90. geometry.dispose();
  91. geometry = new LineGeometry();
  92. line.geometry = geometry
  93. }
  94. geometry.setPositions( positions )
  95. if(line.material.defines.USE_DASH != void 0){
  96. //line.geometry.verticesNeedUpdate = true; //没用
  97. line.geometry.computeBoundingSphere(); //for raycaster
  98. line.computeLineDistances();
  99. }
  100. }else{
  101. geometry.dispose()
  102. line.geometry = new LineGeometry();
  103. }
  104. },
  105. updateLine: function(line, posArr){
  106. if(line instanceof Line2){
  107. LineDraw.moveFatLine(line,posArr)
  108. }else{
  109. LineDraw.moveLine(line,posArr)
  110. }
  111. },
  112. /*
  113. 为line创建用于检测鼠标的透明mesh,实际是个1-2段圆台。
  114. 由于近大远小的原因,假设没有透视畸变、创建的是等粗的圆柱的话, 所看到的线上每个位置的粗细应该和距离成反比。所以将圆柱改为根据距离线性渐变其截面半径的圆台,在最近点(相机到线的垂足)最细。如果最近点在线段上,则分成两段圆台,否则一段。
  115. */
  116. createBoldLine:function(points, o){
  117. o = o || {}
  118. var cylinder = o && o.cylinder;
  119. var CD = points[1].clone().sub(points[0]);
  120. var rotate = function(){//根据端点旋转好模型
  121. cylinder.lastVector = CD;//记录本次的端点向量
  122. var AB = new THREE.Vector3(0,-1,0)
  123. var axisVec = AB.clone().cross(CD).normalize(); //得到垂直于它们的向量,也就是旋转轴
  124. var rotationAngle = AB.angleTo(CD);
  125. cylinder.quaternion.setFromAxisAngle( axisVec, rotationAngle )
  126. }
  127. if(o && o.type == "init"){
  128. cylinder = new THREE.Mesh()
  129. cylinder.material = o.mat
  130. if(CD.length() == 0)return cylinder;
  131. rotate()
  132. }
  133. if(CD.length() == 0)return cylinder;
  134. if(o.type != "update"){
  135. var CDcenter = points[0].clone().add(points[1]).multiplyScalar(.5);
  136. cylinder.position.copy(CDcenter);
  137. if(!cylinder.lastVector || o.type == "moveAndRotate")rotate()
  138. else if(cylinder.lastVector && CD.angleTo(cylinder.lastVector)>0) rotate()//线方向改了or线反向了 重新旋转一下模型
  139. if(config.isEdit && !objects.mainDesign.editing )return cylinder;//节省初始加载时间?
  140. }
  141. //为了保证线段任何地方的可检测点击范围看起来一样大,更新圆台的结构(但是在镜头边缘会比中心看起来大)
  142. var height = points[0].distanceTo(points[1]);
  143. var standPos = o && o.standPos || objects.player.position;
  144. var k = config.isMobile ? 20 : 40;
  145. var dis1 = points[0].distanceTo(standPos);
  146. var dis2 = points[1].distanceTo(standPos);
  147. var foot = math.getFootPoint(standPos, points[0], points[1]);//垂足
  148. if(o.constantBold || objects.player.mode != "panorama"){
  149. var width = 0.1//0.08;
  150. var pts = [new THREE.Vector2(width ,height/2),new THREE.Vector2(width ,-height/2)]
  151. }else if(foot.clone().sub(points[0]).dot( foot.clone().sub(points[1]) ) > 0){//foot不在线段上
  152. var pts = [new THREE.Vector2(dis1 / k,height/2),new THREE.Vector2(dis2 / k,-height/2)]
  153. }else{//在线段上的话,要在垂足这加一个节点,因它距离站位最近,而两端较远
  154. var dis3 = foot.distanceTo(standPos);
  155. var len = foot.distanceTo(points[0])
  156. var pts = [new THREE.Vector2(dis1 / k,height/2), new THREE.Vector2(dis3 / k,height/2-len), new THREE.Vector2(dis2 / k,-height/2)]
  157. }
  158. cylinder.geometry && cylinder.geometry.dispose();//若不删除会占用内存
  159. cylinder.geometry = new THREE.LatheBufferGeometry( pts, 4/* Math.min(dis1,dis2)<10?4:3 */ )
  160. cylinder.renderOrder = 2;
  161. return cylinder;
  162. },
  163. updateBoldLine:function(cylinder, points, type, standPos, constantBold){
  164. this.createBoldLine(points,{type:type, cylinder : cylinder, standPos:standPos, constantBold}) //type:move:平移 会改长短 , type:update根据距离和角度更新 不改长短
  165. },
  166. }
  167. var MeshDraw = {
  168. getShape:function(points, holes){
  169. var shape = new THREE.Shape();
  170. shape.moveTo( points[0].x, points[0].y );
  171. for(var i=1,len=points.length; i<len; i++){
  172. shape.lineTo(points[i].x, points[i].y )
  173. }
  174. /* var holePath = new THREE.Path()
  175. .moveTo( 20, 10 )
  176. .absarc( 10, 10, 10, 0, Math.PI * 2, true )
  177. arcShape.holes.push( holePath );
  178. */
  179. if(holes){//挖空
  180. holes.forEach((points)=>{
  181. var holePath = new THREE.Path()
  182. holePath.moveTo( points[0].x, points[0].y )
  183. for(var i=1,len=points.length; i<len; i++){
  184. holePath.lineTo(points[i].x, points[i].y )
  185. }
  186. shape.holes.push( holePath );
  187. })
  188. }
  189. return shape
  190. },
  191. getShapeGeo: function(points, holes){//获取任意形状(多边形或弧形)的形状面 //quadraticCurveTo() 这是弧形的含函数
  192. var geometry = new THREE.ShapeBufferGeometry( this.getShape(points, holes) ); //ShapeGeometry
  193. /* var matrix = new THREE.Matrix4();//将竖直的面变为水平
  194. matrix.set(//z = y
  195. 1, 0, 0, 0,
  196. 0, 0, 0, 0,
  197. 0, 1, 0, 0,
  198. 0, 0, 0, 1
  199. )
  200. geometry.applyMatrix(matrix) */
  201. //geometry.computeVertexNormals();//对于光照需要的是点法线
  202. return geometry;
  203. },
  204. getExtrudeGeo: function(points, holes, options={}){//获得挤出棱柱,可以选择传递height,或者extrudePath
  205. var shape = this.getShape(points, holes) //points是横截面 [vector2,...]
  206. if(options.extrudePath ){// 路径 :[vector3,...]
  207. var length = extrudePath.reduce((total, currentValue, currentIndex, arr)=>{
  208. if(currentIndex == 0)return 0
  209. return total + currentValue.distanceTo(arr[currentIndex-1]);
  210. },0)
  211. options.extrudePath = new THREE.CatmullRomCurve3(extrudePath, options.closed , 'catmullrom' /* 'centripetal' */ , options.tension)
  212. }
  213. var extrudeSettings = $.extend(options,{
  214. steps: options.steps != void 0 ? options.steps : ( options.extrudePath ? Math.round(length/0.3) : 1),
  215. bevelEnabled: false, //不加的话,height为0时会有圆弧高度
  216. //depth
  217. })
  218. var geometry = new THREE.ExtrudeBufferGeometry( shape, extrudeSettings );
  219. return geometry;
  220. },
  221. getUnPosPlaneGeo : function(){//获取还没有赋值位置的plane geometry
  222. var e = new Uint16Array([0, 1, 2, 0, 2, 3])
  223. // , t = new Float32Array([-.5, -.5, 0, .5, -.5, 0, .5, .5, 0, -.5, .5, 0])
  224. , i = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1])
  225. , g = new THREE.BufferGeometry;
  226. g.setIndex(new THREE.BufferAttribute(e, 1)),
  227. //g.addAttribute("position", new n.BufferAttribute(t, 3)),
  228. g.setAttribute("uv", new THREE.BufferAttribute(i, 2))
  229. return function(){
  230. return g
  231. }
  232. }(),
  233. getPlaneGeo : function(A,B,C,D){
  234. var geo = this.getUnPosPlaneGeo().clone();
  235. var pos = [
  236. A.x, A.y, A.z,
  237. B.x, B.y, B.z,
  238. C.x, C.y, C.z,
  239. D.x, D.y, D.z
  240. ]
  241. //geo.addAttribute("position", new THREE.BufferAttribute(pos, 3))
  242. geo.setAttribute('position', new THREE.Float32BufferAttribute(pos, 3));
  243. geo.computeVertexNormals()
  244. geo.computeBoundingSphere() //for raycaster
  245. return geo;
  246. },
  247. drawPlane : function(A,B,C,D, material){
  248. var wall = new THREE.Mesh(this.getPlaneGeo(A,B,C,D), material);
  249. return wall;
  250. },
  251. movePlane: function(mesh, A,B,C,D){
  252. var pos = new Float32Array([
  253. A.x, A.y, A.z,
  254. B.x, B.y, B.z,
  255. C.x, C.y, C.z,
  256. D.x, D.y, D.z
  257. ])
  258. mesh.geometry.addAttribute("position", new THREE.BufferAttribute(pos, 3))
  259. mesh.geometry.computeBoundingSphere()//for checkIntersect
  260. }
  261. ,
  262. createGeometry:function(posArr, faceArr, uvArr, normalArr ){//创建复杂mesh. faceArr:[[0,1,2],[0,2,3]]
  263. let geo = new THREE.BufferGeometry;
  264. let positions = [];
  265. posArr.forEach(p=>positions.push(p.x,p.y,p.z));
  266. geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
  267. if(faceArr){
  268. let indice = []
  269. faceArr.forEach(f=>indice.push(...f));
  270. geo.setIndex(indice) // auto set Uint16BufferAttribute or Uint32BufferAttribute
  271. }
  272. if(uvArr){
  273. let uvs = []
  274. uvArr.forEach(uv=>uvs.push(uv.x,uv.y));
  275. geo.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2))
  276. }
  277. if(normalArr){
  278. let normals = []
  279. normalArr.forEach(n=>normals.push(n.x,n.y,n.z));
  280. geo.setAttribute("normal", new THREE.Float32BufferAttribute(normals, 3))
  281. }
  282. /*
  283. geo.computeVertexNormals()
  284. geo.computeBoundingSphere() //for raycaster
  285. */
  286. return geo
  287. },
  288. updateGeometry:function(geo, posArr, faceArr, uvArr, normalArr ){//创建复杂mesh. faceArr:[[0,1,2],[0,2,3]]
  289. let positions = [];
  290. posArr.forEach(p=>positions.push(p.x,p.y,p.z));
  291. geo.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
  292. geo.attributes.position.needsUpdate = true;
  293. if(faceArr){
  294. let indice = []
  295. faceArr.forEach(f=>indice.push(...f));
  296. geo.setIndex(indice) // auto set Uint16BufferAttribute or Uint32BufferAttribute
  297. }
  298. if(uvArr){
  299. let uvs = []
  300. uvArr.forEach(uv=>uvs.push(uv.x,uv.y));
  301. geo.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2))
  302. }
  303. if(normalArr){
  304. let normals = []
  305. normalArr.forEach(n=>normals.push(n.x,n.y,n.z));
  306. geo.setAttribute("normal", new THREE.Float32BufferAttribute(normals, 3))
  307. }
  308. /*
  309. geo.computeVertexNormals()
  310. */
  311. geo.computeBoundingSphere() //for raycaster and visi
  312. return geo
  313. }
  314. }
  315. export {LineDraw, MeshDraw} ;