public Sphere ComputeBoundingSphereNaive() { var pointPositions = PointAttributes.FindOrCreate <Vector3>("point_locations"); // FIRST PASS: Find 6 minima/maxima points BoundingBox box = new BoundingBox(); box.Clear(); foreach (Point point in Points) { box.ExtendBy(pointPositions[point]); } float maxRadiusSquare = 0.0f; foreach (Point point in Points) { Vector3 p = pointPositions[point]; float radiusSquare = box.Center.DistanceSquared(pointPositions[point]); if (radiusSquare > maxRadiusSquare) { maxRadiusSquare = radiusSquare; } } return(new Sphere(box.Center, (float)System.Math.Sqrt(maxRadiusSquare))); }
public void Noise(NoiseGenerator noise) { ComputePolygonNormals(); ComputePointNormals("point_normals_smooth"); var pointLocations = PointAttributes.FindOrNull <Vector3>("point_locations"); var pointNormals = PointAttributes.FindOrNull <Vector3>("point_normals_smooth"); foreach (Point point in Points) { if ( (pointLocations != null) && pointLocations.ContainsKey(point) ) { var pos = pointLocations[point]; var normal = Vector3.Normalize(pointLocations[point]); pointLocations[point] = pos + noise.Generate(pos) * normal; } } ComputePolygonCentroids(); ComputePolygonNormals(); SmoothNormalize("corner_normals", "polygon_normals", (2.0f * (float)System.Math.PI)); BuildEdges(); }
public Polygon MakePolygon(List <int> pointIndices) { Polygon polygon = MakePolygon(); /* Sanity check */ for (int i = 0; i < pointIndices.Count; ++i) { for (int j = 0; j < pointIndices.Count; ++j) { if (i == j) { continue; } if (pointIndices[i] == pointIndices[j]) { throw new System.Exception("duplicate polygon corner point indices"); } } } foreach (int pointIndex in pointIndices) { Point point = Points[pointIndex]; polygon.MakeCorner(point); } #if DEBUG_CHECK var pointLocations = PointAttributes.Find <Vector3>("point_locations"); if (polygon.DebugCheck(pointLocations) == false) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = pointIndices.Length - 1; i >= 0; --i) { sb.Append(pointIndices[i].ToString()); if (i > 0) { sb.Append(", "); } } Logger.Log(sb.ToString() + ");"); } else { System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = 0; i < pointIndices.Length; i++) { sb.Append(pointIndices[i].ToString()); if (i < pointIndices.Length - 1) { sb.Append(", "); } } Logger.Log(sb.ToString() + ");"); } #endif return(polygon); }
/// Compute polygon centroids based on point position attributes /// Results are stored in internally stored attribute map named "polygon_centroids". public void ComputePolygonCentroids() { var polygonCentroids = PolygonAttributes.FindOrCreate <Vector3>("polygon_centroids"); var pointLocations = PointAttributes.Find <Vector3>("point_locations"); polygonCentroids.Clear(); foreach (Polygon polygon in Polygons) { polygon.ComputeCentroid(polygonCentroids, pointLocations); } }
/// Compute polygon normals based on point position attributes. /// Results are stored in internally stored attribute map named "polygon_normals". public void ComputePolygonNormals() { var polygonNormals = PolygonAttributes.FindOrCreate <Vector3>("polygon_normals"); var pointLocations = PointAttributes.Find <Vector3>("point_locations"); polygonNormals.Clear(); foreach (Polygon polygon in Polygons) { polygon.ComputeNormal(polygonNormals, pointLocations); } }
public Point MakePoint(Vector3 p) { Point point = MakePoint(); var pointPositions = PointAttributes.FindOrCreate <Vector3>("point_locations"); #if ENABLE_CREATE_TRANSFORM pointPositions[point] = MakePointTransform * new Vector3(p.x, p.y, p.z); #else pointPositions[point] = new Vector3(p.X, p.Y, p.Z); #endif return(point); }
/// \brief Constructs a new Point and assosiates a position attribute for it. public Point MakePoint(float x, float y, float z) { Point point = MakePoint(); var pointPositions = PointAttributes.FindOrCreate <Vector3>("point_locations"); #if ENABLE_CREATE_TRANSFORM pointPositions[point] = MakePointTransform * new Vector3(x, y, z); #else pointPositions[point] = new Vector3(x, y, z); #endif return(point); }
/// \brief Constructs a new Point and assosiates a position attribute for it. public Point MakePoint(double x, double y, double z) { Point point = MakePoint(); var pointPositions = PointAttributes.FindOrCreate <Vector3>("point_locations"); #if ENABLE_CREATE_TRANSFORM pointPositions[point] = MakePointTransform * Vector3((float)x, (float)y, (float)z); #else pointPositions[point] = new Vector3((float)x, (float)y, (float)z); #endif return(point); }
/// \warning This is inefficient! Try not to use this public void MergePoints() { Dictionary <Point, Point> removedPointToRemainingPoint = new Dictionary <Point, Point>(); var pointLocations = PointAttributes.FindOrNull <Vector3>("point_locations"); float pointEpsilon = 0.0000001f; // Merge points foreach (Point p1 in Points) { Vector3 pos1 = pointLocations[p1]; bool alreadyUsed = false; foreach (Point p2 in Points) { if (p1 == p2) { continue; } if (removedPointToRemainingPoint.ContainsKey(p1)) { continue; } Vector3 pos2 = pointLocations[p2]; float distanceSquared = pos1.DistanceSquared(pos2); if (distanceSquared < pointEpsilon) { if (alreadyUsed) { System.Diagnostics.Debug.WriteLine("point already used"); } removedPointToRemainingPoint[p2] = p1; alreadyUsed = true; } } } // Merge polygons foreach (var polygon in Polygons) { polygon.ReplacePoints(removedPointToRemainingPoint); } foreach (var point in removedPointToRemainingPoint.Keys) { Points.Remove(point); } }
public void ComputePointNormals(string mapName) { var pointNormals = PointAttributes.FindOrCreate <Vector3>(mapName); var polygonNormals = PolygonAttributes.Find <Vector3>("polygon_normals"); pointNormals.Clear(); foreach (Point point in Points) { Vector3 normalSum = new Vector3(0.0f, 0.0f, 0.0f); foreach (Corner corner in point.Corners) { normalSum += polygonNormals[corner.Polygon]; } Vector3 averageNormal = normalSum / (float)point.Corners.Count; pointNormals[point] = averageNormal; } }
public void Transform(Matrix4 transform) { Matrix4 inverseTransposeTransform = Matrix4.Transpose(Matrix4.Invert(transform)); // Check.. Did I forget something? // \todo Mark each attributemap how they should be transformed var polygonCentroids = PolygonAttributes.FindOrNull <Vector3>("polygon_centroids"); var polygonNormals = PolygonAttributes.FindOrNull <Vector3>("polygon_normals"); var pointLocations = PointAttributes.FindOrNull <Vector3>("point_locations"); var pointNormals = PointAttributes.FindOrNull <Vector3>("point_normals"); var cornerNormals = CornerAttributes.FindOrNull <Vector3>("corner_normals"); // Make copies of old points foreach (Point point in Points) { if (pointLocations != null && pointLocations.ContainsKey(point)) { pointLocations[point] = transform.TransformPoint(pointLocations[point]); } if (pointNormals != null && pointNormals.ContainsKey(point)) { pointNormals[point] = inverseTransposeTransform.TransformDirection(pointNormals[point]); } } foreach (Polygon polygon in Polygons) { if (polygonCentroids != null && polygonCentroids.ContainsKey(polygon)) { polygonCentroids[polygon] = transform.TransformPoint(polygonCentroids[polygon]); } if (polygonNormals != null && polygonNormals.ContainsKey(polygon)) { polygonNormals[polygon] = inverseTransposeTransform.TransformDirection(polygonNormals[polygon]); } if (cornerNormals != null) { foreach (Corner corner in polygon.Corners) { if (cornerNormals.ContainsKey(corner)) { cornerNormals[corner] = inverseTransposeTransform.TransformDirection(cornerNormals[corner]); } } } } }
public HeightField(float[,] heights, float scaleX, float scaleZ) { var pointLocations = PointAttributes.FindOrCreate <Vector3>("point_locations"); var pointTexcoords = PointAttributes.FindOrCreate <Vector2>("point_texcoords"); // Generate vertices int xCount = heights.GetLength(0); int zCount = heights.GetLength(1); for (int x = 0; x < xCount; x++) { float s = (float)x / (float)xCount; float xP = (float)x * scaleX; for (int z = 0; z < zCount; z++) { float t = (float)z / (float)zCount; float zP = (float)z * scaleZ; float yP = heights[x, z]; var point = MakePoint(); pointLocations[point] = new Vector3(xP, yP, zP); pointTexcoords[point] = new Vector2(s, t); Points[x * zCount + z] = point; } } // Generate quads for (int x = 0; x < xCount - 1; x++) { for (int z = 0; z < zCount - 1; z++) { var pol = MakePolygon(); pol.MakeCorner(Points[(x + 1) * zCount + z]); pol.MakeCorner(Points[(x + 1) * zCount + z + 1]); pol.MakeCorner(Points[(x) * zCount + z + 1]); pol.MakeCorner(Points[(x) * zCount + z]); } } ComputePolygonCentroids(); ComputePolygonNormals(); SmoothNormalize("corner_normals", "polygon_normals", (2.0f * (float)System.Math.PI)); }
public Corner ClosestPolygonCorner(Polygon polygon, Vector3 position) { Corner closestCorner = null; float closestDistanceSquared = float.MaxValue; var pointLocations = PointAttributes.Find <Vector3>("point_locations"); foreach (Corner corner in polygon.Corners) { Vector3 cornerLocation = pointLocations[corner.Point]; float distanceSquared = cornerLocation.DistanceSquared(position); if (distanceSquared < closestDistanceSquared) { closestDistanceSquared = distanceSquared; closestCorner = corner; } } return(closestCorner); }
private bool AllInSphere(Vector3 center, ref float radius) { var pointPositions = PointAttributes.FindOrCreate <Vector3>("point_locations"); float r2 = radius * radius; float maxDistanceSquared = 0.0f; foreach (Point point in Points) { float distanceSquared = center.DistanceSquared(pointPositions[point]); if (distanceSquared > r2) { return(false); } if (distanceSquared > maxDistanceSquared) { maxDistanceSquared = distanceSquared; } } radius = (float)System.Math.Sqrt(maxDistanceSquared); return(true); }
/// \brief Construct a new Polygon from a given set of Point indices /// \param pointIndices Indices to Points that are connected to the new Polygon</param> /// \return Newly created Polygon public Polygon MakePolygon(params int[] pointIndices) { Polygon polygon = MakePolygon(); foreach (int pointIndex in pointIndices) { Point point = Points[pointIndex]; polygon.MakeCorner(point); } #if DEBUG_CHECK var pointLocations = PointAttributes.Find <Vector3>("point_locations"); if (polygon.DebugCheck(pointLocations) == false) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = pointIndices.Length - 1; i >= 0; --i) { sb.Append(pointIndices[i].ToString()); if (i > 0) { sb.Append(", "); } } Logger.Log(sb.ToString() + ");"); } else { System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = 0; i < pointIndices.Length; i++) { sb.Append(pointIndices[i].ToString()); if (i < pointIndices.Length - 1) { sb.Append(", "); } } Logger.Log(sb.ToString() + ");"); } #endif return(polygon); }
public void SmoothAverage( string cornerAttribute, string pointNormalName ) { var cornerAttributes = CornerAttributes.FindOrCreate <Vector4>(cornerAttribute); var cornerNormals = CornerAttributes.FindOrCreate <Vector3>("corner_normals"); var pointNormals = PointAttributes.Find <Vector3>(pointNormalName); var newCornerAttributes = CornerAttributes.FindOrCreate <Vector4>("temp"); foreach (Polygon polygon in Polygons) { polygon.SmoothAverage( newCornerAttributes, cornerAttributes, cornerNormals, pointNormals ); } CornerAttributes.Replace(cornerAttribute, "temp"); }
public Cube(Vector3 size, IVector3 div, float p) { int x; int y; int z; MakeInfo info = new MakeInfo(0.5f * size, div, p); info.pointLocations = PointAttributes.FindOrCreate <Vector3>("point_locations"); info.pointNormals = PointAttributes.FindOrCreate <Vector3>("point_normals"); info.pointTexcoords = PointAttributes.FindOrCreate <Vector2>("point_texcoords"); info.cornerNormals = CornerAttributes.FindOrCreate <Vector3>("corner_normals"); info.cornerTexcoords = CornerAttributes.FindOrCreate <Vector2>("corner_texcoords"); info.polygonCentroids = PolygonAttributes.FindOrCreate <Vector3>("polygon_centroids"); info.polygonNormals = PolygonAttributes.FindOrCreate <Vector3>("polygon_normals"); // Generate vertices // Top and bottom for (x = -info.Div.X; x <= info.Div.X; x++) { float relX = 0.5f + (float)x / info.Size.X; for (z = -info.Div.Z; z <= info.Div.Z; z++) { float relZ = 0.5f + (float)z / info.Size.Z; MakePoint(info, x, info.Div.Y, z, Vector3.UnitY, relX, relZ); MakePoint(info, x, -info.Div.Y, z, -Vector3.UnitY, relX, relZ); } for (y = -info.Div.Y; y <= info.Div.Y; y++) { float relY = 0.5f + (float)y / info.Size.Y; MakePoint(info, x, y, info.Div.Z, Vector3.UnitZ, relX, relY); MakePoint(info, x, y, -info.Div.Z, -Vector3.UnitZ, relX, relY); } } // Left and right for (z = -info.Div.Z; z <= info.Div.Z; z++) { float relZ = 0.5f + (float)z / info.Size.Z; for (y = -info.Div.Y; y <= info.Div.Y; y++) { float relY = 0.5f + (float)y / info.Size.Y; MakePoint(info, info.Div.X, y, z, Vector3.UnitX, relY, relZ); MakePoint(info, -info.Div.X, y, z, -Vector3.UnitX, relY, relZ); } } // Generate quads // Top and bottom for (x = -info.Div.X; x < info.Div.X; x++) { float relX1 = 0.5f + (float)x / info.Size.X; float relX2 = 0.5f + (float)(x + 1) / info.Size.X; for (z = -info.Div.Z; z < info.Div.Z; z++) { float relZ1 = 0.5f + (float)z / info.Size.Z; float relZ2 = 0.5f + (float)(z + 1) / info.Size.Z; var top = MakePolygon(); MakeCorner(info, top, x + 1, info.Div.Y, z, Vector3.UnitY, relX2, relZ1); MakeCorner(info, top, x + 1, info.Div.Y, z + 1, Vector3.UnitY, relX2, relZ2); MakeCorner(info, top, x, info.Div.Y, z + 1, Vector3.UnitY, relX1, relZ2); MakeCorner(info, top, x, info.Div.Y, z, Vector3.UnitY, relX1, relZ1); var bottom = MakePolygon(); MakeCorner(info, bottom, x, -info.Div.Y, z, -Vector3.UnitY, relX1, relZ1); MakeCorner(info, bottom, x, -info.Div.Y, z + 1, -Vector3.UnitY, relX1, relZ2); MakeCorner(info, bottom, x + 1, -info.Div.Y, z + 1, -Vector3.UnitY, relX2, relZ2); MakeCorner(info, bottom, x + 1, -info.Div.Y, z, -Vector3.UnitY, relX2, relZ1); info.polygonNormals[top] = Vector3.UnitY; info.polygonNormals[bottom] = -Vector3.UnitY; } for (y = -info.Div.Y; y < info.Div.Y; y++) { float relY1 = 0.5f + (float)y / info.Size.Y; float relY2 = 0.5f + (float)(y + 1) / info.Size.Y; var back = MakePolygon(); MakeCorner(info, back, x, y, info.Div.Z, Vector3.UnitZ, relX1, relY1); MakeCorner(info, back, x, y + 1, info.Div.Z, Vector3.UnitZ, relX1, relY2); MakeCorner(info, back, x + 1, y + 1, info.Div.Z, Vector3.UnitZ, relX2, relY2); MakeCorner(info, back, x + 1, y, info.Div.Z, Vector3.UnitZ, relX2, relY1); var front = MakePolygon(); MakeCorner(info, front, x + 1, y, -info.Div.Z, -Vector3.UnitZ, relX2, relY1); MakeCorner(info, front, x + 1, y + 1, -info.Div.Z, -Vector3.UnitZ, relX2, relY2); MakeCorner(info, front, x, y + 1, -info.Div.Z, -Vector3.UnitZ, relX1, relY2); MakeCorner(info, front, x, y, -info.Div.Z, -Vector3.UnitZ, relX1, relY1); info.polygonNormals[back] = Vector3.UnitZ; info.polygonNormals[front] = -Vector3.UnitZ; } } // Left and right for (z = -info.Div.Z; z < info.Div.Z; z++) { float relZ1 = 0.5f + (float)z / info.Size.Z; float relZ2 = 0.5f + (float)(z + 1) / info.Size.Z; for (y = -info.Div.Y; y < info.Div.Y; y++) { float relY1 = 0.5f + (float)y / info.Size.Y; float relY2 = 0.5f + (float)(y + 1) / info.Size.Y; var right = MakePolygon(); MakeCorner(info, right, info.Div.X, y, z, Vector3.UnitX, relY1, relZ1); MakeCorner(info, right, info.Div.X, y, z + 1, Vector3.UnitX, relY1, relZ2); MakeCorner(info, right, info.Div.X, y + 1, z + 1, Vector3.UnitX, relY2, relZ2); MakeCorner(info, right, info.Div.X, y + 1, z, Vector3.UnitX, relY2, relZ1); var left = MakePolygon(); MakeCorner(info, left, -info.Div.X, y + 1, z, -Vector3.UnitX, relY2, relZ1); MakeCorner(info, left, -info.Div.X, y + 1, z + 1, -Vector3.UnitX, relY2, relZ2); MakeCorner(info, left, -info.Div.X, y, z + 1, -Vector3.UnitX, relY1, relZ2); MakeCorner(info, left, -info.Div.X, y, z, -Vector3.UnitX, relY1, relZ1); info.polygonNormals[right] = Vector3.UnitX; info.polygonNormals[left] = -Vector3.UnitX; } } ComputePolygonCentroids(); }
public SuperEllipsoid(Vector3 radius, double n1, double n2, int sliceCount, int stackDivision) { MakeInfo info = new MakeInfo(radius, n1, n2, sliceCount, stackDivision); info.pointLocations = PointAttributes.FindOrCreate <Vector3>("point_locations"); info.pointNormals = PointAttributes.FindOrCreate <Vector3>("point_normals"); info.pointTexcoords = PointAttributes.FindOrCreate <Vector2>("point_texcoords"); info.polygonCentroids = PolygonAttributes.FindOrCreate <Vector3>("polygon_centroids"); info.polygonNormals = PolygonAttributes.FindOrCreate <Vector3>("polygon_normals"); info.cornerTexcoords = CornerAttributes.FindOrCreate <Vector2>("corner_texcoords"); int slice; int stack; for (slice = 0; slice < sliceCount; ++slice) { double relSlice = (double)(slice) / (double)(sliceCount); for (stack = -stackDivision; stack <= stackDivision; ++stack) { double relStack = (double)(stack) / (double)(stackDivision + 1); Point point = MakePoint(info, relSlice, relStack); info.points.Add(point); } } info.bottom = MakePoint(info, 0.5f, -1.0f); info.top = MakePoint(info, 0.5f, 1.0f); #region bottom fan { for (slice = 0; slice < sliceCount; ++slice) { int nextSlice = (slice + 1); int stackBase0 = 0; double relSlice = ((double)(slice) + 0.5) / (double)(sliceCount); double relStack = -1.0 + (0.5 / (double)(stackDivision + 1)); Point centroid = MakePoint(info, relSlice, relStack); var polygon = MakePolygon(); #if CCW MakeCorner(info, polygon, slice, stackBase0); MakeCorner(info, polygon, slice, info.stackBase0Bottom); MakeCorner(info, polygon, nextSlice, stackBase0); #else MakeCorner(info, polygon, nextSlice, stackBase0); MakeCorner(info, polygon, slice, info.stackBase0Bottom); MakeCorner(info, polygon, slice, stackBase0); #endif info.polygonCentroids[polygon] = info.pointLocations[centroid]; info.polygonNormals [polygon] = info.pointNormals [centroid]; } } #endregion #region middle quads, bottom up for ( stack = -stackDivision; stack < stackDivision; ++stack ) { int stackBase0 = stack + stackDivision; int nextStackBase0 = stackBase0 + 1; double relStack = ((double)(stack) + 0.5) / (double)(stackDivision + 1); for (slice = 0; slice < sliceCount; ++slice) { int nextSlice = (slice + 1); double relSlice = ((double)(slice) + 0.5) / (double)(sliceCount); Point centroid = MakePoint(info, relSlice, relStack); var polygon = MakePolygon(); #if CCW MakeCorner(info, polygon, nextSlice, nextStackBase0); MakeCorner(info, polygon, slice, nextStackBase0); MakeCorner(info, polygon, slice, stackBase0); MakeCorner(info, polygon, nextSlice, stackBase0); #else MakeCorner(info, polygon, nextSlice, stackBase0); MakeCorner(info, polygon, slice, stackBase0); MakeCorner(info, polygon, slice, nextStackBase0); MakeCorner(info, polygon, nextSlice, nextStackBase0); #endif info.polygonCentroids[polygon] = info.pointLocations[centroid]; info.polygonNormals [polygon] = info.pointNormals [centroid]; } } #endregion #region top fan for (slice = 0; slice < sliceCount; ++slice) { int nextSlice = (slice + 1); int stackBase0 = stackDivision + stackDivision; double relSlice = ((double)(slice) + 0.5) / (double)(sliceCount); double relStack = 1.0 - (0.5 / (double)(stackDivision + 1)); Point centroid = MakePoint(info, relSlice, relStack); var polygon = MakePolygon(); #if CCW MakeCorner(info, polygon, slice, info.stackBase0Top); MakeCorner(info, polygon, slice, stackBase0); MakeCorner(info, polygon, nextSlice, stackBase0); #else MakeCorner(info, polygon, nextSlice, stackBase0); MakeCorner(info, polygon, slice, stackBase0); MakeCorner(info, polygon, slice, info.stackBase0Top); #endif info.polygonCentroids[polygon] = info.pointLocations[centroid]; info.polygonNormals [polygon] = info.pointNormals [centroid]; } #endregion }
public Disc( double outerRadius, double innerRadius, int sliceCount, int stackCount ) { MakeInfo info = new MakeInfo(outerRadius, innerRadius, sliceCount, stackCount); info.pointLocations = PointAttributes.FindOrCreate <Vector3>("point_locations"); info.pointNormals = PointAttributes.FindOrCreate <Vector3>("point_normals"); info.pointTexcoords = PointAttributes.FindOrCreate <Vector2>("point_texcoords"); info.polygonCentroids = PolygonAttributes.FindOrCreate <Vector3>("polygon_centroids"); info.polygonNormals = PolygonAttributes.FindOrCreate <Vector3>("polygon_normals"); info.cornerNormals = CornerAttributes.FindOrCreate <Vector3>("corner_normals"); info.cornerTexcoords = CornerAttributes.FindOrCreate <Vector2>("corner_texcoords"); /* Make points */ for (int stack = 0; stack < stackCount; ++stack) { double relStack = (stackCount == 1) ? 1.0 : (double)stack / (double)(stackCount - 1); for (int slice = 0; slice <= sliceCount; ++slice) { double relSlice = (double)slice / (double)sliceCount; info.points[new KeyValuePair <int, int>(slice, stack)] = MakePoint(info, relSlice, relStack); } } /* Special case without center point */ if (stackCount == 1) { Polygon polygon = MakePolygon(); info.polygonCentroids[polygon] = Vector3.Zero; info.polygonNormals [polygon] = Vector3.UnitZ; for (int slice = sliceCount - 1; slice >= 0; --slice) { MakeCorner(info, polygon, slice, 0); } return; } /* Make center point if needed */ if (innerRadius == 0.0f) { info.center = MakePoint(0.0, 0.0, 0.0); } /* Quads/triangles */ for (int stack = 0; stack < stackCount - 1; ++stack) { double relStackCentroid = (stackCount == 1) ? 0.5 : (double)stack / (double)(stackCount - 1); for (int slice = 0; slice < sliceCount; ++slice) { double relSliceCentroid = ((double)(slice) + 0.5) / (double)(sliceCount); Point centroid = MakePoint(info, relSliceCentroid, relStackCentroid); Polygon polygon = MakePolygon(); info.polygonCentroids[polygon] = info.pointLocations[centroid]; info.polygonNormals [polygon] = Vector3.UnitZ; if ((stack == 0) && (innerRadius == 0.0)) { Corner tip = MakeCorner(info, polygon, slice, stack); MakeCorner(info, polygon, slice + 1, stack + 1); MakeCorner(info, polygon, slice, stack + 1); Vector2 t1 = info.pointTexcoords[GetPoint(info, slice, stack)]; Vector2 t2 = info.pointTexcoords[GetPoint(info, slice + 1, stack)]; Vector2 averageTexcoord = (t1 + t2) / 2.0f; info.cornerTexcoords[tip] = averageTexcoord; } else { MakeCorner(info, polygon, slice + 1, stack + 1); MakeCorner(info, polygon, slice, stack + 1); MakeCorner(info, polygon, slice, stack); MakeCorner(info, polygon, slice + 1, stack); } } } BuildEdges(); }
public Tube( IParametricCurve curve, float radius, int sliceCount, int stackCount ) { float tStep = 1.0f / 512.0f; // Compute initial N Vector3 pos = curve.PositionAt(0.0f); Vector3 posNext = curve.PositionAt(0.0f + tStep); Vector3 posNext2 = curve.PositionAt(0.0f + tStep + tStep); Vector3 d1 = posNext - pos; Vector3 d2 = (posNext2 - posNext) - d1; Vector3 T = Vector3.Normalize(d1); Vector3 N = Vector3.Normalize(d2); Vector3 B = Vector3.Normalize(Vector3.Cross(T, N)); N = Vector3.Normalize(Vector3.Cross(B, T)); var pointLocations = PointAttributes.FindOrCreate <Vector3>("point_locations"); var pointNormals = PointAttributes.FindOrCreate <Vector3>("point_normals"); var pointTexCoords = PointAttributes.FindOrCreate <Vector2>("point_texcoords"); var cornerNormals = CornerAttributes.FindOrCreate <Vector3>("corner_normals"); //var cornerTexCoords = CornerAttributes.FindOrCreate<Vector2>("corner_texcoords"); /* Other vertices */ List <Point> points = new List <Point>(); for (int stack = 0; stack <= stackCount; ++stack) { float t = (float)stack / (float)stackCount; pos = curve.PositionAt(t); posNext = curve.PositionAt(t + tStep); d1 = posNext - pos; T = Vector3.Normalize(d1); B = Vector3.Normalize(Vector3.Cross(T, N)); N = Vector3.Normalize(Vector3.Cross(B, T)); for (int slice = 0; slice < sliceCount; ++slice) { float relPhi = (float)slice / (float)sliceCount; float phi = (float)System.Math.PI * 2.0f * relPhi; float sinPhi = (float)System.Math.Sin(phi); float cosPhi = (float)System.Math.Cos(phi); Vector3 v = pos; v += N * sinPhi * radius; v += B * cosPhi * radius; Point point = MakePoint(); pointLocations[point] = v; pointNormals [point] = N * sinPhi + B * cosPhi; pointTexCoords[point] = new Vector2(relPhi, t); points.Add(point); } } /* Bottom parts */ { Vector3 bottomPosition = curve.PositionAt(0.0f); Vector3 bottomPositionNext = curve.PositionAt(tStep); Vector3 bottomTangent = Vector3.Normalize(bottomPosition - bottomPositionNext); Polygon polygon = MakePolygon(); for (int slice = 0; slice < sliceCount; ++slice) { int stack = 0; int reverseSlice = sliceCount - 1 - slice; Corner corner = polygon.MakeCorner( points[(stack * (sliceCount)) + reverseSlice] ); cornerNormals[corner] = bottomTangent; } } /* Middle quads, t = 0 ... t = 1 */ for (int stack = 0; stack < stackCount; ++stack) { int nextStack = stack + 1; for (int slice = 0; slice < sliceCount; ++slice) { int nextSlice = (slice + 1) % sliceCount; MakePolygon( points[(nextStack * (sliceCount)) + nextSlice], points[(nextStack * (sliceCount)) + slice], points[(stack * (sliceCount)) + slice], points[(stack * (sliceCount)) + nextSlice] ); } } /* Top parts */ { Vector3 topPosition = curve.PositionAt(1.0f); Vector3 topPositionPrev = curve.PositionAt(1.0f - tStep); Vector3 topTangent = Vector3.Normalize(topPosition - topPositionPrev); Polygon polygon = MakePolygon(); for (int slice = 0; slice < sliceCount; ++slice) { int stack = stackCount; Corner corner = polygon.MakeCorner( points[(stack * (sliceCount)) + slice] ); cornerNormals[corner] = topTangent; } } }
/// \todo Accelerate by sorting along major axis public void Merge(Geometry other) { Dictionary <Point, Point> otherPointsToNewPoints = new Dictionary <Point, Point>(); var pointLocationsSelf = PointAttributes.FindOrNull <Vector3>("point_locations"); var pointLocationsOther = other.PointAttributes.FindOrNull <Vector3>("point_locations"); float pointEpsilon = 0.0001f; // Merge points foreach (Point otherPoint in other.Points) { Vector3 otherPosition = pointLocationsOther[otherPoint]; bool existingPointCloseEnough = false; foreach (Point existingPoint in Points) { Vector3 existingPosition = pointLocationsSelf[existingPoint]; float distanceSquared = existingPosition.DistanceSquared(otherPosition); if (distanceSquared < pointEpsilon) { existingPointCloseEnough = true; otherPointsToNewPoints[otherPoint] = existingPoint; break; } } if (existingPointCloseEnough == false) { otherPointsToNewPoints[otherPoint] = MakePoint(otherPosition); } } // Merge polygons foreach (Polygon otherPolygon in other.Polygons) { // Test if we can find at least single matching polygon Polygon matchingPolygon = null; foreach (Polygon existingPolygon in Polygons) { // Test that all other corners can be found bool missingCorners = false; foreach (Corner otherCorner in otherPolygon.Corners) { Point newPoint = otherPointsToNewPoints[otherCorner.Point]; bool cornerFound = false; // Find matching corner foreach (Corner existingCorner in existingPolygon.Corners) { if (newPoint == existingCorner.Point) { cornerFound = true; break; } } // No matching corner found, continue if (cornerFound == false) { missingCorners = true; break; } } if (missingCorners == true) { continue; } // No missing corners - polygons match matchingPolygon = existingPolygon; break; } if (matchingPolygon != null) { // There was a matching polygon, delete it and do not create new from other RemovePolygon(matchingPolygon); //Polygons.Remove(matchingPolygon); } else { // There was no match, add new from other Polygon newPolygon = MakePolygon(); foreach (Corner otherCorner in otherPolygon.Corners) { Point otherPoint = otherCorner.Point; Point newPoint = otherPointsToNewPoints[otherPoint]; newPolygon.MakeCorner(newPoint); } } } // Finally, remove unused points HashSet <Point> usedPoints = new HashSet <Point>(); foreach (Polygon polygon in Polygons) { foreach (Corner corner in polygon.Corners) { usedPoints.Add(corner.Point); } } List <Point> pointsToRemove = new List <Point>(); foreach (Point point in Points) { if (usedPoints.Contains(point) == false) { pointsToRemove.Add(point); } } foreach (Point pointToRemove in pointsToRemove) { Points.Remove(pointToRemove); } }
public void MergeFast(Geometry other, Polygon thisPolygon, Polygon otherPolygon) { Dictionary <Point, Point> otherPointsToNewPoints = new Dictionary <Point, Point>(); var pointLocationsSelf = PointAttributes.FindOrNull <Vector3>("point_locations"); var pointLocationsOther = other.PointAttributes.FindOrNull <Vector3>("point_locations"); float pointEpsilon = 0.0001f; // Merge points foreach (Point otherPoint in other.Points) { Vector3 otherPosition = pointLocationsOther[otherPoint]; bool existingPointCloseEnough = false; foreach (Corner existingCorner in thisPolygon.Corners) { Point existingPoint = existingCorner.Point; Vector3 existingPosition = pointLocationsSelf[existingPoint]; float distanceSquared = existingPosition.DistanceSquared(otherPosition); if (distanceSquared < pointEpsilon) { existingPointCloseEnough = true; otherPointsToNewPoints[otherPoint] = existingPoint; break; } } if (existingPointCloseEnough == false) { otherPointsToNewPoints[otherPoint] = MakePoint(otherPosition); } } RemovePolygon(thisPolygon); // Merge polygons foreach (Polygon otherPolygon2 in other.Polygons) { if (otherPolygon != otherPolygon2) { Polygon newPolygon = MakePolygon(); foreach (Corner otherCorner in otherPolygon.Corners) { Point otherPoint = otherCorner.Point; Point newPoint = otherPointsToNewPoints[otherPoint]; newPolygon.MakeCorner(newPoint); } } } // Finally, remove unused points HashSet <Point> usedPoints = new HashSet <Point>(); foreach (Polygon polygon in Polygons) { foreach (Corner corner in polygon.Corners) { usedPoints.Add(corner.Point); } } List <Point> pointsToRemove = new List <Point>(); foreach (Point point in Points) { if (usedPoints.Contains(point) == false) { pointsToRemove.Add(point); } } foreach (Point pointToRemove in pointsToRemove) { Points.Remove(pointToRemove); } }
public void Geodesate(float radius) { float rInv = 1.0f / radius; var polygonCentroids = PolygonAttributes.FindOrNull <Vector3>("polygon_centroids"); var polygonNormals = PolygonAttributes.FindOrNull <Vector3>("polygon_normals"); var pointLocations = PointAttributes.FindOrNull <Vector3>("point_locations"); var pointNormals = PointAttributes.FindOrNull <Vector3>("point_normals"); var cornerNormals = CornerAttributes.FindOrNull <Vector3>("corner_normals"); // Make copies of old points foreach (Point point in Points) { if ( (pointLocations != null) && pointLocations.ContainsKey(point) ) { Vector3 newNormal = Vector3.Normalize(pointLocations[point]); pointLocations[point] = radius * newNormal; if ( (pointNormals != null) && pointNormals.ContainsKey(point) ) { pointNormals[point] = newNormal; } } } foreach (Polygon polygon in Polygons) { if ( (polygonCentroids != null) && polygonCentroids.ContainsKey(polygon) ) { Vector3 newNormalizedCentroid = Vector3.Normalize(polygonCentroids[polygon]); polygonCentroids[polygon] = radius * newNormalizedCentroid; if ( (polygonNormals != null) && polygonNormals.ContainsKey(polygon) ) { polygonNormals[polygon] = newNormalizedCentroid; } } if (cornerNormals != null) { foreach (Corner corner in polygon.Corners) { if ( cornerNormals.ContainsKey(corner) ) { if (pointNormals.ContainsKey(corner.Point)) { cornerNormals[corner] = pointNormals[corner.Point]; } else if (pointLocations.ContainsKey(corner.Point)) { cornerNormals[corner] = pointLocations[corner.Point] * rInv; } } } } } }
public Sphere ComputeBoundingSphereRitter() { // An Efficient Bounding Sphere // by Jack Ritter // from "Graphics Gems", Academic Press, 1990 // Routine to calculate near-optimal bounding // sphere over a set of points in 3D // Code written by Jack Ritter and Lyle Rains. var pointPositions = PointAttributes.FindOrCreate <Vector3>("point_locations"); // FIRST PASS: Find 6 minima/maxima points Vector3 xmin, xmax, ymin, ymax, zmin, zmax; xmin = ymin = zmin = Vector3.MaxValue; xmax = ymax = zmax = Vector3.MinValue; foreach (Point point in Points) { Vector3 p = pointPositions[point]; if (p.X < xmin.X) { xmin = p; } if (p.X > xmax.X) { xmax = p; } if (p.Y < ymin.Y) { ymin = p; } if (p.Y > ymax.Y) { ymax = p; } if (p.Z < zmin.Z) { zmin = p; } if (p.Z > zmax.Z) { zmax = p; } } // Set span.X = distance between the 2 points xmin & xmax (squared) Vector3 span; Vector3 d; d.X = xmax.X - xmin.X; d.Y = xmax.Y - xmin.Y; d.Z = xmax.Z - xmin.Z; span.X = d.LengthSquared; // Same for Y & Z spans d.X = ymax.X - ymin.X; d.Y = ymax.Y - ymin.Y; d.Z = ymax.Z - ymin.Z; span.Y = d.LengthSquared; d.X = zmax.X - zmin.X; d.Y = zmax.Y - zmin.Y; d.Z = zmax.Z - zmin.Z; span.Z = d.LengthSquared; // Set points dia1 & dia2 to the maximally separated pair Vector3 dia1 = xmin; Vector3 dia2 = xmax; // Assume xspan biggest float maxspan = span.X; if (span.Y > maxspan) { maxspan = span.Y; dia1 = ymin; dia2 = ymax; } if (span.Z > maxspan) { dia1 = zmin; dia2 = zmax; } // dia1, dia2 is a diameter of initial sphere // Calculate initial center Vector3 cen = (dia1 + dia2) / 2.0f; // Calculate initial radius^2 and radius d = dia2 - cen; // Radius vector float rad_sq = d.LengthSquared;; float rad = d.LengthSquared; // SECOND PASS: Increment current sphere foreach (Point point in Points) { Vector3 p = pointPositions[point]; d = p - cen; float old_to_p_sq = d.LengthSquared; // Do r^2 test first if (old_to_p_sq > rad_sq) { // This point is outside of current sphere float old_to_p = (float)System.Math.Sqrt(old_to_p_sq); // Calc radius of new sphere rad = (rad + old_to_p) / 2.0f; // For next r^2 compare rad_sq = rad * rad; float old_to_new = old_to_p - rad; // Calculate center of new sphere cen = (rad * cen + old_to_new * p) / old_to_p; // Suppress if desired #if false System.Diagnostics.Debug.WriteLine( " New sphere: cen,rad = " + cen.ToString() + " " + rad ); #endif } } // THIRD PASS: Adjust the sphere along major axis for potential improvements Sphere s = new Sphere(cen, rad); AdjustBoundingSphere(ref s, -Vector3.UnitX); AdjustBoundingSphere(ref s, Vector3.UnitX); AdjustBoundingSphere(ref s, -Vector3.UnitY); AdjustBoundingSphere(ref s, Vector3.UnitY); AdjustBoundingSphere(ref s, -Vector3.UnitZ); AdjustBoundingSphere(ref s, Vector3.UnitZ); return(s); }
public Cone( double minX, double maxX, double bottomRadius, double topRadius, bool useBottom, bool useTop, int sliceCount, int stackDivision ) { MakeInfo info = new MakeInfo(minX, maxX, bottomRadius, topRadius, useBottom, useTop, sliceCount, stackDivision); info.pointLocations = PointAttributes.FindOrCreate <Vector3>("point_locations"); info.pointNormals = PointAttributes.FindOrCreate <Vector3>("point_normals"); info.pointTexcoords = PointAttributes.FindOrCreate <Vector2>("point_texcoords"); info.polygonCentroids = PolygonAttributes.FindOrCreate <Vector3>("polygon_centroids"); info.polygonNormals = PolygonAttributes.FindOrCreate <Vector3>("polygon_normals"); info.cornerNormals = CornerAttributes.FindOrCreate <Vector3>("corner_normals"); info.cornerTexcoords = CornerAttributes.FindOrCreate <Vector2>("corner_texcoords"); /* Other vertices */ for (int slice = 0; slice <= sliceCount; ++slice) { double relSlice = (double)slice / (double)sliceCount; for (int stack = -stackDivision - info.bottomNotSingular; stack <= stackDivision + info.topNotSingular; ++stack) { double relStack = (double)stack / (double)(stackDivision + 1); info.points[new KeyValuePair <int, int>(slice, stack)] = ConePoint(info, relSlice, relStack); } } /* Bottom parts */ if (bottomRadius == 0.0) { info.bottom = MakePoint(minX, 0.0, 0.0); /* apex */ for (int slice = 0; slice < sliceCount; ++slice) { int stack = -stackDivision; // second last stack, bottom is -stackDivision - 1 double relSliceCentroid = ((double)slice + 0.5) / (double)sliceCount; double relStackCentroid = -1.0 + (0.5 / (double)(stackDivision + 1)); Point centroid = ConePoint(info, relSliceCentroid, relStackCentroid); Polygon polygon = MakePolygon(); MakeCorner(info, polygon, slice + 1, stack); MakeCorner(info, polygon, slice, stack); Corner tip = MakeCorner(info, polygon, slice, -stackDivision - 1); Vector3 n1 = info.pointNormals[GetPoint(info, slice, stack)]; Vector3 n2 = info.pointNormals[GetPoint(info, slice + 1, stack)]; Vector3 averageNormal = Vector3.Normalize(n1 + n2); info.cornerNormals[tip] = averageNormal; Vector2 t1 = info.pointTexcoords[GetPoint(info, slice, stack)]; Vector2 t2 = info.pointTexcoords[GetPoint(info, slice + 1, stack)]; Vector2 averageTexCoord = (t1 + t2) / 2.0f; info.cornerTexcoords[tip] = averageTexCoord; info.polygonCentroids[polygon] = info.pointLocations[centroid]; info.polygonNormals [polygon] = info.pointNormals [centroid]; } } else { if (useBottom == true) { Polygon polygon = MakePolygon(); info.polygonCentroids[polygon] = new Vector3((float)minX, 0.0f, 0.0f); info.polygonNormals [polygon] = new Vector3(-1.0f, 0.0f, 0.0f); for (int slice = 0; slice < sliceCount; ++slice) { int reverseSlice = sliceCount - 1 - slice; MakeCorner(info, polygon, reverseSlice, -stackDivision - 1, true); } } } /* Middle quads, bottom up */ for ( int stack = -stackDivision - info.bottomNotSingular; stack < stackDivision + info.topNotSingular; ++stack ) { double relStackCentroid = ((double)stack + 0.5) / (double)(stackDivision + 1); for (int slice = 0; slice < sliceCount; ++slice) { double relSliceCentroid = ((double)(slice) + 0.5) / (double)(sliceCount); Point centroid = ConePoint(info, relSliceCentroid, relStackCentroid); Polygon polygon = MakePolygon(); MakeCorner(info, polygon, slice + 1, stack + 1); MakeCorner(info, polygon, slice, stack + 1); MakeCorner(info, polygon, slice, stack); MakeCorner(info, polygon, slice + 1, stack); info.polygonCentroids[polygon] = info.pointLocations[centroid]; info.polygonNormals [polygon] = info.pointNormals [centroid]; } } /* Top parts */ if (topRadius == 0.0) { info.top = MakePoint(maxX, 0.0, 0.0); /* apex */ for (int slice = 0; slice < sliceCount; ++slice) { int stack = stackDivision; double relSliceCentroid = ((double)(slice) + 0.5) / (double)(sliceCount); double relStackCentroid = 1.0 - (0.5 / (double)(stackDivision + 1)); Point centroid = ConePoint(info, relSliceCentroid, relStackCentroid); Polygon polygon = MakePolygon(); Corner tip = MakeCorner(info, polygon, slice, stackDivision + 1); MakeCorner(info, polygon, slice, stack); MakeCorner(info, polygon, slice + 1, stack); Vector3 n1 = info.pointNormals[GetPoint(info, slice, stack)]; Vector3 n2 = info.pointNormals[GetPoint(info, slice + 1, stack)]; Vector3 averageNormal = Vector3.Normalize(n1 + n2); info.cornerNormals[tip] = averageNormal; Vector2 t1 = info.pointTexcoords[GetPoint(info, slice, stack)]; Vector2 t2 = info.pointTexcoords[GetPoint(info, slice + 1, stack)]; Vector2 averageTexcoord = (t1 + t2) / 2.0f; info.cornerTexcoords[tip] = averageTexcoord; info.polygonCentroids[polygon] = info.pointLocations[centroid]; info.polygonNormals [polygon] = info.pointNormals [centroid]; } } else { if (useTop == true) { Polygon polygon = MakePolygon(); info.polygonCentroids[polygon] = new Vector3((float)maxX, 0.0f, 0.0f); info.polygonNormals [polygon] = new Vector3(1.0f, 0.0f, 0.0f); for (int slice = 0; slice < sliceCount; ++slice) { MakeCorner(info, polygon, slice, stackDivision + 1, true); } } } //MergePoints(); }