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);
}
}
}