private static double UpdateBackAngle(BoundingBoxData boxData) { Edge nextEdge = null; var yDir = boxData.RotatorVector.Cross(boxData.Direction); var minSlope = double.PositiveInfinity; foreach (var edge in boxData.BackVertex.Edges) { var otherVertex = edge.OtherVertex(boxData.BackVertex); var vector = otherVertex.Coordinates.Subtract(boxData.BackVertex.Coordinates); var y = yDir.Dot(vector); if (y < 0) { // the x-value is boxData.Direction.Dot(vector) and it's positive for all edges since it's the back vertex var slope = -boxData.Direction.Dot(vector) / y; if (slope < minSlope) { minSlope = slope; nextEdge = edge; } } } if (minSlope < 0) { return(double.PositiveInfinity); } boxData.BackVertex = nextEdge.OtherVertex(boxData.BackVertex); boxData.BackEdge = nextEdge; return(Math.Atan(minSlope)); }
private static double UpdateOrthAngle(BoundingBoxData boxData) { GaussSphereArc arcToRemove = null; var minSlope = double.PositiveInfinity; boxData.PosYDir = boxData.RotatorVector.Cross(boxData.Direction).Normalize(); foreach (var arc in boxData.OrthGaussSphereArcs) { var x = boxData.Direction.Dot(arc.ToFace.Normal); var y = boxData.PosYDir.Dot(arc.ToFace.Normal); if (y == 0.0) { continue; } var tempSlope = -x / y; if (!(tempSlope < minSlope)) { continue; } minSlope = tempSlope; arcToRemove = arc; } if (minSlope < 0) { return(double.PositiveInfinity); } var edgesAtJunction = new List <Edge>(arcToRemove.ToFace.Edges); for (var i = boxData.OrthGaussSphereArcs.Count - 1; i >= 0; i--) { var index = edgesAtJunction.FindIndex(boxData.OrthGaussSphereArcs[i].Edge); if (index >= 0) { boxData.OrthGaussSphereArcs.RemoveAt(i); boxData.OrthVertices.Remove(edgesAtJunction[index].From); boxData.OrthVertices.Remove(edgesAtJunction[index].To); edgesAtJunction.RemoveAt(index); } } foreach (var edge in edgesAtJunction) { if (!boxData.OrthVertices.Contains(edge.From)) { boxData.OrthVertices.Add(edge.From); } if (!boxData.OrthVertices.Contains(edge.To)) { boxData.OrthVertices.Add(edge.To); } boxData.OrthGaussSphereArcs.Add(new GaussSphereArc(edge, edge.OwnedFace == arcToRemove.ToFace ? edge.OtherFace : edge.OwnedFace)); } return(Math.Atan(minSlope)); }
private static bool DifferentMembershipInExtrema(BoundingBoxData boxDataA, BoundingBoxData boxDataB) { var boxASides = boxDataA.Box.PointsOnFaces.Skip(2); var boxBSides = boxDataB.Box.PointsOnFaces.Skip(2).ToList(); foreach (var boxASide in boxASides) { if (!boxBSides.Any(boxBSide => boxASide.Intersect(boxBSide).Any())) { return(true); } } return(false); }
/// <summary> /// Finds the obb along direction. /// </summary> /// <param name="boxData">The box data.</param> private static void FindOBBAlongDirection(BoundingBoxData boxData) { var direction0 = boxData.Direction = boxData.Direction.normalize(3); var height = direction0.dotProduct(boxData.RotatorEdge.From.Position.subtract(boxData.BackVertex.Position, 3), 3); double[,] backTransform; var points = MiscFunctions.Get2DProjectionPoints(boxData.OrthVertices, direction0, out backTransform, false); var boundingRectangle = RotatingCalipers2DMethod(points); //Get the Direction vectors from rotating caliper and projection. var tempDirection = new[] { boundingRectangle.Directions2D[0][0], boundingRectangle.Directions2D[0][1], 0.0, 1.0 }; var direction1 = backTransform.multiply(tempDirection).Take(3).ToArray(); tempDirection = new[] { boundingRectangle.Directions2D[1][0], boundingRectangle.Directions2D[1][1], 0.0, 1.0 }; var direction2 = backTransform.multiply(tempDirection).Take(3).ToArray(); boxData.Box = new BoundingBox { Dimensions = new[] { height, boundingRectangle.Dimensions[0], boundingRectangle.Dimensions[1] }, Directions = new[] { direction0, direction1, direction2 }, PointsOnFaces = new[] { new List <Vertex> { boxData.RotatorEdge.From, boxData.RotatorEdge.To }, new List <Vertex> { boxData.BackVertex }, boundingRectangle.PointsOnSides[0].SelectMany(p => p.References).ToList(), boundingRectangle.PointsOnSides[1].SelectMany(p => p.References).ToList(), boundingRectangle.PointsOnSides[2].SelectMany(p => p.References).ToList(), boundingRectangle.PointsOnSides[3].SelectMany(p => p.References).ToList() }, Volume = height * boundingRectangle.Dimensions[0] * boundingRectangle.Dimensions[1] }; }
public void SerializeBoundingBoxData_ValidObjectsGiven_ShouldPass() { const string expectedXml = @"<?xml version=""1.0"" encoding=""utf-8""?><wps:BoundingBoxData xmlns:ows=""http://www.opengis.net/ows/2.0"" xmlns:xli=""http://www.w3.org/1999/xlink"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:wps=""http://www.opengis.net/wps/2.0""><wps:Format mimeType=""test"" maximumMegabytes=""0"" default=""false"" /><wps:Format mimeType=""test"" maximumMegabytes=""0"" default=""false"" /><wps:SupportedCRS default=""true"">test-uri-1</wps:SupportedCRS><wps:SupportedCRS default=""true"">test-uri-1</wps:SupportedCRS><wps:SupportedCRS default=""true"">test-uri-1</wps:SupportedCRS></wps:BoundingBoxData>"; // Remove white spaces and new line characters for XML comparison. var trimmedExpectedXml = Regex.Replace(expectedXml, @"\s+", string.Empty); var boundingBoxData = new BoundingBoxData { Formats = new[] { new Format { MimeType = "test" }, new Format { MimeType = "test" }, }, SupportedCrs = new[] { new CoordinateReferenceSystem { IsDefault = true, Uri = "test-uri-1" }, new CoordinateReferenceSystem { IsDefault = true, Uri = "test-uri-1" }, new CoordinateReferenceSystem { IsDefault = true, Uri = "test-uri-1" }, } }; var resultXml = _serializer.Serialize(boundingBoxData); var trimmedResult = Regex.Replace(resultXml, @"\s+", string.Empty); trimmedResult.Should().Be(trimmedExpectedXml); }
//void Update() //{ // if(Input.GetKeyUp(KeyCode.Alpha1)) // { // Play("sayHi", 1, 1); // } //} public Rect GetRectColider(string name) { if (dragonBonesCom != null && dragonBonesCom.animation != null) { Slot slot = dragonBonesCom.armature.GetSlot(name); if (slot != null) { BoundingBoxData boundingBoxData = slot.boundingBoxData; if (boundingBoxData != null) { var tx = slot.globalTransformMatrix.tx; var ty = slot.globalTransformMatrix.ty; var boundingBoxWidth = boundingBoxData.width; var boundingBoxHeight = boundingBoxData.height; //var leftTopPos = new Vector3(tx - boundingBoxWidth * 0.5f, ty + boundingBoxHeight * 0.5f, 0.0f); //var leftBottomPos = new Vector3(tx - boundingBoxWidth * 0.5f, ty - boundingBoxHeight * 0.5f, 0.0f); //var rightTopPos = new Vector3(tx + boundingBoxWidth * 0.5f, ty + boundingBoxHeight * 0.5f, 0.0f); //var rightBottomPos = new Vector3(tx + boundingBoxWidth * 0.5f, ty - boundingBoxHeight * 0.5f, 0.0f); return(new Rect(tx, ty, boundingBoxWidth, boundingBoxHeight)); } } } return(new Rect(0, 0, 0, 0)); }
/// <summary> /// The MC_ApproachOne rotates around each edge of the convex hull between the owned and /// other faces. In this way, it guarantees a much more optimal solution than the flat /// with face algorithm, but is, therefore, slower. /// </summary> /// <timeDomain> /// Since the computation cost for each Bounding Box is linear O(n), /// and the approximate worse case number of normals considered is n*PI/maxDeltaAngle, /// Lower Bound O(n^2). Upper Bound O(n^(2)*PI/maxDeltaAngle). [ex. upper bound is O(36*n^2) when MaxDeltaAngle = 5 /// degrees.] /// </timeDomain> /// <accuracy> /// Garantees the optimial orientation is within maxDeltaAngle error. /// </accuracy> private static BoundingBox OrientedBoundingBox(TVGLConvexHull convexHull) { var minBox = new BoundingBox( new Vector3(double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity), new[] { Vector3.UnitX, Vector3.UnitY, Vector3.UnitZ }, new Vector3(double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity)); foreach (var rotateEdge in convexHull.Edges) { #region Initialize variables //Initialize variables //rotatorVector is basically the edge in question - the vector that is being rotated about var rotatorVector = rotateEdge.Vector.Normalize(); // startDir is the starting Direction - based on the OtherFace var startDir = rotateEdge.OtherFace.Normal; // endDir is the OwnedFace final Direction - we go from Other to Owned since in order to be about // the positive Direction of the rotatorVector var endDir = rotateEdge.OwnedFace.Normal; // posYDir is the vector for the positive y-Direction. Well, this is a simplification of the //gauss sphere to a 2D circle. The Direction (such as startDir) represents the x-axis and this //, which is the orthogonal is the y Direction var origPosYDir = rotatorVector.Cross(startDir).Normalize(); var totalAngle = Math.PI - rotateEdge.InternalAngle; var thisBoxData = new BoundingBoxData(startDir, origPosYDir, rotateEdge, rotatorVector, convexHull); #endregion FindOBBAlongDirection(thisBoxData); if (thisBoxData.Box.Volume < minBox.Volume) { minBox = thisBoxData.Box; } var angle = 0.0; var deltaAngleToBackChange = 0.0; var deltaAngleOrthSet = 0.0; BoundingBoxData backChangeBox = null; BoundingBoxData sideChangeBox = null; do { if (deltaAngleToBackChange <= 0) { backChangeBox = thisBoxData.Copy(); deltaAngleToBackChange = UpdateBackAngle(backChangeBox); } if (deltaAngleOrthSet <= 0) { sideChangeBox = thisBoxData.Copy(); deltaAngleOrthSet = UpdateOrthAngle(sideChangeBox); } BoundingBoxData nextBoxData; if (deltaAngleOrthSet < deltaAngleToBackChange) { deltaAngleToBackChange -= deltaAngleOrthSet; angle += deltaAngleOrthSet; deltaAngleOrthSet = 0; nextBoxData = sideChangeBox; } else if (deltaAngleToBackChange < deltaAngleOrthSet) { deltaAngleOrthSet -= deltaAngleToBackChange; angle += deltaAngleToBackChange; deltaAngleToBackChange = 0; nextBoxData = backChangeBox; } else // if they are equal to each other { angle += deltaAngleToBackChange; deltaAngleOrthSet = deltaAngleToBackChange = 0; nextBoxData = backChangeBox; } if (angle > totalAngle) { // nextBoxData = new BoundingBoxData(endDir, rotatorVector.Cross(endDir).Normalize(), rotateEdge, rotatorVector, convexHull); nextBoxData.Angle = totalAngle; nextBoxData.Direction = endDir; } else { nextBoxData.Angle = angle; nextBoxData.Direction = UpdateDirection(startDir, rotatorVector, origPosYDir, angle); } nextBoxData.PosYDir = nextBoxData.RotatorVector.Cross(nextBoxData.Direction).Normalize(); /****************/ FindOBBAlongDirection(nextBoxData); /****************/ if (DifferentMembershipInExtrema(thisBoxData, nextBoxData)) { var lowerBox = thisBoxData; var upperBox = nextBoxData; var midBox = thisBoxData.Copy(); while (!lowerBox.Angle.IsPracticallySame(upperBox.Angle, Constants.OBBTolerance)) { midBox.Direction = (lowerBox.Direction + upperBox.Direction).Divide(2).Normalize(); midBox.Angle = (lowerBox.Angle + upperBox.Angle) / 2.0; FindOBBAlongDirection(midBox); if (midBox.Box.Volume > lowerBox.Box.Volume && midBox.Box.Volume > upperBox.Box.Volume) { break; } if (!DifferentMembershipInExtrema(lowerBox, midBox)) { lowerBox = midBox; } else if (!DifferentMembershipInExtrema(upperBox, midBox)) { upperBox = midBox; } else { throw new Exception("new midbox is different from BOTH neighbors!"); } } if (thisBoxData.Box.Volume < minBox.Volume) { minBox = midBox.Box; } } thisBoxData = nextBoxData; if (thisBoxData.Box.Volume < minBox.Volume) { minBox = thisBoxData.Box; } } while (angle < totalAngle); } return(minBox); }