📄 font3d.java
字号:
// set the previous normals to null when we are done pn1 = null; pn2 = null; }// for j }//for i } else { // if shape int m, offset=0; Point3f P2 = new Point3f(), Q2 = new Point3f(), P1=new Point3f(); Vector3f nn = new Vector3f(), nn1= new Vector3f(), nn2= new Vector3f(), nn3= new Vector3f(); Vector3f nna = new Vector3f(), nnb=new Vector3f(); float length; boolean validNormal = false; // fontExtrusion.shape is specified, and is NOT straight line for (i=0;i < islandCounts.length;i++){ for (j=0, k= 0, offset = num =0;j < islandCounts[i].length;j++){ num += islandCounts[i][j]; p1.x = outVerts[i][num - 1].x; p1.y = outVerts[i][num - 1].y; p1.z = 0.0f; q1.x = p1.x; q1.y = p1.y; q1.z = p1.z+fontExtrusion.length; p3.z = 0.0f; for (m=num-2; m >= 0; m--) { p3.x = outVerts[i][m].x; p3.y = outVerts[i][m].y; if (getNormal(p3, q1, p1, nn1)) { if (!flip_side_orient) { nn1.negate(); } goodNormal.set(nn1); break; } } for (;k < num;k++){ p2.x = outVerts[i][k].x;p2.y = outVerts[i][k].y;p2.z = 0.0f; q2.x = p2.x; q2.y = p2.y; q2.z = p2.z+fontExtrusion.length; getNormal(p1, q1, p2, nn2); p3.x = outVerts[i][(k+1)==num ? offset:(k+1)].x; p3.y = outVerts[i][(k+1)==num ? offset:(k+1)].y; p3.z = 0.0f; if (!getNormal(p3,p2,q2, nn3)) { nn3.set(goodNormal); } else { if (!flip_side_orient) { nn3.negate(); } goodNormal.set(nn3); } // Calculate normals at the point by averaging normals // of two faces on each side of the point. nna.x = (nn1.x+nn2.x); nna.y = (nn1.y+nn2.y); nna.z = (nn1.z+nn2.z); normalize(nna); nnb.x = (nn3.x+nn2.x); nnb.y = (nn3.y+nn2.y); nnb.z = (nn3.z+nn2.z); normalize(nnb); P1.x = p1.x;P1.y = p1.y;P1.z = p1.z; P2.x = p2.x;P2.y = p2.y; P2.z = p2.z; Q2.x = q2.x;Q2.y = q2.y; Q2.z = q2.z; for (m=1;m < fontExtrusion.pnts.length;m++){ q1.z = q2.z = fontExtrusion.pnts[m].x; q1.x = P1.x + nna.x * fontExtrusion.pnts[m].y; q1.y = P1.y + nna.y * fontExtrusion.pnts[m].y; q2.x = P2.x + nnb.x * fontExtrusion.pnts[m].y; q2.y = P2.y + nnb.y * fontExtrusion.pnts[m].y; if (!getNormal(p1, q1, p2, n1)) { n1.set(goodNormal); } else { if (!flip_side_orient) { n1.negate(); } goodNormal.set(n1); } if (flip_side_orient) { triAry.setCoordinate(currCoordIndex, p1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; } else { triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; triAry.setCoordinate(currCoordIndex, p1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; } triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; if (!getNormal(p2, q1, q2, n1)) { n1.set(goodNormal); } else { if (!flip_side_orient) { n1.negate(); } goodNormal.set(n1); } if (flip_side_orient) { triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; } else { triAry.setCoordinate(currCoordIndex, q1); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; triAry.setCoordinate(currCoordIndex, p2); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; } triAry.setCoordinate(currCoordIndex, q2); triAry.setNormal(currCoordIndex, n1); currCoordIndex++; p1.x = q1.x;p1.y = q1.y;p1.z = q1.z; p2.x = q2.x;p2.y = q2.y;p2.z = q2.z; }// for m p1.x = P2.x; p1.y = P2.y; p1.z = P2.z; q1.x = Q2.x; q1.y = Q2.y; q1.z = Q2.z; nn1.x = nn2.x;nn1.y = nn2.y;nn1.z = nn2.z; }// for k offset = num; }// for j }//for i }// if shape }// if fontExtrusion geo = (GeometryArrayRetained) triAry.retained; geomHash.put(ch, geo); } return geo; } static boolean getNormal(Point3f p1, Point3f p2, Point3f p3, Vector3f normal) { Vector3f v1 = new Vector3f(); Vector3f v2 = new Vector3f(); // Must compute normal v1.sub(p2, p1); v2.sub(p2, p3); normal.cross(v1, v2); normal.negate(); float length = normal.length(); if (length > 0) { length = 1 / length; normal.x *= length; normal.y *= length; normal.z *= length; return true; } return false; } // check if 2 contours are inside/outside/intersect one another // INPUT: // vertCnt1, vertCnt2 - number of vertices in 2 contours // begin1, begin2 - starting indices into vertices for 2 contours // vertices - actual vertex data // OUTPUT: // status == 1 - intersecting contours // 2 - first contour inside the second // 3 - second contour inside the first // 0 - disjoint contours(2 islands) static int check2Contours(int begin1, int end1, int begin2, int end2, Point3f[] vertices) { int i, j; boolean inside2, inside1; inside2 = pointInPolygon2D(vertices[begin1].x, vertices[begin1].y, begin2, end2, vertices); for (i=begin1+1; i < end1;i++) { if (pointInPolygon2D(vertices[i].x, vertices[i].y, begin2, end2, vertices) != inside2) { return 1; //intersecting contours } } // Since we are using point in polygon test and not // line in polygon test. There are cases we miss the interesting // if we are not checking the reverse for all points. This happen // when two points form a line pass through a polygon but the two // points are outside of it. inside1 = pointInPolygon2D(vertices[begin2].x, vertices[begin2].y, begin1, end1, vertices); for (i=begin2+1; i < end2;i++) { if (pointInPolygon2D(vertices[i].x, vertices[i].y, begin1, end1, vertices) != inside1) { return 1; //intersecting contours } } if (!inside2) { if (!inside1) { return 0; // disjoint countours } // inside2 = false and inside1 = true return 3; // second contour inside first } // must be inside2 = true and inside1 = false // Note that it is not possible inside2 = inside1 = true // unless two contour overlap to each others. // return 2; // first contour inside second } // Test if 2D point (x,y) lies inside polygon represented by verts. // z-value of polygon vertices is ignored. Sent only to avoid data-copy. // Uses ray-shooting algorithm to compute intersections along +X axis. // This algorithm works for all polygons(concave, self-intersecting) and // is best solution here due to large number of polygon vertices. // Point is INSIDE if number of intersections is odd, OUTSIDE if number // of intersections is even. static boolean pointInPolygon2D(float x, float y, int begIdx, int endIdx, Point3f[] verts){ int i, num_intersections = 0; float xi; for (i=begIdx;i < endIdx-1;i++) { if ((verts[i].y >= y && verts[i+1].y >= y) || (verts[i].y < y && verts[i+1].y < y)) continue; xi = verts[i].x + (verts[i].x - verts[i+1].x)*(y - verts[i].y)/ (verts[i].y - verts[i+1].y); if (x < xi) num_intersections++; } // Check for segment from last vertex to first vertex. if (!((verts[i].y >= y && verts[begIdx].y >= y) || (verts[i].y < y && verts[begIdx].y < y))) { xi = verts[i].x + (verts[i].x - verts[begIdx].x)*(y - verts[i].y)/ (verts[i].y - verts[begIdx].y); if (x < xi) num_intersections++; } return ((num_intersections % 2) != 0); } static final boolean normalize(Vector3f v) { float len = v.length(); if (len > 0) { len = 1.0f/len; v.x *= len; v.y *= len; v.z *= len; return true; } return false; } // A Tree of islands form based on contour, each parent's contour // enclosed all the child. We built this since Triangular fail to // handle the case of multiple concentrated contours. i.e. if // 4 contours A > B > C > D. Triangular will fail recongized // two island, one form by A & B and the other by C & D. // Using this tree we can separate out every 2 levels and pass // in to triangular to workaround its limitation. static private class IslandsNode { private ArrayList islandsList = null; int startIdx, endIdx; IslandsNode(int startIdx, int endIdx) { this.startIdx = startIdx; this.endIdx = endIdx; islandsList = null; } void addChild(IslandsNode node) { if (islandsList == null) { islandsList = new ArrayList(5); } islandsList.add(node); } void removeChild(IslandsNode node) { islandsList.remove(islandsList.indexOf(node)); } IslandsNode getChild(int idx) { return (IslandsNode) islandsList.get(idx); } int numChild() { return (islandsList == null ? 0 : islandsList.size()); } int numVertices() { return endIdx - startIdx; } void insert(IslandsNode newNode, Point3f[] vertices) { boolean createNewLevel = false; if (islandsList != null) { IslandsNode childNode; int status; for (int i=numChild()-1; i>=0; i--) { childNode = getChild(i); status = check2Contours(newNode.startIdx, newNode.endIdx, childNode.startIdx, childNode.endIdx, vertices); switch (status) { case 2: // newNode inside childNode, go down recursively childNode.insert(newNode, vertices); return; case 3:// childNode inside newNode, // continue to search other childNode also // inside this one and group them together. newNode.addChild(childNode); createNewLevel = true; break; default: // intersecting or disjoint } } } if (createNewLevel) { // Remove child in newNode from this for (int i=newNode.numChild()-1; i>=0; i--) { removeChild(newNode.getChild(i)); } // Add the newNode to parent } addChild(newNode); } // Return a list of node with odd number of level void collectOddLevelNode(UnorderList list, int level) { if ((level % 2) == 1) { list.add(this); } if (islandsList != null) { level++; for (int i=numChild()-1; i>=0; i--) { getChild(i).collectOddLevelNode(list, level); } } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -