public void Remove(T removedObject, SimpleVolume previousVolume) { if (values == null) { if (childVolumeA.myVolume.Overlaps(previousVolume)) { childVolumeA.Remove(removedObject, previousVolume); } if (childVolumeB.myVolume.Overlaps(previousVolume)) { childVolumeB.Remove(removedObject, previousVolume); } return; } for (byte i = 0; i < heldValues; i++) { if (values[i].Equals(removedObject)) { int count = heldValues - i - 1; if (count > 0) { Array.Copy(values, i + 1, values, i, count); } heldValues--; values[heldValues] = default(T); return; } } }
public static long GetMaximumSizeToExtendDynamicVolume(DynamicVolume volume) { if (volume is SimpleVolume) { SimpleVolume simpleVolume = (SimpleVolume)volume; return(GetMaximumSizeToExtendDynamicDiskExtent(simpleVolume.DiskExtent)); } else if (volume is StripedVolume) { StripedVolume stripedVolume = (StripedVolume)volume; long max = Int64.MaxValue; foreach (DynamicDiskExtent extent in stripedVolume.Extents) { long extentMax = GetMaximumSizeToExtendDynamicDiskExtent(extent); max = Math.Min(max, extentMax); } return(max); } else if (volume is Raid5Volume) { Raid5Volume raid5Volume = (Raid5Volume)volume; long max = Int64.MaxValue; foreach (DynamicDiskExtent extent in raid5Volume.Extents) { long extentMax = GetMaximumSizeToExtendDynamicDiskExtent(extent); max = Math.Min(max, extentMax); } return(max); } else { return(0); } }
public void UpdateChild(T movedObject, SimpleVolume previousVolume) { if (movedObject.IsInVolume(myVolume)) { if (previousVolume.Overlaps(myVolume)) { if (values == null) { childVolumeA.UpdateChild(movedObject, previousVolume); childVolumeB.UpdateChild(movedObject, previousVolume); return; } for (byte i = 0; i < heldValues; i++) { if (values[i].Equals(movedObject)) { return; } } } Add(movedObject); return; } if (previousVolume.Overlaps(myVolume)) { Remove(movedObject, myVolume); } }
public List <T> InVolume(SimpleVolume volume, bool exact = true) { HashSet <T> possibleOverlaps = new HashSet <T>(); List <T> list = new List <T>(); rootNode.InVolume(volume, list, possibleOverlaps, true, exact); return(list); }
public void Update(T movedObject, SimpleVolume previousVolume) { if (values == null) { childVolumeA.UpdateChild(movedObject, previousVolume); childVolumeB.UpdateChild(movedObject, previousVolume); return; } }
public void InVolume(SimpleVolume vol, List <T> list, HashSet <T> possibleOverlaps, bool last, bool exact) { if (values == null) { bool inSecond = childVolumeA.myVolume.Overlaps(vol); if (childVolumeA.myVolume.Overlaps(vol)) { childVolumeA.InVolume(vol, list, possibleOverlaps, last && !inSecond, exact); } if (inSecond) { childVolumeA.InVolume(vol, list, possibleOverlaps, last, exact); } return; } int startingIndex = list.Count; if (exact) { for (int i = 0; i < heldValues; i++) { T item = values[i]; if (item.IsInVolume(vol) && !possibleOverlaps.Contains(item)) { list.Add(item); } } } else { for (int i = 0; i < heldValues; i++) { T item = values[i]; if (item.GetMaxVolume().Overlaps(vol) && !possibleOverlaps.Contains(item)) { list.Add(item); } } } if (!last) { for (int i = startingIndex; i < list.Count; i++) { if (!list[i].GetMaxVolume().ContainedIn(myVolume)) { possibleOverlaps.Add(list[i]); } } } }
public static void ExtendDynamicVolume(DynamicVolume volume, long numberOfAdditionalExtentSectors, DiskGroupDatabase database) { if (volume is SimpleVolume) { SimpleVolume simpleVolume = (SimpleVolume)volume; VolumeManagerDatabaseHelper.ExtendSimpleVolume(database, simpleVolume, numberOfAdditionalExtentSectors); } else if (volume is StripedVolume) { StripedVolume stripedVolume = (StripedVolume)volume; VolumeManagerDatabaseHelper.ExtendStripedVolume(database, stripedVolume, numberOfAdditionalExtentSectors); } else if (volume is Raid5Volume) { Raid5Volume raid5Volume = (Raid5Volume)volume; VolumeManagerDatabaseHelper.ExtendRAID5Volume(database, raid5Volume, numberOfAdditionalExtentSectors); } }
public void AddIntersectLines(List <Point> points, int surfaceIndex, Obstacle forObstacle, MovementMechanism forMechanism) { VolumeTree <ObstacleHitLine> collection = SurfaceObstacleLines[surfaceIndex]; if (collection == null) { SimpleVolume surfaceVolume = MyVolume; switch (surfaceIndex) { case 0: surfaceVolume.MaxZ = surfaceVolume.MinZ; break; case 1: surfaceVolume.MinZ = surfaceVolume.MaxZ; break; case 2: surfaceVolume.MaxY = surfaceVolume.MinY; break; case 3: surfaceVolume.MinX = surfaceVolume.MaxX; break; case 4: surfaceVolume.MinY = surfaceVolume.MaxY; break; case 5: surfaceVolume.MaxX = surfaceVolume.MinX; break; } collection = new VolumeTree <ObstacleHitLine>(surfaceVolume); SurfaceObstacleLines[surfaceIndex] = collection; } ObstacleHitLineGroup lineGroup = new ObstacleHitLineGroup(); lineGroup.CausingObstacle = forObstacle; lineGroup.Mechanism = forMechanism; lineGroup.SetupPoints(points, collection, SurfaceNormal(surfaceIndex)); }
private static SimpleVolume GetSimpleVolume(List <DynamicDisk> disks, VolumeManagerDatabase database, ComponentRecord componentRecord, VolumeRecord volumeRecord) { List <ExtentRecord> extentRecords = database.FindExtentsByComponentID(componentRecord.ComponentId); if (extentRecords.Count == 1) { ExtentRecord extentRecord = extentRecords[0]; DiskRecord diskRecord = database.FindDiskByDiskID(extentRecord.DiskId); DynamicDisk disk = DynamicDiskHelper.FindDisk(disks, diskRecord.DiskGuid); // we add nulls as well DynamicDiskExtent extent = DynamicDiskExtentHelper.GetDiskExtent(disk, extentRecord); SimpleVolume volume = new SimpleVolume(extent, volumeRecord.VolumeGuid, database.DiskGroupGuid); volume.VolumeID = volumeRecord.VolumeId; volume.Name = volumeRecord.Name; volume.DiskGroupName = database.DiskGroupName; return(volume); } else { // component / extent records are invalid throw new InvalidDataException("Number of extents in component record does not match actual number of extent records"); } }
public RectangleObstacle(Item backingItem, SimpleVolume volume) : base(backingItem) { Room origin = backingItem.Position.OriginRoom; MyVolume = volume; }
public VolumeTree(SimpleVolume maxVolume) { rootNode = new VolumeNode <T>(maxVolume); }
public void Add(T newObject) { if (values == null) { if (newObject.IsInVolume(childVolumeA.myVolume)) { childVolumeA.Add(newObject); } if (newObject.IsInVolume(childVolumeB.myVolume)) { childVolumeB.Add(newObject); } return; } if (heldValues < ValuesSize) { values[heldValues] = newObject; heldValues++; return; } int minX = myVolume.MaxX, minY = myVolume.MaxY, minZ = myVolume.MaxZ, maxX = myVolume.MinX, maxY = myVolume.MinY, maxZ = myVolume.MinZ; for (byte i = 0; i < ValuesSize; i++) { SimpleVolume nextVolume = values[i].GetMaxVolume(); minX = Math.Min(minX, nextVolume.MinX); maxX = Math.Max(maxX, nextVolume.MaxX); minY = Math.Min(minY, nextVolume.MinY); maxY = Math.Max(maxY, nextVolume.MaxY); minZ = Math.Min(minZ, nextVolume.MinZ); maxZ = Math.Max(maxZ, nextVolume.MaxZ); } int middleX = (maxX + minX) / 2; int middleY = (maxY + minY) / 2; int middleZ = (maxZ + minZ) / 2; //Split the current area through the 'center' (technically the center of the USED area) SimpleVolume newLeft, newRight, newForward, newBack, newTop, newBottom; newLeft.MinX = myVolume.MinX; newLeft.MaxX = middleX; newLeft.MinY = myVolume.MinY; newLeft.MaxY = myVolume.MaxY; newLeft.MinZ = myVolume.MinZ; newLeft.MaxZ = myVolume.MaxZ; newRight.MinX = middleX + 1; newRight.MaxX = myVolume.MaxX; newRight.MinY = myVolume.MinY; newRight.MaxY = myVolume.MaxY; newRight.MinZ = myVolume.MinZ; newRight.MaxZ = myVolume.MaxZ; newForward.MinX = myVolume.MinX; newForward.MaxX = myVolume.MaxX; newForward.MinY = myVolume.MinY; newForward.MaxY = middleY; newForward.MinZ = myVolume.MinZ; newForward.MaxZ = myVolume.MaxZ; newBack.MinX = myVolume.MinX; newBack.MaxX = myVolume.MaxX; newBack.MinY = middleY + 1; newBack.MaxY = myVolume.MaxY; newBack.MinZ = myVolume.MinZ; newBack.MaxZ = myVolume.MaxZ; newTop.MinX = myVolume.MinX; newTop.MaxX = myVolume.MaxX; newTop.MinY = myVolume.MinY; newTop.MaxY = myVolume.MaxY; newTop.MinZ = myVolume.MinZ; newTop.MaxZ = middleZ; newBottom.MinX = myVolume.MinX; newBottom.MaxX = myVolume.MaxX; newBottom.MinY = myVolume.MinY; newBottom.MaxY = myVolume.MaxY; newBottom.MinZ = middleZ + 1; newBottom.MaxZ = myVolume.MaxZ; byte leftCount = 0, rightCount = 0, forwardCount = 0, backCount = 0, topCount = 0, bottomCount = 0; T[] leftItems = new T[100]; T[] rightItems = new T[100]; T[] forwardItems = new T[100]; T[] backItems = new T[100]; T[] topItems = new T[100]; T[] bottomItems = new T[100]; //Sort items into the area(s) they exist in for (byte i = 0; i < ValuesSize; i++) { T nextItem = values[i]; if (nextItem.IsInVolume(newLeft)) { leftItems[leftCount++] = nextItem; } if (nextItem.IsInVolume(newRight)) { rightItems[rightCount++] = nextItem; } if (nextItem.IsInVolume(newForward)) { forwardItems[forwardCount++] = nextItem; } if (nextItem.IsInVolume(newBack)) { backItems[backCount++] = nextItem; } if (nextItem.IsInVolume(newTop)) { topItems[topCount++] = nextItem; } if (nextItem.IsInVolume(newBottom)) { bottomItems[bottomCount++] = nextItem; } } byte maxYCount = Math.Max(forwardCount, backCount); byte maxXCount = Math.Max(leftCount, rightCount); byte maxZCount = Math.Max(topCount, bottomCount); if (maxYCount < maxZCount || //Is Y obviously better to split than Z (maxZCount == maxYCount && (maxZ - minZ <= maxY - minY)) || //Is Y less-obviously better-or-equal to split than Z maxXCount < maxZCount || //Is X obviously better to split than Z (maxZCount == maxXCount && (maxZ - minZ <= maxX - minX))) //Is X less-obviously better-or-equal to split than Z { if (maxYCount > maxXCount || //Is X obviously better to split than Y (maxYCount == maxXCount && (maxX - minX >= maxY - minY))) //Is X less-obviously better-or-equal to split than Y { //Split on X childVolumeA = new VolumeNode <T>(newLeft, leftItems); childVolumeB = new VolumeNode <T>(newRight, rightItems); } else { //Split on Y childVolumeA = new VolumeNode <T>(newForward, forwardItems); childVolumeB = new VolumeNode <T>(newBack, backItems); } } else { //Split on Z childVolumeA = new VolumeNode <T>(newTop, topItems); childVolumeB = new VolumeNode <T>(newBottom, bottomItems); } values = null; Add(newObject); }
public bool IsInVolume(SimpleVolume volume) { return(KejUtils.Geometry.Geometry.IsInVolume(volume, Start, End)); }
public OptimizedVolume(SimpleVolume volume, OptimizedModel model) { this.parentModel = model; vertices.Capacity = volume.faceTriangles.Count * 3; facesTriangle.Capacity = volume.faceTriangles.Count; Dictionary<int, List<int>> indexMap = new Dictionary<int, List<int>>(); Stopwatch t = new Stopwatch(); t.Start(); for (int faceIndex = 0; faceIndex < volume.faceTriangles.Count; faceIndex++) { if (MatterSlice.Canceled) { return; } OptimizedFace optimizedFace = new OptimizedFace(); if ((faceIndex % 1000 == 0) && t.Elapsed.Seconds > 2) { LogOutput.logProgress("optimized", faceIndex + 1, volume.faceTriangles.Count); } for (int vertexIndex = 0; vertexIndex < 3; vertexIndex++) { Point3 p = volume.faceTriangles[faceIndex].vertices[vertexIndex]; int hash = (int)(((p.x + MELD_DIST / 2) / MELD_DIST) ^ (((p.y + MELD_DIST / 2) / MELD_DIST) << 10) ^ (((p.z + MELD_DIST / 2) / MELD_DIST) << 20)); int idx = 0; bool add = true; if (indexMap.ContainsKey(hash)) { for (int n = 0; n < indexMap[hash].Count; n++) { if ((vertices[indexMap[hash][n]].position - p).AbsLengthLEQ(MELD_DIST)) { idx = indexMap[hash][n]; add = false; break; } } } if (add) { if (!indexMap.ContainsKey(hash)) { indexMap.Add(hash, new List<int>()); } indexMap[hash].Add(vertices.Count); idx = vertices.Count; vertices.Add(new OptimizedPoint3(p)); } optimizedFace.vertexIndex[vertexIndex] = idx; } if (optimizedFace.vertexIndex[0] != optimizedFace.vertexIndex[1] && optimizedFace.vertexIndex[0] != optimizedFace.vertexIndex[2] && optimizedFace.vertexIndex[1] != optimizedFace.vertexIndex[2]) { //Check if there is a face with the same points bool duplicate = false; for (int _idx0 = 0; _idx0 < vertices[optimizedFace.vertexIndex[0]].usedByFacesList.Count; _idx0++) { for (int _idx1 = 0; _idx1 < vertices[optimizedFace.vertexIndex[1]].usedByFacesList.Count; _idx1++) { for (int _idx2 = 0; _idx2 < vertices[optimizedFace.vertexIndex[2]].usedByFacesList.Count; _idx2++) { if (vertices[optimizedFace.vertexIndex[0]].usedByFacesList[_idx0] == vertices[optimizedFace.vertexIndex[1]].usedByFacesList[_idx1] && vertices[optimizedFace.vertexIndex[0]].usedByFacesList[_idx0] == vertices[optimizedFace.vertexIndex[2]].usedByFacesList[_idx2]) duplicate = true; } } } if (!duplicate) { vertices[optimizedFace.vertexIndex[0]].usedByFacesList.Add(facesTriangle.Count); vertices[optimizedFace.vertexIndex[1]].usedByFacesList.Add(facesTriangle.Count); vertices[optimizedFace.vertexIndex[2]].usedByFacesList.Add(facesTriangle.Count); facesTriangle.Add(optimizedFace); } } } //fprintf(stdout, "\rAll faces are optimized in %5.1fs.\n",timeElapsed(t)); int openFacesCount = 0; for (int faceIndex = 0; faceIndex < facesTriangle.Count; faceIndex++) { OptimizedFace optimizedFace = facesTriangle[faceIndex]; optimizedFace.touchingFaces[0] = getOtherFaceIndexContainingVertices(optimizedFace.vertexIndex[0], optimizedFace.vertexIndex[1], faceIndex); optimizedFace.touchingFaces[1] = getOtherFaceIndexContainingVertices(optimizedFace.vertexIndex[1], optimizedFace.vertexIndex[2], faceIndex); optimizedFace.touchingFaces[2] = getOtherFaceIndexContainingVertices(optimizedFace.vertexIndex[2], optimizedFace.vertexIndex[0], faceIndex); if (optimizedFace.touchingFaces[0] == -1) { openFacesCount++; } if (optimizedFace.touchingFaces[1] == -1) { openFacesCount++; } if (optimizedFace.touchingFaces[2] == -1) { openFacesCount++; } } //fprintf(stdout, " Number of open faces: %i\n", openFacesCount); }
public override void MarkIntersectWithSurface(ObstacleSurface otherSurface, MovementMechanism forMechanism) { Hitbox hitbox = forMechanism.Hitbox; switch (hitbox.Type) { case Hitbox.HitboxType.Square: { //SquareHitbox square = hitbox as SquareHitbox; } break; default: throw new NotImplementedException("Unknown hitbox type"); } SimpleVolume vol = MyVolume; Orientation offset = forMechanism.HitboxOffset(otherSurface); //Reverse changes to find how this object intersects with original surface instead of the other way around. vol.MinX = vol.MinX - offset.x - hitbox.MaxXIncrease((Rotation)offset); vol.MaxX = vol.MaxX - offset.x + hitbox.MaxXDecrease((Rotation)offset); vol.MinY = vol.MinY - offset.y - hitbox.MaxYIncrease((Rotation)offset); vol.MaxY = vol.MaxY - offset.y + hitbox.MaxYDecrease((Rotation)offset); vol.MinZ = vol.MinZ - offset.z - hitbox.MaxZIncrease((Rotation)offset); vol.MaxZ = vol.MaxZ - offset.z + hitbox.MaxZDecrease((Rotation)offset); Vector normal = otherSurface.GetNormal(); int height = otherSurface.GetHeight(); //Important: These indices match the obstacle point indices. int[] differences = new int[8]; differences[0] = (int)normal.DotProduct(vol.MinX, vol.MinY, vol.MinZ) - height; differences[1] = (int)normal.DotProduct(vol.MaxX, vol.MinY, vol.MinZ) - height; differences[2] = (int)normal.DotProduct(vol.MaxX, vol.MaxY, vol.MinZ) - height; differences[3] = (int)normal.DotProduct(vol.MinX, vol.MaxY, vol.MinZ) - height; differences[4] = (int)normal.DotProduct(vol.MinX, vol.MinY, vol.MaxZ) - height; differences[5] = (int)normal.DotProduct(vol.MaxX, vol.MinY, vol.MaxZ) - height; differences[6] = (int)normal.DotProduct(vol.MaxX, vol.MaxY, vol.MaxZ) - height; differences[7] = (int)normal.DotProduct(vol.MinX, vol.MaxY, vol.MaxZ) - height; List <int> negativeHeights = new List <int>(8); List <int> positiveHeights = new List <int>(8); if (differences[0] > 0) { positiveHeights.Add(0); } else { negativeHeights.Add(0); } if (differences[1] > 0) { positiveHeights.Add(1); } else { negativeHeights.Add(1); } if (differences[2] > 0) { positiveHeights.Add(2); } else { negativeHeights.Add(2); } if (differences[3] > 0) { positiveHeights.Add(3); } else { negativeHeights.Add(3); } if (differences[4] > 0) { positiveHeights.Add(4); } else { negativeHeights.Add(4); } if (differences[5] > 0) { positiveHeights.Add(5); } else { negativeHeights.Add(5); } if (differences[6] > 0) { positiveHeights.Add(6); } else { negativeHeights.Add(6); } if (differences[7] > 0) { positiveHeights.Add(7); } else { negativeHeights.Add(7); } if (positiveHeights.Count == 0 || negativeHeights.Count == 0) { return; } for (int i = 0; i < negativeHeights.Count; i++) { int pointId = negativeHeights[i]; for (int j = 0; j < 3; j++) { SurfaceLine line = PointLine(pointId, j); ObstaclePoint otherPoint = line.Start; if (otherPoint.id == pointId) { otherPoint = line.End; } if (differences[otherPoint.id] > 0) { double ratio = differences[pointId] / (differences[pointId] - differences[otherPoint.id]); Point start = PointPosition(pointId); Point end = otherPoint.Position; Point intersectPoint; intersectPoint.x = start.x + (int)((end.x - start.x) * ratio); intersectPoint.y = start.y + (int)((end.y - start.y) * ratio); intersectPoint.z = start.z + (int)((end.z - start.z) * ratio); List <Point> IntersectingPoints = new List <Point>(); IntersectingPoints.Add(intersectPoint); SurfaceLine previousLine = line; SurfaceLine nextLine = new SurfaceLine(); //compiler has failed me for once, this shouldn't need initialization here. int previousSurfaceId = -1; do { ObstacleSurface nextSurface = previousLine.Left; if (previousSurfaceId == nextSurface.surfaceIndex) { nextSurface = previousLine.Right; } for (int k = 0; k < 4; k++) { nextLine = nextSurface.GetLine(k); if (nextLine.id == previousLine.id) { continue; } ObstaclePoint nextStart = nextLine.Start; ObstaclePoint nextEnd = nextLine.End; if ((differences[nextStart.id] > 0 && differences[nextEnd.id] <= 0) || (differences[nextStart.id] <= 0 && differences[nextEnd.id] > 0)) { start = nextStart.Position; end = nextEnd.Position; ratio = differences[nextStart.id] / (differences[nextStart.id] - differences[nextEnd.id]); intersectPoint.x = start.x + (int)((end.x - start.x) * ratio); intersectPoint.y = start.y + (int)((end.y - start.y) * ratio); intersectPoint.z = start.z + (int)((end.z - start.z) * ratio); IntersectingPoints.Add(intersectPoint); break; } } previousSurfaceId = nextSurface.surfaceIndex; previousLine = nextLine; }while (nextLine.id != line.id); otherSurface.AddIntersectLines(IntersectingPoints, this, forMechanism); return; } } } }
public VolumeNode(SimpleVolume maxVolume, T[] startingValues) { myVolume = maxVolume; values = startingValues; }
public void Update(T movedObject, SimpleVolume previousVolume) { rootNode.Update(movedObject, previousVolume); }
public void Remove(T removedObject, SimpleVolume previousVolume) { rootNode.Remove(removedObject, previousVolume); }
public VolumeNode(SimpleVolume maxVolume) { myVolume = maxVolume; values = new T[ValuesSize]; }