protected StoredValue <ValueT> GetValue(int x, int y, int z, long identifier) { if (valueDictionary.ContainsKey(identifier)) { var prevValue = valueDictionary[identifier]; if (prevValue.NumTimesCalled < 7) { prevValue.NumTimesCalled++; } else { valueDictionary.Remove(identifier); } return(prevValue); } var newValue = new StoredValue <ValueT> { Value = GetValueFromSolid(x, y, z), X = x, Y = y, Z = z, NumTimesCalled = 1, ID = identifier }; valueDictionary.Add(identifier, newValue); return(newValue); }
protected override double GetOffset(StoredValue <double> from, StoredValue <double> to, int direction, int sign) { if (from.Value.IsPracticallySame(surfaceLevel)) { return(0.0); } if (to.Value.IsPracticallySame(surfaceLevel)) { return(gridToCoordinateFactor); } if (to.Value.IsPracticallySame(from.Value)) { return(gridToCoordinateFactor / 2); } return(gridToCoordinateFactor * (surfaceLevel - from.Value) / (to.Value - from.Value)); }
protected override double GetOffset(StoredValue <double> from, StoredValue <double> to, int direction, int sign) { if (from.Value.IsNegligible()) { return(0.0); } if (to.Value.IsNegligible()) { return(gridToCoordinateFactor); } if (direction == 2 && (double.IsInfinity(from.Value) || double.IsInfinity(to.Value))) { return(0.5 * gridToCoordinateFactor); } return(-gridToCoordinateFactor * from.Value / (to.Value - from.Value)); }
protected override double GetOffset(StoredValue <bool> from, StoredValue <bool> to, int direction, int sign) { switch (direction) { case 0: var maxX = to.X - from.X; for (int i = 1; i < maxX; i++) { if (GetValueFromSolid((from.X + sign * i), from.Y, from.Z) != GetValueFromSolid((from.X + sign * (i - 1)), from.Y, from.Z)) { return(gridToCoordinateFactor * (i + 0.5) / maxX); } } break; case 1: var maxY = to.Y - from.Y; for (int i = 1; i < maxY; i++) { if (GetValueFromSolid(from.X, (from.Y + sign * i), from.Z) != GetValueFromSolid(from.X, (from.Y + sign * (i - 1)), from.Z)) { return(gridToCoordinateFactor * (i + 0.5) / maxY); } } break; case 2: var maxZ = to.X - from.X; for (int i = 1; i < maxZ; i++) { if (GetValueFromSolid(from.X, from.Y, (from.Z + sign * i)) != GetValueFromSolid(from.X, from.Y, (from.Z + sign * (i - 1)))) { return(gridToCoordinateFactor * (i + 0.5) / maxZ); } } break; } return(gridToCoordinateFactor); }
protected override double GetOffset(StoredValue <bool> from, StoredValue <bool> to, int direction, int sign) { switch (direction) { case 0: var maxX = (int)(to.X - from.X); for (int i = 1; i < maxX; i++) { if (solid[(int)(from.X + sign * i), (int)from.Y, (int)from.Z] != solid[(int)(from.X + sign * (i - 1)), (int)from.Y, (int)from.Z]) { return(gridToCoordinateFactor * (i + 0.5) / maxX); } } break; case 1: var maxY = (int)(to.Y - from.Y); for (int i = 1; i < maxY; i++) { if (solid[(int)from.X, (int)(from.Y + sign * i), (int)from.Z] != solid[(int)from.X, (int)(from.Y + sign * (i - 1)), (int)from.Z]) { return(gridToCoordinateFactor * (i + 0.5) / maxY); } } break; case 2: var maxZ = (int)(to.X - from.X); for (int i = 1; i < maxZ; i++) { if (solid[(int)from.X, (int)from.Y, (int)(from.Z + sign * i)] != solid[(int)from.X, (int)from.Y, (int)(from.Z + sign * (i - 1))]) { return(gridToCoordinateFactor * (i + 0.5) / maxZ); } } break; } return(gridToCoordinateFactor); }
protected abstract double GetOffset(StoredValue <ValueT> from, StoredValue <ValueT> to, int direction, int sign);
/// <summary> /// MakeTriangles performs the Marching Cubes algorithm on a single cube /// </summary> protected void MakeFacesInCube(int xIndex, int yIndex, int zIndex) { int cubeType = 0; var cube = new StoredValue <ValueT> [8]; //Find which vertices are inside of the surface and which are outside for (var i = 0; i < 8; i++) { var thisX = xIndex + _unitOffsetTable[i][0]; var thisY = yIndex + _unitOffsetTable[i][1]; var thisZ = zIndex + _unitOffsetTable[i][2]; var id = getIdentifier((int)thisX, (int)thisY, (int)thisZ); var v = cube[i] = GetValue((int)thisX, (int)thisY, (int)thisZ, id); if (IsInside(v.Value)) { cubeType |= 1 << i; } } //Find which edges are intersected by the surface int edgeFlags = CubeEdgeFlagsTable[cubeType]; //If the cube is entirely inside or outside of the surface, then there will be no intersections if (edgeFlags == 0) { return; } var EdgeVertex = new Vertex[12]; //this loop creates or retrieves the vertices that are on the edges of the //marching cube. These are stored in the EdgeVertexIndexTable for (var i = 0; i < 12; i++) { //if there is an intersection on this edge if ((edgeFlags & 1) != 0) { var direction = Math.Abs((int)directionTable[i]) - 1; var sign = directionTable[i] > 0 ? 1 : -1; var fromCorner = cube[EdgeCornerIndexTable[i][0]]; var toCorner = cube[EdgeCornerIndexTable[i][1]]; // var id = fromCorner.ID ; var id = sign > 0 ? fromCorner.ID : toCorner.ID; if (vertexDictionaries[direction].ContainsKey(id)) { EdgeVertex[i] = vertexDictionaries[direction][id]; } else { var coord = new Vector3( _xMin + fromCorner.X * gridToCoordinateFactor, _yMin + fromCorner.Y * gridToCoordinateFactor, _zMin + fromCorner.Z * gridToCoordinateFactor); var offSetUnitVector = (direction == 0) ? Vector3.UnitX : (direction == 1) ? Vector3.UnitY : Vector3.UnitZ; double offset = GetOffset(fromCorner, toCorner, direction, sign); coord = coord + (offSetUnitVector * sign * offset); EdgeVertex[i] = new Vertex(coord); vertexDictionaries[direction].Add(id, EdgeVertex[i]); } } edgeFlags >>= 1; } //now the triangular faces are created that connect the vertices identified above. //based on the les that were found. There can be up to five per cube var faceVertices = new Vertex[3]; for (var i = 0; i < NumFacesTable[cubeType]; i++) { for (var j = 0; j < 3; j++) { var vertexIndex = FaceVertexIndicesTable[cubeType][3 * i + j]; faceVertices[j] = EdgeVertex[vertexIndex]; } faces.Add(new PolygonalFace(faceVertices)); } }