public void Bounds_ReturnsVerticesBoundingBox() { var bbox = VectorUtils.Bounds(new Vector2[] { Vector2.zero, Vector2.right, Vector2.one }); Assert.AreEqual(Vector2.zero, bbox.min); Assert.AreEqual(Vector2.one, bbox.max); }
/// <summary> /// Build a 2D bounding box for the shape. /// </summary> protected override void GenerateBounds() { // TO DO // http://www.iquilezles.org/www/articles/bezierbbox/bezierbbox.htm int bezierSteps = VectorShapeUtils.bezierSteps; List <Vector2> pointList = new List <Vector2>(); float step = 1f / bezierSteps; for (int i = 0; i < vertices.Length; i++) { Vertex vert = vertices[i]; pointList.Add(vert.position); if (vert.segmentCurves) { Vertex vertNext = vertices[NextIndex(i)]; float t = step; for (int j = 1; j < bezierSteps; j++) { pointList.Add(VectorShapeUtils.EvaluateCubicCurve(vert.position, vert.exitCP, vertNext.enterCP, vertNext.position, t)); t += step; } } } shapeBounds = VectorUtils.Bounds(pointList); boundsDirty = false; }
public void Bounds_ComputesBezierPathBounds() { var path = VectorUtils.MakeArc(Vector2.zero, 0.0f, Mathf.PI / 2, 1.0f); var bbox = VectorUtils.Bounds(path); Assert.AreEqual(0.0f, bbox.min.x, VectorUtils.Epsilon); Assert.AreEqual(0.0f, bbox.min.y, VectorUtils.Epsilon); Assert.AreEqual(1.0f, bbox.max.x, VectorUtils.Epsilon); Assert.AreEqual(1.0f, bbox.max.y, VectorUtils.Epsilon); }
public static Rect CalcBounds(string svg) { using (var reader = new StringReader(svg)) { var sceneInfo = SVGParser.ImportSVG(reader, ViewportOptions.DontPreserve); var tessOptions = SvgToPng.TessellationOptions; var geometry = VectorUtils.TessellateScene(sceneInfo.Scene, tessOptions, sceneInfo.NodeOpacity); var vertices = geometry.SelectMany(geom => geom.Vertices.Select(x => (geom.WorldTransform * x))).ToArray(); var bounds = VectorUtils.Bounds(vertices); return(bounds); } }
private static VectorShape TryParseShapeToCircle(Shape shape, Matrix2D transform) { if (shape.Contours.Length > 1) { return(null); } BezierContour contour = shape.Contours[0]; if (contour.Segments.Length < 5) { return(null); } if (!contour.Closed) { return(null); } BezierSegment[] segments = new BezierSegment[contour.Segments.Length - 1]; for (int i = 0; i < segments.Length; i++) { segments[i].P0 = transform.MultiplyPoint(contour.Segments[i].P0); segments[i].P1 = transform.MultiplyPoint(contour.Segments[i].P1); segments[i].P2 = transform.MultiplyPoint(contour.Segments[i].P2); segments[i].P3 = transform.MultiplyPoint(contour.Segments[(i + 1)].P0); } Rect shapeBounds = VectorUtils.Bounds(VectorUtils.BezierSegmentsToPath(segments)); Vector2 center = shapeBounds.center; float radius = (shapeBounds.width + shapeBounds.height) / 4f; float error = radius / 200f; for (int i = 0; i < segments.Length; i++) { if (Mathf.Abs(Vector2.Distance(center, segments[i].P0) - radius) > error) { return(null); } Vector2 midpoint = VectorUtils.Eval(segments[i], 0.5f); if (Mathf.Abs(Vector2.Distance(center, midpoint) - radius) > error) { return(null); } } CircleShape circle = new CircleShape(center, radius); circle.colorOutline = Color.red; return(circle); }
List <Vector2[]> ISpritePhysicsOutlineDataProvider.GetOutlines(GUID guid) { if (GetSVGSpriteData().PhysicsOutlines.Count == 0) { // If no physics outline was set in the Sprite Editor, show the sprite's physics shape directly (if any) var sprite = GetSprite(); if (sprite == null) { return(null); } var importer = GetImporter(); int width; int height; importer.TextureSizeForSpriteEditor(sprite, out width, out height); var size = new Vector2(width, height); var offset = new Vector2(-width / 2.0f, -height / 2.0f); var storedShapes = new List <Vector2[]>(sprite.GetPhysicsShapeCount()); var shape = new List <Vector2>(); for (int i = 0; i < sprite.GetPhysicsShapeCount(); ++i) { shape.Clear(); sprite.GetPhysicsShape(i, shape); var bounds = VectorUtils.Bounds(shape); for (int j = 0; j < shape.Count; ++j) { var p = shape[j]; p -= bounds.min; p /= bounds.size; p *= size; p += offset; shape[j] = p; } storedShapes.Add(shape.ToArray()); } return(storedShapes); } return(GetSVGSpriteData().PhysicsOutlines.Select(x => x.Vertices.ToArray()).ToList()); }
private static Sprite SpriteFromGeometry(List <VectorUtils.Geometry> geoms) { var vertices = new List <Vector2>(); var indices = new List <UInt16>(); var colors = new List <Color>(); foreach (var geom in geoms) { if (geom.Indices.Length == 0) { continue; } indices.AddRange(geom.Indices.Select(x => (UInt16)(x + vertices.Count))); vertices.AddRange(geom.Vertices.Select(x => geom.WorldTransform * x)); colors.AddRange(Enumerable.Repeat(geom.Color, geom.Vertices.Length)); } var bbox = VectorUtils.Bounds(vertices); VectorUtils.RealignVerticesInBounds(vertices, bbox, true); var rect = new Rect(0, 0, bbox.width, bbox.height); // The Sprite.Create(Rect, Vector2, float, Texture2D) method is internal. Using reflection // until it becomes public. var spriteCreateMethod = typeof(Sprite).GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(Rect), typeof(Vector2), typeof(float), typeof(Texture2D) }, null); var sprite = spriteCreateMethod.Invoke(null, new object[] { rect, Vector2.zero, 100.0f, null }) as Sprite; sprite.OverrideGeometry(vertices.ToArray(), indices.ToArray()); var colors32 = colors.Select(c => (Color32)c); using (var nativeColors = new NativeArray <Color32>(colors32.ToArray(), Allocator.Temp)) sprite.SetVertexAttribute <Color32>(VertexAttribute.Color, nativeColors); return(sprite); }
/// <summary> /// Build a 2D bounding box for the shape. /// </summary> protected override void GenerateBounds() { List <Vector2> pointList = new List <Vector2>(); float step = 1f / bezierSteps; for (int i = 0; i < vertices.Length; i++) { Vertex vert = vertices[i]; pointList.Add(vert.position); if (vert.segmentCurves) { Vertex vertNext = vertices[NextIndex(i)]; float t = step; for (int j = 1; j < bezierSteps; j++) { pointList.Add(EvaluateCubicCurve(vert.position, vert.exitCP, vertNext.enterCP, vertNext.position, t)); t += step; } } } shapeBounds = VectorUtils.Bounds(pointList); }
public Rect CalcSize(XdObjectJson xdObject) { var position = Vector2.zero; var size = new Vector2(xdObject.Shape.Width, xdObject.Shape.Height); var scaleBehavior = xdObject.Style?.Fill?.Pattern?.Meta?.Ux?.ScaleBehavior ?? "fill"; var spriteUid = xdObject.Style?.Fill?.Pattern?.Meta?.Ux?.Uid; var shapeType = xdObject.Shape?.Type; if (!string.IsNullOrWhiteSpace(spriteUid)) { // nothing } else if (SvgUtil.Types.Contains(shapeType)) { var svg = SvgUtil.CreateSvg(xdObject); using (var reader = new StringReader(svg)) { var sceneInfo = SVGParser.ImportSVG(reader, ViewportOptions.DontPreserve); var tessOptions = SvgToPng.TessellationOptions; var geometry = VectorUtils.TessellateScene(sceneInfo.Scene, tessOptions, sceneInfo.NodeOpacity); var vertices = geometry.SelectMany(geom => geom.Vertices.Select(x => (geom.WorldTransform * x))).ToArray(); var bounds = VectorUtils.Bounds(vertices); if (bounds.width > 0.0001f && bounds.height > 0.0001f) { size = new Vector2(bounds.width, bounds.height); position = new Vector2(bounds.x, bounds.y); } } } if (scaleBehavior == "cover" && size.x > 0.0001f && size.y > 0.0001f) { var imageWidth = xdObject.Style?.Fill?.Pattern?.Width ?? 0f; var imageHeight = xdObject.Style?.Fill?.Pattern?.Height ?? 0f; var imageSize = new Vector2(imageWidth, imageHeight); var imageAspect = imageSize.x / imageSize.y; var instanceAspect = size.x / size.y; var offsetX = xdObject.Style?.Fill?.Pattern?.Meta?.Ux?.OffsetX ?? 0f; var offsetY = xdObject.Style?.Fill?.Pattern?.Meta?.Ux?.OffsetY ?? 0f; var scale = xdObject.Style?.Fill?.Pattern?.Meta?.Ux?.Scale ?? 1.0f; if (imageAspect > instanceAspect) { var prev = size.x; size.x = size.y * (imageSize.x / imageSize.y); position.x -= (size.x - prev) / 2f; position.x += offsetX * xdObject.Shape.Width * imageAspect / instanceAspect; position.y += offsetY * xdObject.Shape.Height; } else { var prev = size.y; size.y = size.x * (imageSize.y / imageSize.x); position.y -= (size.y - prev) / 2f; position.x += offsetX * xdObject.Shape.Width; position.y += offsetY * xdObject.Shape.Height * imageAspect / instanceAspect; } { var prev = size; size *= scale; position -= (size - prev) / 2f; } } return(new Rect(position, size)); }