void CalculateTangentAndBinormal(const MQPoint& v0, const MQPoint& v1, const MQPoint& v2, const MQPoint& n0, const MQPoint& n1, const MQPoint& n2, const MQCoordinate& t0, const MQCoordinate& t1, const MQCoordinate& t2, MQPoint& tan0, MQPoint& tan1, MQPoint& tan2, MQPoint& bin0, MQPoint& bin1, MQPoint& bin2) { MQPoint edge1, edge2, crossP; edge1.x = v1.x - v0.x; edge1.y = t1.u - t0.u; // s-vector - don't need to compute this multiple times edge1.z = t1.v - t0.v; // t-vector edge2.x = v2.x - v0.x; edge2.y = t2.u - t0.u; // another s-vector edge2.z = t2.v - t0.v; // another t-vector crossP = Normalize(GetCrossProduct(edge1, edge2)); if(fabs(crossP.x) < 1e-4f){ crossP.x = 1.0f; } tan0.x = tan1.x = tan2.x = -crossP.y / crossP.x; bin0.x = bin1.x = bin2.x = -crossP.z / crossP.x; // y, s, t edge1.x = v1.y - v0.y; edge2.x = v2.y - v0.y; crossP = Normalize(GetCrossProduct(edge1, edge2)); if(fabs(crossP.x) < 1e-4f){ crossP.x = 1.0f; } tan0.y = tan1.y = tan2.y = -crossP.y / crossP.x; bin0.y = bin1.y = bin2.y = -crossP.z / crossP.x; // z, s, t edge1.x = v1.z - v0.z; edge2.x = v2.z - v0.z; crossP = Normalize(GetCrossProduct(edge1, edge2)); if(fabs(crossP.x) < 1e-4f){ crossP.x = 1.0f; } tan0.z = tan1.z = tan2.z = -crossP.y / crossP.x; bin0.z = bin1.z = bin2.z = -crossP.z / crossP.x; // Orthonormalize to normal tan0 -= n0 * GetInnerProduct(tan0, n0); tan1 -= n1 * GetInnerProduct(tan1, n1); tan2 -= n2 * GetInnerProduct(tan2, n2); bin0 -= n0 * GetInnerProduct(bin0, n0); bin1 -= n1 * GetInnerProduct(bin1, n1); bin2 -= n2 * GetInnerProduct(bin2, n2); // Normalize tangents and binormals tan0 = Normalize(tan0); tan1 = Normalize(tan1); tan2 = Normalize(tan2); bin0 = Normalize(bin0); bin1 = Normalize(bin1); bin2 = Normalize(bin2); }
void CalculateTangent(const MQPoint& v0, const MQPoint& v1, const MQPoint& v2, const MQPoint& normal, const MQCoordinate& t0, const MQCoordinate& t1, const MQCoordinate& t2, MQPoint& tangent) { MQPoint edge1, edge2, crossP; edge1.x = v1.x - v0.x; edge1.y = t1.u - t0.u; // s-vector - don't need to compute this multiple times edge1.z = t1.v - t0.v; // t-vector edge2.x = v2.x - v0.x; edge2.y = t2.u - t0.u; // another s-vector edge2.z = t2.v - t0.v; // another t-vector crossP = Normalize(GetCrossProduct(edge1, edge2)); if(fabs(crossP.x) < 1e-4f){ crossP.x = 1.0f; } float tanX = -crossP.y / crossP.x; tangent.x = tanX; // y, s, t edge1.x = v1.y - v0.y; edge2.x = v2.y - v0.y; crossP = Normalize(GetCrossProduct(edge1, edge2)); if(fabs(crossP.x) < 1e-4f){ crossP.x = 1.0f; } float tanY = -crossP.y / crossP.x; tangent.y = tanY; // z, s, t edge1.x = v1.z - v0.z; edge2.x = v2.z - v0.z; crossP = Normalize(GetCrossProduct(edge1, edge2)); if(fabs(crossP.x) < 1e-4f){ crossP.x = 1.0f; } float tanZ = -crossP.y / crossP.x; tangent.z = tanZ; // Orthonormalize to normal tangent -= normal * GetInnerProduct(tangent, normal); // Normalize tangents tangent = Normalize(tangent); }
//--------------------------------------------------------------------------- // GetNormal() // Get a normal vector for a face constituted by three points. // 3点からなる面の法線を得る //--------------------------------------------------------------------------- MQPoint GetNormal(const MQPoint& p0, const MQPoint& p1, const MQPoint& p2) { MQPoint ep = GetCrossProduct(p1-p2, p0-p1); if(ep == MQPoint(0,0,0)) return MQPoint(0,0,0); return ep / GetSize(ep); }
/* * *************************************************************************** * Routine: GemMesh_fromSurfaceMeshes * * Author: Johan Hake ([email protected]) * * Purpose: Use tetgen to generate a GemMesh from a surface mesh * *************************************************************************** */ GemMesh* GemMesh_fromSurfaceMeshes(SurfaceMesh** surfmeshes, int num_surface_meshes, char* tetgen_params) { unsigned int j, sm_index, num_vertices = 0, num_faces = 0; unsigned int num_regions = 0, num_holes = 0; SurfaceMesh* surfmesh; FLTVECT normal, midpoint; INT3VECT face0; tetgenio in, out; tetgenio::facet *f; tetgenio::polygon *p; in.firstnumber = 1; // Collect info from the surface meshes for (sm_index=0; sm_index<num_surface_meshes; sm_index++) { // Get the surface mesh surfmesh = surfmeshes[sm_index]; // Check if neighborlist is created if (surfmesh->neighbor_list == NULL) SurfaceMesh_createNeighborlist(surfmesh); if (surfmesh->num_vertices == 0 || surfmesh->num_faces == 0) { printf("The %d:th surface mesh is empty. Abandoning "\ "tetrahedralization.\n", sm_index); return GemMesh_ctor(0, 0, false); } if (!surfmesh->closed) { printf("The %d:th surface mesh is not closed. Abandoning "\ "tetrahedralization.\n", sm_index); return GemMesh_ctor(0, 0, false); } // Bump counters if (!surfmesh->as_hole) num_regions += 1; else num_holes += 1; num_vertices += surfmesh->num_vertices; num_faces += surfmesh->num_faces; } // We need at least one region if (num_regions < 1) { printf("Expected at least one surface mesh which is not a hole.\n"); return GemMesh_ctor(0, 0, false); } // Assign memory printf("num vertices: %d\n", num_vertices); printf("num faces: %d\n", num_faces); in.numberofpoints = num_vertices; in.pointlist = new REAL[in.numberofpoints * 3]; in.numberoffacets = num_faces; in.facetlist = new tetgenio::facet[in.numberoffacets]; in.facetmarkerlist = new int[in.numberoffacets]; printf("num regions: %d\n", num_regions); in.numberofregions = num_regions; in.regionlist = new REAL[num_regions*5]; if (num_holes > 0) { printf("num holes: %d\n", num_holes); in.numberofholes = num_holes; in.holelist = new REAL[num_holes*3]; } // Reset counters num_vertices = num_faces = num_regions = num_holes = 0; // Iterate over the surface meshes and assign info for (sm_index=0; sm_index<num_surface_meshes; sm_index++) { // Get the surface mesh surfmesh = surfmeshes[sm_index]; // Assign vertex information for (j = 0; j < surfmesh->num_vertices; j++) { in.pointlist[j*3 + 0 + num_vertices*3] = surfmesh->vertex[j].x; in.pointlist[j*3 + 1 + num_vertices*3] = surfmesh->vertex[j].y; in.pointlist[j*3 + 2 + num_vertices*3] = surfmesh->vertex[j].z; } // Assign face information for (j = 0; j < surfmesh->num_faces; j++) { f = &in.facetlist[j+num_faces]; f->holelist = (REAL *) NULL; f->numberofholes = 0; f->numberofpolygons = 1; f->polygonlist = new tetgenio::polygon[f->numberofpolygons]; p = &f->polygonlist[0]; p->numberofvertices = 3; p->vertexlist = new int[p->numberofvertices]; p->vertexlist[0] = surfmesh->face[j].a + in.firstnumber + num_vertices; p->vertexlist[1] = surfmesh->face[j].b + in.firstnumber + num_vertices; p->vertexlist[2] = surfmesh->face[j].c + in.firstnumber + num_vertices; in.facetmarkerlist[j+num_faces] = surfmesh->face[j].m == -1 ? 0 : surfmesh->face[j].m; } // Get region or hole coordinate by using a face face0 = surfmesh->face[0]; // Face normal normal = GetCrossProduct(surfmesh, face0.a, face0.b, face0.c); // Midpoint of face midpoint.x = surfmesh->vertex[face0.a].x/3; midpoint.y = surfmesh->vertex[face0.a].y/3; midpoint.z = surfmesh->vertex[face0.a].z/3; midpoint.x += surfmesh->vertex[face0.b].x/3; midpoint.y += surfmesh->vertex[face0.b].y/3; midpoint.z += surfmesh->vertex[face0.b].z/3; midpoint.x += surfmesh->vertex[face0.c].x/3; midpoint.y += surfmesh->vertex[face0.c].y/3; midpoint.z += surfmesh->vertex[face0.c].z/3; // Weight based on length double weight = sqrt(pow(surfmesh->vertex[face0.a].x-\ surfmesh->vertex[face0.b].x, 2) + \ pow(surfmesh->vertex[face0.a].y-\ surfmesh->vertex[face0.b].y, 2) + \ pow(surfmesh->vertex[face0.a].z-\ surfmesh->vertex[face0.b].z, 2)); // Add region information if (!surfmesh->as_hole) { // Calculate region info using face information // FIXME: Why should we add the normal values? // FIXME: If normal is pointing outwards we should substract to // FIXME: get a point inside the surface mesh.... in.regionlist[num_regions*5 + 0] = midpoint.x + normal.x*weight; in.regionlist[num_regions*5 + 1] = midpoint.y + normal.y*weight; in.regionlist[num_regions*5 + 2] = midpoint.z + normal.z*weight; // Set region marker (attribute) in.regionlist[num_regions*5 + 3] = surfmesh->marker; // If volume constraints if (surfmesh->use_volume_constraint) { printf("Volume constraint: %.5f\n", surfmesh->volume_constraint); in.regionlist[num_regions*5 + 4] = surfmesh->volume_constraint; } else in.regionlist[num_regions*5 + 4] = -1; // Bump counter num_regions += 1; } else { // Calculate hole info using face information in.holelist[num_holes*3 + 0] = midpoint.x + normal.x*weight; in.holelist[num_holes*3 + 1] = midpoint.y + normal.y*weight; in.holelist[num_holes*3 + 2] = midpoint.z + normal.z*weight; // Bump counter num_holes += 1; } // Bump face and vertex counters num_vertices += surfmesh->num_vertices; num_faces += surfmesh->num_faces; } // Add boundary marker on each node // FIXME: Why? Aren't the markers set on the generatedmesh? in.pointmarkerlist = new int[in.numberofpoints]; for (j = 0; j < in.numberofpoints; j++) in.pointmarkerlist[j] = 1; // Debug in.save_nodes("plc"); in.save_poly("plc"); // Call TetGen tetrahedralize(tetgen_params, &in, &out, NULL); // Debug out.save_nodes("result"); out.save_elements("result"); out.save_faces("result"); // Convert to a generalized tetrahedral mesh structure return GemMesh_fromTetgen(out); }