use of maspack.matrix.Vector3i in project artisynth_core by artisynth.
the class DistanceGridTester method normalCalcTest.
/**
* This test verifies the normal calculations. For every point, we find the
* nearest point to the triangle, subtract the points, and normalize the
* resulting vector. There is usually quite a bit of error, especially with
* finer resolution meshes. The error calculation is done per axis, and
* should perhaps be represented in a better way in the future.
*/
private void normalCalcTest() {
Vector3d normal = new Vector3d();
double[] myPhi = g.getDistances();
double epsilon = 1e-8;
Point3d closestPoint = new Point3d();
Point3d meshpnt = new Point3d();
double errorCount = 0;
Vector3d errorSum = new Vector3d();
Vector3d errorAverage = new Vector3d();
Vector3d errorMax = new Vector3d();
Vector3d errorThis = new Vector3d();
for (int i = 0; i < myPhi.length; i++) {
g.getLocalVertexCoords(meshpnt, g.vertexToXyzIndices(new Vector3i(), i));
double dist = g.getLocalDistanceAndNormal(normal, meshpnt.x, meshpnt.y, meshpnt.z);
Face face = (Face) g.getClosestFeature(i);
face.nearestPoint(closestPoint, meshpnt);
// closestPoint.sub (meshpnt);
meshpnt.sub(closestPoint);
meshpnt.absolute();
meshpnt.normalize();
normal.absolute();
// normal.scale (dist);
double myErr = meshpnt.distance(normal);
if (myErr > epsilon) {
// g.setGridPointColor (i, Color.WHITE);
errorThis.x = Math.abs(normal.x - meshpnt.x) / meshpnt.x * 100.0;
errorThis.y = Math.abs(normal.y - meshpnt.y) / meshpnt.y * 100.0;
errorThis.z = Math.abs(normal.z - meshpnt.z) / meshpnt.z * 100.0;
if (errorThis.x > errorMax.x) {
errorMax.x = errorThis.x;
}
if (errorThis.y > errorMax.y) {
errorMax.y = errorThis.y;
}
if (errorThis.z > errorMax.z) {
errorMax.z = errorThis.z;
}
errorSum.add(errorThis);
errorCount++;
}
}
if (errorCount != 0) {
errorAverage.x = errorSum.x / errorCount;
errorAverage.y = errorSum.y / errorCount;
errorAverage.z = errorSum.z / errorCount;
}
System.out.println("Average error of normals: " + errorAverage);
System.out.println("Max error of normals: " + errorMax);
}
use of maspack.matrix.Vector3i in project artisynth_core by artisynth.
the class DistanceGridTester method checkPhiIsSet.
/**
* This test checks that every value in phi is less than half the width of
* the parallelpiped that is formed by the grid.
*/
private void checkPhiIsSet() {
double[] myPhi = g.getDistances();
Vector3i resolution = g.getResolution();
Vector3d cellSize = g.getCellWidths();
double maxDist = Math.sqrt(resolution.x * cellSize.x * resolution.x * cellSize.x + resolution.y * cellSize.y * resolution.y * cellSize.y + resolution.z * cellSize.z * resolution.z * cellSize.z);
for (int i = 0; i < myPhi.length; i++) {
if (myPhi[i] >= maxDist || myPhi[i] <= -maxDist) {
throw new TestException("phi at index " + i + " has not been set.");
}
}
System.out.println("Phi has been initialized. Test Passed.");
}
use of maspack.matrix.Vector3i in project artisynth_core by artisynth.
the class DistanceGridTester method colourTest.
/**
* This test changes the colour of each vertex based on
* distance from the mesh surface. This is a visual test of the integrity
* of the signed distance field.
*/
private void colourTest() {
double[] myPhi = g.getDistances();
Vector3i resolution = g.getResolution();
Vector3d cellSize = g.getCellWidths();
for (int i = 0; i < myPhi.length; i++) {
// Extract out the grid coordinates.
Vector3i gidxs = new Vector3i();
g.vertexToXyzIndices(gidxs, i);
double maxDist = Math.sqrt(resolution.x * cellSize.x * resolution.x * cellSize.x + resolution.y * cellSize.y * resolution.y * cellSize.y + resolution.z * cellSize.z * resolution.z * cellSize.z) / 3.0f;
float h = (float) (Math.abs(g.getVertexDistance(gidxs)) / maxDist);
float[] RGB = new float[3];
float[] HSV = new float[3];
HSV[0] = h;
HSV[1] = 1.0f;
HSV[2] = 1.0f;
ColorUtils.HSVtoRGB(HSV, RGB);
g.setVertexColor(i, new Color(RGB[0], RGB[1], RGB[2]));
}
System.out.println("Colour Test complete.");
}
use of maspack.matrix.Vector3i in project artisynth_core by artisynth.
the class DistanceGrid method getLocalDistanceAndNormal.
/**
* Calculates the distance and normal at an arbitrary point in local
* coordinates using multilinear interpolation, as described for {@link
* #getLocalDistanceAndNormal(Vector3d,Point3d)}. If <code>Dnrm</code> is
* non-<code>null</code>, the method also calculated the normal derivative.
* If the point lies outside the grid volume, {@link #OUTSIDE_GRID} is
* returned.
*
* @param norm returns the normal (local coordinates)
* @param Dnrm if non-null, returns the normal derivative (local coordinates)
* @param point point at which to calculate the normal and distance
* (local coordinates).
* @return interpolated distance, or <code>OUTSIDE_GRID</code>.
*/
public double getLocalDistanceAndNormal(Vector3d norm, Matrix3d Dnrm, Point3d point) {
Vector3d coords = new Vector3d();
Vector3i vidx = new Vector3i();
if (!getCellCoords(vidx, coords, point)) {
return OUTSIDE_GRID;
}
double dx = coords.x;
double dy = coords.y;
double dz = coords.z;
// Compute weights w000, w001, w010, etc. for trilinear interpolation.
// w001z, w011z, etc. are the derivatives of the weights
// with respect to dz. Can use to compute weights, and also
// to compute Dnrm if needed
double w001z = (1 - dx) * (1 - dy);
double w011z = (1 - dx) * dy;
double w101z = dx * (1 - dy);
double w111z = dx * dy;
double w000 = w001z * (1 - dz);
double w001 = w001z * dz;
double w010 = w011z * (1 - dz);
double w011 = w011z * dz;
double w100 = w101z * (1 - dz);
double w101 = w101z * dz;
double w110 = w111z * (1 - dz);
double w111 = w111z * dz;
double d000 = getVertexDistance(vidx.x, vidx.y, vidx.z);
double d001 = getVertexDistance(vidx.x, vidx.y, vidx.z + 1);
double d010 = getVertexDistance(vidx.x, vidx.y + 1, vidx.z);
double d011 = getVertexDistance(vidx.x, vidx.y + 1, vidx.z + 1);
double d100 = getVertexDistance(vidx.x + 1, vidx.y, vidx.z);
double d101 = getVertexDistance(vidx.x + 1, vidx.y, vidx.z + 1);
double d110 = getVertexDistance(vidx.x + 1, vidx.y + 1, vidx.z);
double d111 = getVertexDistance(vidx.x + 1, vidx.y + 1, vidx.z + 1);
double d = w000 * d000 + w001 * d001 + w010 * d010 + w011 * d011 + w100 * d100 + w101 * d101 + w110 * d110 + w111 * d111;
if (norm != null || Dnrm != null) {
Vector3d n000 = getLocalVertexNormal(vidx.x, vidx.y, vidx.z);
Vector3d n001 = getLocalVertexNormal(vidx.x, vidx.y, vidx.z + 1);
Vector3d n010 = getLocalVertexNormal(vidx.x, vidx.y + 1, vidx.z);
Vector3d n011 = getLocalVertexNormal(vidx.x, vidx.y + 1, vidx.z + 1);
Vector3d n100 = getLocalVertexNormal(vidx.x + 1, vidx.y, vidx.z);
Vector3d n101 = getLocalVertexNormal(vidx.x + 1, vidx.y, vidx.z + 1);
Vector3d n110 = getLocalVertexNormal(vidx.x + 1, vidx.y + 1, vidx.z);
Vector3d n111 = getLocalVertexNormal(vidx.x + 1, vidx.y + 1, vidx.z + 1);
if (norm == null && Dnrm != null) {
norm = new Vector3d();
}
if (norm != null) {
norm.setZero();
norm.scaledAdd(w000, n000);
norm.scaledAdd(w001, n001);
norm.scaledAdd(w010, n010);
norm.scaledAdd(w011, n011);
norm.scaledAdd(w100, n100);
norm.scaledAdd(w101, n101);
norm.scaledAdd(w110, n110);
norm.scaledAdd(w111, n111);
// norm.normalize();
}
if (Dnrm != null) {
// compute weight derivatives with respect to dx and dy
double w100x = (1 - dy) * (1 - dz);
double w101x = (1 - dy) * dz;
double w110x = dy * (1 - dz);
double w111x = dy * dz;
double w010y = (1 - dx) * (1 - dz);
double w011y = (1 - dx) * dz;
double w110y = dx * (1 - dz);
double w111y = dx * dz;
if (true) {
Vector3d row = new Vector3d();
// top row of Dnrm
row.x = (-w100x * n000.x - w101x * n001.x - w110x * n010.x - w111x * n011.x + w100x * n100.x + w101x * n101.x + w110x * n110.x + w111x * n111.x);
row.y = (-w010y * n000.x - w011y * n001.x + w010y * n010.x + w011y * n011.x - w110y * n100.x - w111y * n101.x + w110y * n110.x + w111y * n111.x);
row.z = (-w001z * n000.x + w001z * n001.x - w011z * n010.x + w011z * n011.x - w101z * n100.x + w101z * n101.x - w111z * n110.x + w111z * n111.x);
myGridToLocal.transformCovec(row, row);
row.scale(d);
Dnrm.m00 = row.x;
Dnrm.m01 = row.y;
Dnrm.m02 = row.z;
// middle row of Dnrm
row.x = (-w100x * n000.y - w101x * n001.y - w110x * n010.y - w111x * n011.y + w100x * n100.y + w101x * n101.y + w110x * n110.y + w111x * n111.y);
row.y = (-w010y * n000.y - w011y * n001.y + w010y * n010.y + w011y * n011.y - w110y * n100.y - w111y * n101.y + w110y * n110.y + w111y * n111.y);
row.z = (-w001z * n000.y + w001z * n001.y - w011z * n010.y + w011z * n011.y - w101z * n100.y + w101z * n101.y - w111z * n110.y + w111z * n111.y);
myGridToLocal.transformCovec(row, row);
row.scale(d);
Dnrm.m10 = row.x;
Dnrm.m11 = row.y;
Dnrm.m12 = row.z;
// bottom row of Dnrm
row.x = (-w100x * n000.z - w101x * n001.z - w110x * n010.z - w111x * n011.z + w100x * n100.z + w101x * n101.z + w110x * n110.z + w111x * n111.z);
row.y = (-w010y * n000.z - w011y * n001.z + w010y * n010.z + w011y * n011.z - w110y * n100.z - w111y * n101.z + w110y * n110.z + w111y * n111.z);
row.z = (-w001z * n000.z + w001z * n001.z - w011z * n010.z + w011z * n011.z - w101z * n100.z + w101z * n101.z - w111z * n110.z + w111z * n111.z);
myGridToLocal.transformCovec(row, row);
row.scale(d);
Dnrm.m20 = row.x;
Dnrm.m21 = row.y;
Dnrm.m22 = row.z;
} else {
Dnrm.setZero();
}
Vector3d grad = new Vector3d();
grad.x = (-w100x * d000 - w101x * d001 - w110x * d010 - w111x * d011 + w100x * d100 + w101x * d101 + w110x * d110 + w111x * d111);
grad.y = (-w010y * d000 - w011y * d001 + w010y * d010 + w011y * d011 - w110y * d100 - w111y * d101 + w110y * d110 + w111y * d111);
grad.z = (-w001z * d000 + w001z * d001 - w011z * d010 + w011z * d011 - w101z * d100 + w101z * d101 - w111z * d110 + w111z * d111);
myGridToLocal.transformCovec(grad, grad);
Dnrm.addOuterProduct(norm, grad);
}
}
return d;
}
use of maspack.matrix.Vector3i in project artisynth_core by artisynth.
the class DistanceGrid method createDistanceSurface.
/**
* Creates a triangular mesh approximating the surface on which the linearly
* interpolated distance function equals <code>val</code>.
*
* @param val iso surface value
* @return iso surface for linear interpolation
*/
public PolygonalMesh createDistanceSurface(double val, int res) {
MarchingTetrahedra marcher = new MarchingTetrahedra();
Vector3i cellRes = new Vector3i(getResolution());
cellRes.scale(res);
int nvx = cellRes.x + 1;
int nvy = cellRes.y + 1;
int nvz = cellRes.z + 1;
double[] dists = new double[nvx * nvy * nvz];
double invRes = 1.0 / res;
Point3d q = new Point3d();
for (int i = 0; i < myNx - 1; i++) {
for (int j = 0; j < myNy - 1; j++) {
for (int k = 0; k < myNz - 1; k++) {
double d000 = getVertexDistance(i, j, k);
double d001 = getVertexDistance(i, j, k + 1);
double d010 = getVertexDistance(i, j + 1, k);
double d011 = getVertexDistance(i, j + 1, k + 1);
double d100 = getVertexDistance(i + 1, j, k);
double d101 = getVertexDistance(i + 1, j, k + 1);
double d110 = getVertexDistance(i + 1, j + 1, k);
double d111 = getVertexDistance(i + 1, j + 1, k + 1);
int maxci = (i < myNx - 2 ? res - 1 : res);
int maxcj = (j < myNy - 2 ? res - 1 : res);
int maxck = (k < myNz - 2 ? res - 1 : res);
double cx, cy, cz;
for (int ci = 0; ci <= maxci; ci++) {
cx = ci * invRes;
for (int cj = 0; cj <= maxcj; cj++) {
cy = cj * invRes;
for (int ck = 0; ck <= maxck; ck++) {
cz = ck * invRes;
double w001z = (1 - cx) * (1 - cy);
double w011z = (1 - cx) * cy;
double w101z = cx * (1 - cy);
double w111z = cx * cy;
double w000 = w001z * (1 - cz);
double w001 = w001z * cz;
double w010 = w011z * (1 - cz);
double w011 = w011z * cz;
double w100 = w101z * (1 - cz);
double w101 = w101z * cz;
double w110 = w111z * (1 - cz);
double w111 = w111z * cz;
dists[(i * res + ci) + (j * res + cj) * nvx + (k * res + ck) * nvx * nvy] = w000 * d000 + w001 * d001 + w010 * d010 + w011 * d011 + w100 * d100 + w101 * d101 + w110 * d110 + w111 * d111;
}
}
}
}
}
}
PolygonalMesh mesh = marcher.createMesh(dists, Vector3d.ZERO, new Vector3d(invRes, invRes, invRes), cellRes, val);
mesh.transform(myGridToLocal);
return mesh;
}
Aggregations