private IEnumerable<PlacementPosition> GetPossibleNodePlacementsForCorner(Point corner, TextureAtlasNode node, List<TextureAtlasNode> placedNodes, CalculatorSettings settings) { var boundaryArea = settings.Size.ToRectangle(); var possiblePlacementRects = new[] { new Rectangle(corner.X, corner.Y, node.Size.Width, node.Size.Height), new Rectangle(corner.X, corner.Y, -node.Size.Width, node.Size.Height).Normalize(), new Rectangle(corner.X, corner.Y, -node.Size.Width, -node.Size.Height).Normalize(), new Rectangle(corner.X, corner.Y, node.Size.Width, -node.Size.Height).Normalize() }; var validPlacements = possiblePlacementRects .Where(r => r.IsEntirelyContainedBy(boundaryArea)).ToArray(); var xx = validPlacements.Where(r => !placedNodes.Any(n => n.GetBounds().IntersectsWith(r))).ToArray(); foreach(var rect in xx) { var result = new PlacementPosition(rect.X, rect.Y, false, rect.Width, rect.Height); yield return result; } // No point rotating a square! if (!settings.IsRotationEnabled || node.Size.Width == node.Size.Height) yield break; foreach (var rect in new[] { new Rectangle(corner.X, corner.Y, node.Size.Height, node.Size.Width), new Rectangle(corner.X, corner.Y, -node.Size.Height, node.Size.Width).Normalize(), new Rectangle(corner.X, corner.Y, -node.Size.Height, -node.Size.Width).Normalize(), new Rectangle(corner.X, corner.Y, node.Size.Height, -node.Size.Width).Normalize(), } .Where(r => r.IsEntirelyContainedBy(boundaryArea)) .Where(r => placedNodes.Any(n => n.GetBounds().IntersectsWith(r))) ) { var result = new PlacementPosition(rect.X, rect.Y, true, rect.Width, rect.Height); yield return result; } }
private PlacementScore Score(Point corner, PlacementPosition placement, List<TextureAtlasNode> placedNodes, Size outputTextureSize) { var result = new PlacementScore(); var edges = GetEdges(outputTextureSize, placedNodes).ToList(); var corners = GetCorners(outputTextureSize, placedNodes).ToList(); var sharedEdgeSum = placement .GetBounds() .GetEdges() .Sum(e => edges.Sum(placedEdge => e.GetOverlap(placedEdge))); var cornerDistance = placement .GetBounds() .GetCorners() .Sum(p => corners.Min(c => p.DistanceBetween(c))); result.UtilizationScore = sharedEdgeSum; result.WastageScore = placement.GetBounds().GetEdges().Sum(e=>e.Length) - sharedEdgeSum; result.CornerParity = cornerDistance; result.IsVaildPlacement = true; return result; }