/** * Methode die het punt bepaald waarop een ray, gerepresenteerd door a en b in een array, in een face f. * De vertices van de Face f zitten in de model waar f in zit. */ static double RayTriangleIntersection(ref unitVector direction, ref Model3D model, ref Face f) { double r = 0.0; Vec3D[] v = model.vertices; Vec3D h = f.normal;// v[f.vertices[1]].subtract(v[f.vertices[0]]).cross(v[f.vertices[2]].subtract(v[f.vertices[0]])); if (h.length() > double.Epsilon) { Vec3D normal = f.normal.normalize(); //normalize the normal, then dot it with the direction vector double NU = System.Math.Abs(normal.dot(direction.vector)); if (NU > double.Epsilon) { double d = (normal.dot(v[f.vertices[0]])) / NU; if (d > r) { Vec3D P = direction.vector.times(d); //is P on the triangle? if ((v[f.vertices[0]].subtract(P).cross(v[f.vertices[1]].subtract(P))).dot(f.normal) >= 0 && (v[f.vertices[1]].subtract(P).cross(v[f.vertices[2]].subtract(P))).dot(f.normal) >= 0 && (v[f.vertices[2]].subtract(P).cross(v[f.vertices[0]].subtract(P))).dot(f.normal) >= 0) return d; } } } //the ray will not intersect with the triangle return double.NaN; }
/** * Methode die het punt bepaald waarop een ray, gerepresenteerd door a en b in een array, in een face f. * De vertices van de Face f zitten in de model waar f in zit. */ static double RayTriangleIntersection2(ref unitVector direction, ref Model3D model, ref Face f) { double r = 0.0; double d = 0.0; Vec3D[] v = model.vertices; Vec3D u = direction.vector; Vec3D A = v[f.vertices[0]]; Vec3D B = v[f.vertices[1]]; Vec3D C = v[f.vertices[2]]; Vec3D CA = A.subtract(C); Vec3D CB = B.subtract(C); Vec3D p = u.cross(CB); double det = CA.dot(p); if (det > double.Epsilon) { double AlphaS = C.times(-1.0).dot(p); if (AlphaS >= 0 && AlphaS <= det) { Vec3D q = CA.cross(C); double BetaS = u.dot(q); if (BetaS >= 0 && AlphaS + BetaS <= det) d = (CB.dot(q)) / det; } } else if(det < 0-Double.Epsilon) { double AlphaS = C.times(-1).dot(p); if (AlphaS <= 0 && AlphaS >= det) { Vec3D q = CA.cross(C); double BetaS = u.dot(q); if (BetaS <= 0 && AlphaS + BetaS >= det) d = (CB.dot(q)) / det; } } if (d > r) r = d; //the ray will not intersect with the triangle return r; }
static double[] getMinMaxPhiTheta(ref Face f, ref Vec3D[] v, ref Model3D model) { /* int minPhi = phiTheta[0]; int minTheta = phiTheta[1]; int maxPhi = phiTheta[2]; int maxTheta = phiTheta[3]; */ double[] minmax = new double[4]; minmax[0] = double.MaxValue; minmax[1] = double.MaxValue; minmax[2] = double.MinValue; minmax[3] = double.MinValue; double minX = double.MaxValue, maxX = double.MinValue, minY = double.MaxValue, maxY = double.MinValue, minZ = double.MaxValue, maxZ = double.MinValue, meanX = 0, meanY = 0, meanZ = 0; for(int k=0; k < f.numberOfVertices; k++) { Vec3D vec = v[f.vertices[k]]; updateMinMaxMeanXYZ(ref minX,ref maxX,ref meanX,vec.x,ref minY,ref maxY,ref meanY,vec.y,ref minZ,ref maxZ,ref meanZ,vec.z,k); double phi, theta; phi = System.Math.Atan2(vec.y, vec.x); theta = System.Math.Acos((vec.z) / (vec.length())); if (minmax[0] > phi) minmax[0] = phi; if (minmax[1] > theta) minmax[1] = theta; if (minmax[2] < phi) minmax[2] = phi; if (minmax[3] < theta) minmax[3] = theta; } /* //Because of the possibility of an polygon lying on all equal or close theta, the correct theta may not be found with only the points. //Trying to solve this here. Vec3D dotPoint = new Vec3D(double.NaN,double.NaN,double.NaN); double dotDist = double.MaxValue; for (int k = 0; k < f2.numberOfVertices; k++) { Vec3D a, b, edge; a = v[f.vertices[k]].copy().normalize(); b = v[f.vertices[(k + 1) % f.numberOfVertices]].copy().normalize(); edge = a.subtract(b).normalize(); double dotO = b.dot(edge); if (dotO < 0.0) { Vec3D tempPoint = b.addition(edge.times(dotO)); double tempDist = tempPoint.squaredLength(); if (dotDist > tempDist) { dotDist = tempDist; dotPoint = tempPoint; } } } minmax[3] = System.Math.Acos((dotPoint.z) / (dotPoint.length())); */ //Check om te bepalen of de polygon in het xy vlak (z is up), //zo ja, check of erboven of eronder is en pas theta aan om volledig door te lopen. if (minX < 0 && maxX > 0 && minY < 0 && maxY > 0) if (meanZ > 0) minmax[1] = 0; else minmax[3] = System.Math.PI; return minmax; }
private static double getExtendOneVector(ref Model3D model, ref unitVector direction) { double tempExtend = 0.0; for (int i = 0; i < model.faces.Length; i++) { Face f = model.faces[i]; double extend = RayTriangleIntersection2(ref direction, ref model, ref f); if (extend > tempExtend) tempExtend = extend; } return tempExtend; }
static double[] getExtendBruteForce(ref Model3D model, ref unitVector[] ds) { double[] extends = new double[4 * B * B]; //initialize all values to 0 for (int q = 0; q < extends.Length; q++) extends[q] = 0.0; int counter = 0; for (int k = 0; k < model.faces.Length; k++) { Face f = model.faces[k]; for (int i = 0; i < ds.Length; i++) { unitVector temp = ds[i]; double extend = RayTriangleIntersection2(ref temp, ref model, ref f); counter++; if (double.IsNaN(extend)) { // System.Console.WriteLine("Did not hit. a: {0} b: {1}", temp.a, temp.b); continue; } int temporary = (temp.a * 2 * B) + temp.b; if (extends[temporary] < extend) extends[temporary] = extend; /* Console.WriteLine("Extends {0}:\textend: {1},\tphi: {2},\ttheta: {3},\t" + "minPhi: {4},\tmaxPhi: {5},\tminTheta: {6},\tmaxTheta: {7},\t" + "minPhiIndexValue: {8},\tmaxPhiIndexValue: {9},\tminThetaIndexValue: {10},\tmaxThetaIndexValue: {11}", temporary, extend, temp.phi, temp.theta, 0, System.Math.PI*2, 0, System.Math.PI, 0, System.Math.PI * 2, 0, System.Math.PI); */ } } return extends; }
static double[] getExtend(ref Model3D model, ref unitVector[] ds) { double[] extends = new double[4*B*B]; //initialize all values to 0 for(int q = 0; q < extends.Length; q++) extends[q] = 0.0; int counter = 0; for(int k=0; k < model.faces.Length; k++) { Face f = model.faces[k]; double[] phiTheta = getMinMaxPhiTheta(ref f, ref model.vertices,ref model); double minPhi = phiTheta[0]; double minTheta = phiTheta[1]; double maxPhi = phiTheta[2]; double maxTheta = phiTheta[3]; double searchPhi; if (minPhi < 0) searchPhi = minPhi + (2 * System.Math.PI); else searchPhi = minPhi; int minPhiIndex = BinSearchPhi(ref ds, searchPhi, 0, ds.Length - 1, false); while (minPhiIndex > 0 && ds[minPhiIndex - 1].phi == ds[minPhiIndex].phi) minPhiIndex--; if (maxPhi < 0) searchPhi = maxPhi + 2 * System.Math.PI; else searchPhi = maxPhi; int maxPhiIndex = BinSearchPhi(ref ds, maxPhi, 0, ds.Length - 1, true); while (maxPhiIndex < ds.Length-1 && ds[maxPhiIndex + 1].phi == ds[maxPhiIndex].phi) maxPhiIndex++; //min en max van de theta zijn onveranderlijk over de subset in phi. Dit vanwege //de sortering over eerst phi en vervolgens theta, waardoor de opeenvolging altijd hetzelfde is. int minThetaIndex = BinSearchTheta(ref ds, minTheta, minPhiIndex, minPhiIndex + B2, false); minThetaIndex -= minPhiIndex; // maakt de index relatief ten opzicht van de phiIndex int maxThetaIndex = BinSearchTheta(ref ds, maxTheta, minPhiIndex, minPhiIndex + B2, true); maxThetaIndex -= minPhiIndex; int thetaRange = maxThetaIndex - minThetaIndex; int range = System.Math.Abs(maxPhiIndex - minPhiIndex) / B2; for (int i = 0; i <= range; i++) { for (int j = 0; j <= thetaRange; j++) { int index = (minPhiIndex + i * B2 + minThetaIndex + j) % ds.Length; //Modulo vanwege dat als maxPhi groter is dan PI het eigenlijk negatief is, daarom moet er over het einde van de array worden doorgelopen. unitVector temp = ds[index]; double extend = RayTriangleIntersection2(ref temp, ref model, ref f); counter++; if (extend == 0.0) { // System.Console.WriteLine("Did not hit. a: {0} b: {1}",temp.a, temp.b); continue; } int temporary = (temp.a * 2 * B) + temp.b; if(extends[temporary] < extend) extends[temporary] = extend; /* Console.WriteLine("Extends {0}: \textend: {1},\tphi: {2},\ttheta: {3},\t" + "minPhi: {4},\tmaxPhi: {5},\tminTheta: {6},\tmaxTheta: {7},\t" + "minPhiIndexValue: {8},\tmaxPhiIndexValue: {9},\tminThetaIndexValue: {10},\tmaxThetaIndexValue: {11}", temporary, extend, temp.phi, temp.theta, minPhi, maxPhi, minTheta, maxTheta, ds[minPhiIndex + minThetaIndex].phi, ds[minPhiIndex + (range - 1) * B2 + minThetaIndex].phi, ds[minPhiIndex + minThetaIndex].theta, ds[minPhiIndex + (range - 1) * B2 + minThetaIndex].theta); */ } } } System.Console.WriteLine(counter); return extends; }
//do all the important stuff :-) static double[] extractFeatureVector(ref Model3D model, ref unitVector[] ds) { //bruteforce // double[] extends2 = getExtendBruteForce(ref model, ref ds); //optimized double[] extends = getExtend(ref model, ref ds); //because of a error with the calculation of phi because of Atan2, the 0 values are recalculated for (int i = 0; i < extends.Length; i++) { if (extends[i] == 0.0) { int b = i % B2; int a = (i / B2); extends[i] = getExtendOneVector(ref model, ref ds[B2 * b + a]); } } double[] feature = SFFT(extends, ds); return feature; }