using ProceduralToolkit.FastNoiseLib; using System; using System.Collections.Generic; using UnityEngine; namespace ProceduralToolkit { /// /// Various useful methods and constants /// public static class PTUtils { /// /// Lowercase letters from a to z /// public const string LowercaseLetters = "abcdefghijklmnopqrstuvwxyz"; /// /// Uppercase letters from A to Z /// public const string UppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /// /// Digits from 0 to 9 /// public const string Digits = "0123456789"; /// /// The concatenation of the strings and /// public const string Letters = LowercaseLetters + UppercaseLetters; /// /// The concatenation of the strings and /// public const string Alphanumerics = Letters + Digits; /// /// Square root of 0.5 /// public const float Sqrt05 = 0.7071067811865475244f; /// /// Square root of 2 /// public const float Sqrt2 = 1.4142135623730950488f; /// /// Square root of 5 /// public const float Sqrt5 = 2.2360679774997896964f; /// /// Golden angle in radians /// public const float GoldenAngle = Mathf.PI*(3 - Sqrt5); /// /// Swaps values of and /// public static void Swap(ref T left, ref T right) { T temp = left; left = right; right = temp; } /// /// Knapsack problem solver for items with equal value /// /// Item identificator /// Set of items where key is item identificator and value is item weight /// Maximum weight /// Pre-filled knapsack /// Set to true if you want to fill the remaining free space with the smallest item /// /// Filled knapsack where values are number of items of type key. /// /// https://en.wikipedia.org/wiki/Knapsack_problem /// public static Dictionary Knapsack(Dictionary set, float capacity, Dictionary knapsack = null, bool overloadKnapsack = false) { var keys = new List(set.Keys); // Sort keys by their weights in descending order keys.Sort((a, b) => -set[a].CompareTo(set[b])); if (knapsack == null) { knapsack = new Dictionary(); foreach (var key in keys) { knapsack[key] = 0; } } return Knapsack(set, keys, capacity, knapsack, 0, overloadKnapsack); } private static Dictionary Knapsack(Dictionary set, List keys, float remainder, Dictionary knapsack, int startIndex, bool overloadKnapsack) { T smallestKey = keys[keys.Count - 1]; if (remainder < set[smallestKey]) { if (overloadKnapsack) { knapsack[smallestKey] = 1; } return knapsack; } // Cycle through items and try to put them in knapsack for (var i = startIndex; i < keys.Count; i++) { T key = keys[i]; float weight = set[key]; // Larger items won't fit, smaller items will fill as much space as they can knapsack[key] += (int) (remainder/weight); remainder %= weight; } if (remainder > 0) { if (overloadKnapsack) { knapsack[smallestKey] += 1; remainder -= set[smallestKey]; } // Fix for https://github.com/Syomus/ProceduralToolkit/issues/72 var repackedCopy = new Dictionary(knapsack); // Throw out largest item and try again for (var i = 0; i < keys.Count; i++) { T key = keys[i]; if (repackedCopy[key] != 0) { // Already tried every combination, return as is if (key.Equals(smallestKey)) { return repackedCopy; } repackedCopy[key]--; remainder += set[key]; startIndex = i + 1; break; } } repackedCopy = Knapsack(set, keys, remainder, repackedCopy, startIndex, overloadKnapsack); if (TotalWeight(set, repackedCopy) > TotalWeight(set, knapsack)) { knapsack = repackedCopy; } } return knapsack; } private static float TotalWeight(Dictionary set, Dictionary knapsack) { float weight = 0; foreach(var item in knapsack) { weight += set[item.Key] * item.Value; } return weight; } public static string ToString(this Vector3 vector, string format, IFormatProvider formatProvider) { return string.Format("({0}, {1}, {2})", vector.x.ToString(format, formatProvider), vector.y.ToString(format, formatProvider), vector.z.ToString(format, formatProvider)); } public static string ToString(this Quaternion quaternion, string format, IFormatProvider formatProvider) { return string.Format("({0}, {1}, {2}, {3})", quaternion.x.ToString(format, formatProvider), quaternion.y.ToString(format, formatProvider), quaternion.z.ToString(format, formatProvider), quaternion.w.ToString(format, formatProvider)); } public static void ApplyProperties(this Renderer renderer, RendererProperties properties) { renderer.lightProbeUsage = properties.lightProbeUsage; renderer.lightProbeProxyVolumeOverride = properties.lightProbeProxyVolumeOverride; renderer.reflectionProbeUsage = properties.reflectionProbeUsage; renderer.probeAnchor = properties.probeAnchor; renderer.shadowCastingMode = properties.shadowCastingMode; renderer.receiveShadows = properties.receiveShadows; renderer.motionVectorGenerationMode = properties.motionVectorGenerationMode; } public static MeshRenderer CreateMeshRenderer(string name, out MeshFilter meshFilter) { var gameObject = new GameObject(name); meshFilter = gameObject.AddComponent(); var meshRenderer = gameObject.AddComponent(); return meshRenderer; } public static Texture2D CreateTexture(int width, int height, Color clearColor) { var texture = new Texture2D(width, height, TextureFormat.ARGB32, false, true) { filterMode = FilterMode.Point }; texture.Clear(clearColor); texture.Apply(); return texture; } /// /// Returns a noise value between 0.0 and 1.0 /// public static float GetNoise01(this FastNoise noise, float x, float y) { return Mathf.Clamp01(noise.GetNoise(x, y)*0.5f + 0.5f); } } }