1/* 2<?xml version='1.0' standalone='yes' ?> 3<!-- xml header for scripts & plugin manager --> 4<script> 5 <name>Join Objects</name> 6 <author>Julian MacDonald</author> 7 <version>1.8</version> 8 <beta>2</beta> 9 <date>23/08/2007</date> 10 <description> 11This script joins a set of selected objects into a single triangle mesh 12non-triangle meshes are converted to triangle meshes using the user-entered Max Error. 13Smoothness values for vertices and edges are retained. There is also the ability to 'weld' vertices 14within a certain distance of each other. 15Textures are also partly retained. 16Still to do: support for layered textures 17Problems: texture scaling/orientation/position not retained correctly (need access to methods - Peter to allow in next version) 18 if a texture is used more than once with different mappings, only the last mapping is transferred. 19 </description> 20 <comments> 21 </comments> 22</script> 23*/ 24 25 26scene=window.getScene(); 27sel=scene.getSelection(); 28// 29// make sure at least 2 objects have been selected 30if (sel.length<2) 31{ 32 new MessageDialog(window,"Select at least 2 objects"); 33 return; 34} 35// 36ObjInfo=new ObjectInfo[sel.length]; // array for holding ObjInfos for each selected object 37// 38// 39// get a name for the new object and tolerance for 40// triangle mesh conversion if required 41// 42nameField=new BTextField("JoinedMesh",20); 43tolField=new ValueField(0.02,ValueField.POSITIVE); 44yesWeld = new BCheckBox(); 45weldTolField=new ValueField(0.01,ValueField.POSITIVE); 46yesTex=new BCheckBox(); 47sp1=new Spacer(nameField,nameField); 48sp2=new Spacer(nameField,nameField); 49sp3=new Spacer(nameField,nameField); 50// 51widgets=new Widget[]{nameField,sp1,tolField,sp2,yesWeld,weldTolField,sp3,yesTex}; 52labels=new String[]{"Name:",null,"Surface Accuracy:",null,"Weld Close Points:","Weld Distance:",null,"Retain Textures:"}; 53dlg = new ComponentsDialog(window, "Options for Resulting Mesh:",widgets,labels); 54if (!dlg.clickedOk()) return; 55// 56objname = nameField.getText(); 57tol=tolField.getValue(); 58wantsWeld=yesWeld.getState(); 59weldTol=weldTolField.getValue(); 60wantsTex=yesTex.getState(); 61// 62// go through selected objects and get ObjInfos 63// convert any non-triangle meshes to triangle meshes 64// 65count=0; 66for(int i=0;i<sel.length;i++) 67{ 68 selObjInfo=scene.getObject(sel[i]); // get the ith ObjInfo 69 if (selObjInfo.object instanceof TriangleMesh) // if it's a triangle mesh get it 70 { 71 ObjInfo[i]=scene.getObject(sel[i]); 72 } 73 else // otherwise convert to a triangle mesh 74 { 75 Obj=selObjInfo.object.convertToTriangleMesh(tol); 76 ObjInfo[i]=new ObjectInfo(Obj,selObjInfo.coords,""); 77 } 78} 79// 80// 81// get number of vertices/faces in joined mesh 82vtot=0; 83ftot=0; 84etot=0; 85numV=new int[sel.length]; 86for (i=0;i<sel.length;i++) 87{ 88 v=ObjInfo[i].object.getVertices(); 89 f=ObjInfo[i].object.getFaces(); 90 e=ObjInfo[i].object.getEdges(); 91 numV[i]=v.length; // number of vertices in each object 92 vtot=vtot+v.length; // total number of vertices in resulting mesh 93 ftot=ftot+f.length; // total number of faces in resulting mesh 94 etot=etot+e.length; 95} 96// 97va=new Vec3[vtot]; // create an array to hold the new mesh vertex coordinates 98vs=new float[vtot]; // create an array to hold the new mesh vertex Smoothness values 99es=new float[etot]; // create an array to hold the new mesh edge Smoothness values 100fc=new int[ftot][3]; // create an array to hold the new mesh face data 101count=0; 102ecount=0; 103fcount=0; 104disp=0; 105// cycle through the selected objects 106for (i=0;i<sel.length;i++) 107{ 108 // get vertex information and put into array for new mesh 109 v=ObjInfo[i].object.getVertices(); 110 mv=ObjInfo[i].coords.fromLocal(); 111 for (j=0;j<v.length;j++) 112 { 113 newV=new Vec3(v[j].r); 114 mv.transform(newV); 115 va[count]=newV; 116 vs[count]=v[j].smoothness; 117 count++; 118 } 119 // get edge smoothness values and put into array for new mesh 120 e=ObjInfo[i].object.getEdges(); 121 for (k=0;k<e.length;k++) 122 { 123 es[ecount]=e[k].smoothness; 124 ecount++; 125 } 126 // get face information and put into array for new mesh 127 f=ObjInfo[i].object.getFaces(); 128 for (j=0;j<f.length;j++) 129 { 130 fc[fcount][0]=f[j].v1+disp; 131 fc[fcount][1]=f[j].v2+disp; 132 fc[fcount][2]=f[j].v3+disp; 133 fcount++; 134 } 135 disp=disp+numV[i]; 136} 137// 138// 139// add the new object to the scene 140newMesh=new TriangleMesh(va,fc); 141// put original smoothness values back 142newVerts=newMesh.getVertices(); 143for (i=0;i<newVerts.length;i++) 144{ 145 newVerts[i].smoothness=vs[i]; 146} 147// 148newEdges=newMesh.getEdges(); 149for (i=0;i<newEdges.length;i++) 150{ 151 newEdges[i].smoothness=es[i]; 152} 153// 154// 155// 156// TEXTURES 157if (wantsTex) 158{ 159// ** Transfer the texture information from the original objects to the new mesh ** 160// 161layTex=new LayeredTexture(newMesh); // create a new LayeredTexture 162layMap=new LayeredMapping(newMesh,layTex); // get the associated LayeredMapping 163// 164tex=new Texture[sel.length]; // array for textures of each object 165texMap=new TextureMapping[sel.length]; // array for texture mappings for each object texture 166// 167// loop through selected objects (and hence individual textures) and get the texture details 168fc=0; // face count 169vc=0; // vertex count 170for (i=0;i<sel.length;i++) 171{ 172 tex[i]=ObjInfo[i].object.getTexture(); // get the texture for the ith object 173 texMap[i]=ObjInfo[i].object.getTextureMapping().duplicate(); // get the mapping (i.e. type and scaling, orientation etc.) 174 layMap.addLayer(tex[i]); // add the ith object's texture to the layered texture 175 layMap.setLayerMode(i,0); 176} 177newMesh.setTexture(layTex,layMap); // apply the layered texture to the new mesh 178// 179// The basic method here is to assign each layer of the new mesh's layered texture per-face 180// and then map the appropriate texture layer to the part of the mesh corresponding to the original object 181// 182faceParVal=new FaceParameterValue[sel.length]; 183for (h=0;h<sel.length;h++) 184{ 185 // h is the texture number (i.e. h=0 is the texture of the first object, h=1 for second object etc.) 186 // i is the layer number 187 // texture numbers are ordered opposite to the layers they are in 188 // 189 texVal=new double[ftot]; // array to hold texture parameter values for each face 190 i=sel.length-1-h; // layer number 191 texParams=new TextureParameter[texMap[h].getParameters().length]; // set up array for any texture parameters 192// print(texMap[h].getParameters()); 193 texParams=texMap[h].getParameters(); //get the texture parameters (if any) within the hth texture 194 // 195 tempParam=layMap.getLayerParameters(i); 196 faceParVal[i]=new FaceParameterValue(newMesh,tempParam[0]); 197 // set the parameter values to 0 for the other parts of the mesh 198 for (f=0;f<fc;f++) 199 { 200 texVal[f]=0.0; 201 } 202 // set the parameter values to 1 for the relevant faces 203 for (f=fc;f<fc+ObjInfo[h].object.getFaces().length;f++) 204 { 205 texVal[f]=1.0; 206 } 207 // set the parameter values to 0 for the other parts of the mesh 208 for (f=fc+ObjInfo[h].object.getFaces().length;f<ftot;f++) 209 { 210 texVal[f]=0.0; 211 } 212 newMesh.setParameterValue(tempParam[0],faceParVal[i]); 213 faceParVal[i].setValue(texVal); 214 // 215 // correct the texture mapping centre 216 // 217 // for linear 3D mapping 218 if (texMap[i] instanceof LinearMapping3D) 219 { 220 texScale=texMap[i].getScale(); 221 texCent=texMap[i].getCenter(); 222 scaleCorr=new Vec3(1/texScale.x,1/texScale.y,1/texScale.z); 223 scaleCorr.multiply(ObjInfo[i].coords.getOrigin()); 224 texMap[i].setCenter(scaleCorr); 225 } 226 // for 2D projection mapping 227 if (texMap[i] instanceof ProjectionMapping) 228 { 229 texScale=texMap[i].getScale(); 230 texCent=texMap[i].getCenter(); 231 scaleCorr1=new Vec2(1/texScale.x,1/texScale.y); 232 scaleCorr=new Vec2(scaleCorr1.x*ObjInfo[i].coords.getOrigin().x+texCent.x,scaleCorr1.y*ObjInfo[i].coords.getOrigin().y+texCent.y); 233 texMap[i].setCenter(scaleCorr); 234 } 235 // for cylindrical or spherical mapping 236 if ((texMap[i] instanceof CylindricalMapping)||(texMap[i] instanceof SphericalMapping)) 237 { 238 // paramVal=ObjInfo[i].object.getParameterValues(); //get texture coordinates 239 // texCoordsX=paramVal[0].getValue(); 240 // texCoordsY=paramVal[1].getValue(); 241 // texCoordsZ=paramVal[2].getValue(); 242 // for (q=0;q<texCoordsX.length;q++) 243 // { 244 // texCoordsX[q]=texCoordsX[q]+ObjInfo[i].coords.getOrigin().x; 245 // texCoordsY[q]=texCoordsY[q]+ObjInfo[i].coords.getOrigin().y; 246 // texCoordsZ[q]=texCoordsZ[q]+ObjInfo[i].coords.getOrigin().z; 247 // } 248 // paramVal[0].setValue(texCoordsX); 249 // paramVal[1].setValue(texCoordsY); 250 // paramVal[2].setValue(texCoordsZ); 251 texMap[i].setBoundToSurface(true); 252 } 253 layMap.setLayerMapping(h,texMap[i]); // set the mapping correctly 254 // cycle through the texture parameters, determine the mapping type and set the values for the 255 // relevant part of the new mesh 256 // 257 for (j=0;j<texParams.length;j++) 258 { 259 paramVal=ObjInfo[h].object.getParameterValue(texParams[j]); // determine mapping type 260 // 261 // *** per-object texture parameters *** 262 if (paramVal instanceof ConstantParameterValue) 263 { 264 tpVal=new double[ftot]; // array to hold texture parameter values for each face of new mesh 265 val=paramVal.getValue(); // single value containing value of the parameter for the original object 266 // set the parameter values to 0 for the other parts of the mesh 267 for (f=0;f<fc;f++) 268 { 269 tpVal[f]=0.0; 270 } 271 // set the parameter values as per the original object for the relevant faces 272 for (f=fc;f<fc+ObjInfo[h].object.getFaces().length;f++) 273 { 274 tpVal[f]=val; 275 } 276 // set the parameter values to 0 for the other parts of the mesh 277 for (f=fc+ObjInfo[h].object.getFaces().length;f<ftot;f++) 278 { 279 tpVal[f]=0.0; 280 } 281 paramVal2=new FaceParameterValue(tpVal); // make a new FaceParameterValue to apply to new mesh 282 newMesh.setParameterValue(texParams[j],paramVal2); // apply it 283 } 284 // 285 // 286 // *** per-face texture parameters *** 287 if (paramVal instanceof FaceParameterValue) 288 { 289 tpVal=new double[ftot]; // array to hold texture parameter values for each face of new mesh 290 valPerFace=paramVal.getValue(); // array containing values of the parameter for each face of original object 291 // set the parameter values to 0 for the other parts of the mesh 292 for (f=0;f<fc;f++) 293 { 294 tpVal[f]=0.0; 295 } 296 // set the parameter values as per the original object for the relevant faces 297 for (f=fc;f<fc+ObjInfo[h].object.getFaces().length;f++) 298 { 299 tpVal[f]=valPerFace[f-fc]; 300 } 301 // set the parameter values to 0 for the other parts of the mesh 302 for (f=fc+ObjInfo[h].object.getFaces().length;f<ftot;f++) 303 { 304 tpVal[f]=0.0; 305 } 306 paramVal2=new FaceParameterValue(tpVal); // make a new FaceParameterValue to apply to new mesh 307 newMesh.setParameterValue(texParams[j],paramVal2); // apply it 308 } 309 // 310 // 311 // *** per-vertex parameters *** 312 if (paramVal instanceof VertexParameterValue) 313 { 314 tpVal=new double[vtot]; // array to hold texture parameter values for each vertex of new mesh 315 valPerVert=paramVal.getValue(); // array containing values of the parameter for each vertex of original object 316 // set the parameter values to 0 for the other parts of the mesh 317 for (v=0;v<vc;v++) 318 { 319 tpVal[v]=0.0; 320 } 321 // set the parameter values as per the original object for the relevant vertices 322 for (v=vc;v<vc+ObjInfo[h].object.getVertices().length;v++) 323 { 324 tpVal[v]=valPerVert[v-vc]; 325 } 326 // set the parameter values to 0 for the other parts of the mesh 327 for (v=vc+ObjInfo[h].object.getVertices().length;v<vtot;v++) 328 { 329 tpVal[v]=0.0; 330 } 331 paramVal2=new VertexParameterValue(tpVal); // make a new VertexParameterValue to apply to new mesh 332 newMesh.setParameterValue(texParams[j],paramVal2); // apply it 333 print(paramVal2.getValue()); 334 } 335 // 336 // 337 // *** per face-vertex texture parameters *** 338 if (paramVal instanceof FaceVertexParameterValue) 339 { 340 tpVal=new double[3][ftot]; // array to hold texture parameter values for each face-vertex of new mesh 341 valPerFace=paramVal.getValue(); //array containing values of the parameter for each face-vertex of original object 342 // set the parameter values to 0 for the other parts of the mesh 343 for (f=0;f<fc;f++) 344 { 345 tpVal[0][f]=0.0; 346 tpVal[1][f]=0.0; 347 tpVal[2][f]=0.0; 348 } 349 // set the parameter values as per the original object for the relevant face-vertices 350 for (f=fc;f<fc+ObjInfo[h].object.getFaces().length;f++) 351 { 352 tpVal[0][f]=valPerFace[0][f-fc]; 353 tpVal[1][f]=valPerFace[1][f-fc]; 354 tpVal[2][f]=valPerFace[2][f-fc]; 355 } 356 // set the parameter values to 0 for the other parts of the mesh 357 for (f=fc+ObjInfo[h].object.getFaces().length;f<ftot;f++) 358 { 359 tpVal[0][f]=0.0; 360 tpVal[1][f]=0.0; 361 tpVal[2][f]=0.0; 362 } 363 paramVal2=new FaceVertexParameterValue(tpVal); // make a new FaceVertexParameterValue to apply to new mesh 364 newMesh.setParameterValue(texParams[j],paramVal2); // apply it 365 } 366 } 367 368 // 369 fc=fc+ObjInfo[h].object.getFaces().length; 370 vc=vc+ObjInfo[h].object.getVertices().length; 371} 372// 373// add the new mesh to the scene. 374// 375newMesh.setTexture(layTex,layMap); // apply the layered texture to the new mesh 376} 377// 378// 379// 380// WELD 381// 382if (wantsWeld) 383{ 384 vert=newVerts; 385 face=newMesh.getFaces(); 386 edge=newEdges; 387 // 388 reassignV=new int[vert.length]; 389 reposV=new int[vert.length]; 390 numCoVert=0; 391 newVertIndex=new int [vert.length]; 392 vToBeDel=new int[vert.length]; 393 for (i=0;i<vert.length;i++) 394 { 395 reassignV[i]=-1; 396 reposV[i]=i; 397 } 398 // 399 for (v1=0;v1<vert.length;v1++) 400 { 401 for (v2=v1+1;v2<vert.length;v2++) 402 { 403 Dist=vert[v1].r.distance(vert[v2].r); 404 if ((Dist<weldTol)&&(reassignV[v2]==-1)) 405 { 406 reassignV[v2]=v1; 407 for (k=v2+1;k<vert.length;k++) 408 { 409 reposV[k]--; 410 } 411 numCoVert++; 412 } 413 } 414 } 415 if (numCoVert==0) 416 { 417 new MessageDialog(window, "There are no vertices within the required tolerance"); 418 return; 419 } 420 // build new index 421 for (i=0;i<vert.length;i++) 422 { 423 if (reassignV[i]!=-1) newVertIndex[i]=reposV[reassignV[i]]; else newVertIndex[i]=reposV[i]; 424 } 425 // 426 // create new vertices skipping 'duplicates' 427 // 428 vCount=0; 429 newVert=new TriangleMesh.Vertex[vert.length-numCoVert]; 430 for (i=0;i<vert.length;i++) // cycle through the vertices 431 { 432 skip=0; 433 if (reassignV[i]==-1) 434 { 435 newVert[vCount]=vert[i]; 436 vCount++; 437 } 438 } 439 // 440 // reassign the face vertices 441 faceInfo=new int [face.length][3]; 442 for (f=0;f<face.length;f++) 443 { 444 faceInfo[f][0]=newVertIndex[face[f].v1]; 445 faceInfo[f][1]=newVertIndex[face[f].v2]; 446 faceInfo[f][2]=newVertIndex[face[f].v3]; 447 } 448 // 449 newMesh.setShape(newVert,faceInfo); 450 } 451// 452// 453window.addObject(newMesh,new CoordinateSystem(),objname,null); 454