home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Freeware 25 / FreelogHS25.iso / Dessin / ArtOfIllusion2.2.1 / Scripts / Tools / Sculpt.bsh < prev    next >
Text File  |  2005-06-11  |  5KB  |  163 lines

  1. /*
  2. <?xml version='1.0' standalone='yes' ?>
  3.  
  4. <script>
  5.     <name>Sculpt</name>
  6.     <author>Peter Eastman (peastman@users.sourceforge.net)</author>
  7.     <version>1.7</version>
  8.     <date>04/03/2004</date>
  9.     <description>
  10. This script takes a closed curve and creates a 3D surface which has that curve as its profile.
  11. It was inspired by the Teddy modelling program by Takeo Igarashi.
  12. This is intended to be a prototype for a new modelling tool in Art of Illusion.
  13.     </description>
  14. </script>
  15. */
  16.  
  17. // Given a triangle mesh, this function determines which vertices are on the boundary.
  18.  
  19. findBoundaryVerts(mesh)
  20. {
  21.   vert = mesh.getVertices();
  22.   edge = mesh.getEdges();
  23.   onBoundary = new boolean [vert.length];
  24.   for (i = 0; i < edge.length; i++)
  25.     if (edge[i].f2 == -1)
  26.       onBoundary[edge[i].v1] = onBoundary[edge[i].v2] = true;
  27.   return onBoundary;
  28. }
  29.  
  30. // This function calculates the squared distance between a point and an edge.
  31.  
  32. vertEdgeDistance2(point, end1, end2)
  33. {
  34.   v = end2.minus(end1);
  35.   len = v.length();
  36.   if (len < 1e-10)
  37.     return point.distance2(end1);
  38.   v.scale(1.0/len);
  39.   v1 = point.minus(end1);
  40.   dot = v.dot(v1);
  41.   if (dot > len)
  42.     return end2.distance2(point);
  43.   if (dot < 0.0)
  44.     return end1.distance2(point);
  45.   v1.subtract(v.times(v.dot(v1)));
  46.   return v1.length2();
  47. }
  48.  
  49. // Given a distance at every vertex, find the maximum distance in the local neighborhood
  50. // of each vertex.
  51.  
  52. findMaxLocalDistance(dist, edge)
  53. {
  54.   maxDist = new double [dist.length];
  55.   for (i = 0; i < maxDist.length; i++)
  56.     maxDist[i] = dist[i];
  57.   for (i = 0; i < edge.length; i++)
  58.   {
  59.     if (dist[edge[i].v1] > maxDist[edge[i].v2])
  60.       maxDist[edge[i].v2] = dist[edge[i].v1];
  61.     if (dist[edge[i].v2] > maxDist[edge[i].v1])
  62.       maxDist[edge[i].v1] = dist[edge[i].v2];
  63.   }
  64.   return maxDist;
  65. }
  66.  
  67. // Get the curve to sculpt.
  68.  
  69. scene = window.getScene();
  70. sel = scene.getSelection();
  71. if (sel.length != 1 || !(scene.getObject(sel[0]).object instanceof Curve) || !scene.getObject(sel[0]).object.isClosed())
  72. {
  73.   new MessageDialog(window, "Please select a single closed curve to sculpt.");
  74.   return;
  75. }
  76. info = scene.getObject(sel[0]);
  77.  
  78. // Convert it to a triangle mesh and subdivide it twice.
  79.  
  80. mesh = info.object.convertToTriangleMesh(0.1);
  81. tex = scene.getDefaultTexture();
  82. mesh.setTexture(tex, tex.getDefaultMapping());
  83. mesh = TriangleMesh.subdivideEdges(mesh, null, Double.MAX_VALUE);
  84. mesh = TriangleMesh.subdivideEdges(mesh, null, Double.MAX_VALUE);
  85.  
  86. // There may still be some interior edges which connect two boundary vertices.
  87. // Subdivide them.
  88.  
  89. onBoundary = findBoundaryVerts(mesh);
  90. edge = mesh.getEdges();
  91. split = new boolean [edge.length];
  92. for (i = 0; i < edge.length; i++)
  93.   split[i] = (edge[i].f2 != -1 && onBoundary[edge[i].v1] && onBoundary[edge[i].v2]);
  94. mesh = TriangleMesh.subdivideLinear(mesh, split);
  95.  
  96. // Calculate the squared distance from every interior vertex to the boundary.
  97.  
  98. onBoundary = findBoundaryVerts(mesh);
  99. vert = mesh.getVertices();
  100. edge = mesh.getEdges();
  101. dist2 = new double [vert.length];
  102. for (i = 0; i < vert.length; i++)
  103. {
  104.   if (onBoundary[i])
  105.     continue;
  106.   dist2[i] = Double.MAX_VALUE;
  107.   for (j = 0; j < edge.length; j++)
  108.     if (edge[j].f2 == -1)
  109.     {
  110.       d2 = vertEdgeDistance2(vert[i].r, vert[edge[j].v1].r, vert[edge[j].v2].r);
  111.       if (d2 < dist2[i])
  112.         dist2[i] = d2;
  113.     }
  114. }
  115.  
  116. // For every vertex, find the vertex in its neighborhood which is farthest from
  117. // the boundary.  This gives the "local radius".
  118.  
  119. maxDist2 = findMaxLocalDistance(dist2, edge);
  120. //maxDist2 = findMaxLocalDistance(maxDist2, edge);
  121.  
  122. // Create a new mesh by "doubling" every face and interior vertex.
  123.  
  124. pairIndex = new int [vert.length];
  125. numVert = vert.length;
  126. for (i = 0; i < onBoundary.length; i++)
  127.   if (!onBoundary[i])
  128.     pairIndex[i] = numVert++;
  129. face = mesh.getFaces();
  130. newFace = new int [face.length*2][3];
  131. for (i = 0; i < face.length; i++)
  132. {
  133.   j = face.length+i;
  134.   newFace[i][0] = face[i].v1;
  135.   newFace[i][1] = face[i].v2;
  136.   newFace[i][2] = face[i].v3;
  137.   newFace[j][0] = (onBoundary[face[i].v1] ? face[i].v1 : pairIndex[face[i].v1]);
  138.   newFace[j][1] = (onBoundary[face[i].v3] ? face[i].v3 : pairIndex[face[i].v3]);
  139.   newFace[j][2] = (onBoundary[face[i].v2] ? face[i].v2 : pairIndex[face[i].v2]);
  140. }
  141.  
  142. // Construct the new vertices, offsetting every interior vertex along the normal.
  143.  
  144. norm = mesh.getNormals();
  145. newVert = new TriangleMesh.Vertex [numVert];
  146. for (i = 0; i < vert.length; i++)
  147. {
  148.   newVert[i] = vert[i];
  149.   if (!onBoundary[i])
  150.   {
  151.     newVert[pairIndex[i]] = new TriangleMesh.Vertex(mesh, vert[i]);
  152.     displace = Math.sqrt(2.0*Math.sqrt(dist2[i]*maxDist2[i])-dist2[i]);
  153.     newVert[i].r.add(norm[i].times(displace));
  154.     newVert[pairIndex[i]].r.subtract(norm[i].times(displace));
  155.   }
  156. }
  157.  
  158. // Add the mesh to the window.
  159.  
  160. mesh = new TriangleMesh(newVert, newFace);
  161. window.addObject(mesh, info.coords.duplicate(), "Sculpted "+info.name, null);
  162. window.setSelection(scene.getNumObjects()-1);
  163.