private void CheckMinPosition(int tileIndex, int vertexPosition) { var tolerance = 1.0f; if (SlurMath.ApproxEquals(_verts[vertexPosition].transform.position.y, _min, tolerance) && (tileIndex != 0)) { _verts[vertexPosition].Body.isKinematic = true; _tilesTouchingGround++; } //Debug.Log("Touching ground " + _tilesTouchingGround); }
private void LowestPosition() { _min = _verts.Min(v => v.transform.position.y); var tolerance = 1.0f; foreach (var v in _verts.Where(v => SlurMath.ApproxEquals(v.transform.position.y, _min, tolerance))) { _positionsAvailableToTouchGround++; } Debug.Log("lowest is " + _min); Debug.Log("Positions on the ground " + _positionsAvailableToTouchGround); }
/// <summary> /// Shifts a subset of a list of items in place. /// </summary> public static void Shift <T>(this IList <T> list, int offset, int from, int to) { if (list is T[] arr) { ArrayExtensions.Shift(arr, offset, from, to); return; } offset = SlurMath.RepeatPositive(-offset, to - from); Reverse(list, from, from + offset); Reverse(list, from + offset, to); Reverse(list, from, to); }
/// <summary> /// /// </summary> private void DisplayVNR2Density() { const string propName = "_Value"; CellLayer[] layers = _stack.Layers; //int layer0 = _currentLayer + 1; int layer0 = 0; int layer1 = _stack.Layers.Length; //apply material props to each obj renderer for (int k = layer0; k < layer1; k++) { Cell[,] cells = layers[k].Cells; int nrows = cells.GetLength(0); int ncols = cells.GetLength(1); for (int i = 0; i < nrows; i++) { for (int j = 0; j < ncols; j++) { Cell cell = cells[i, j]; // skip dead cells if (cell.State == 0) { continue; } // update cell material Renderer renderer = cell.Renderer; renderer.enabled = true; renderer.sharedMaterial = _densityMaterial; // set material properties renderer.GetPropertyBlock(_properties); // normalize density float density = GetNeighborDensity(cells, new Index2(i, j), Neighborhoods.VonNeumannR2); float value = SlurMath.Normalize(density, _densityDisplayMin, _densityDisplayMax); _properties.SetFloat(propName, value); cell.Renderer.SetPropertyBlock(_properties); } } } _currentLayer = layer1; }
/// <summary> /// /// </summary> private void DisplayFitness() { const string propName = "_Value"; var population = _population.Population; foreach (var stack in population) { // normalize fitness float value = SlurMath.Normalize(stack.Fitness, _population.MinFitness, _population.MaxFitness); if (stack.Fitness == _population.MaxFitness) { value = .999f; } if (stack.Fitness == _population.MinFitness) { value = .001f; } if (stack.gameObject.active == false) { continue; } foreach (var layer in stack.Layers) { foreach (var cell in layer.Cells) { // skip dead cells if (cell.State == 0) { continue; } // update cell material MeshRenderer renderer = cell.Renderer; renderer.sharedMaterial = _fitnessMaterial; // set material properties { renderer.GetPropertyBlock(_properties); _properties.SetFloat(propName, value); renderer.SetPropertyBlock(_properties); } } } } }
/// <inheritdoc /> protected sealed override double ValueAtLinearUnsafe(Vector2d point) { (var u, var v) = Vector2d.Fract(ToGridSpace(point), out Vector2i whole); var x0 = whole.X; var y0 = whole.Y * CountX; var x1 = x0 + 1; var y1 = y0 + CountX; var vals = Values; return(SlurMath.Lerp( SlurMath.Lerp(vals[x0 + y0], vals[x1 + y0], u), SlurMath.Lerp(vals[x0 + y1], vals[x1 + y1], u), v)); }
/// <inheritdoc /> protected sealed override double ValueAtLinear(Vector2d point) { (var u, var v) = Vector2d.Fract(ToGridSpace(point), out Vector2i whole); var x0 = WrapX(whole.X); var y0 = WrapY(whole.Y) * CountX; int x1 = WrapX(whole.X + 1); int y1 = WrapY(whole.Y + 1) * CountX; var vals = Values; return(SlurMath.Lerp( SlurMath.Lerp(vals[x0 + y0], vals[x1 + y0], u), SlurMath.Lerp(vals[x0 + y1], vals[x1 + y1], u), v)); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { Mesh mesh = null; List <Point3d> points = new List <Point3d>(); double iso = 0d; if (!DA.GetData(0, ref mesh)) { return; } if (!DA.GetDataList <Point3d>(1, points)) { return; } if (!DA.GetData(2, ref iso)) { return; } var hem = mesh.ToHeMesh(); var field = MeshField3d.Double.Create(hem); var vecs = points.Select(p => (SpatialSlur.Vector3d)p).ToList(); var kdTree = KdTree.CreateBalanced(vecs.Select(v => (v.XY).ToArray())); var nearest = hem.Vertices.Select(p => kdTree.NearestL2(new double[] { p.Position.X, p.Position.Y })).ToList(); List <double> val = new List <double>(); for (int i = 0; i < hem.Vertices.Count; i++) { double d = hem.Vertices[i].Position.DistanceTo(points[nearest[i]]); val.Add(d); } Interval interval = GetInterval(val); for (int i = 0; i < val.Count; i++) { val[i] = (SlurMath.Remap(val[i], interval.T0, interval.T1, -1, 1)) - iso; } field.Set(val); DA.SetData(0, Field3d.Create(v => field.ValueAt(v))); }
/// <inheritdoc /> protected sealed override double ValueAtLinearUnsafe(Vec2d point) { point = ToGridSpace(point); double u = SlurMath.Fract(point.X, out int i0); double v = SlurMath.Fract(point.Y, out int j0); j0 *= CountX; int i1 = i0 + 1; int j1 = j0 + CountX; var vals = Values; return(SlurMath.Lerp( SlurMath.Lerp(vals[i0 + j0], vals[i1 + j0], u), SlurMath.Lerp(vals[i0 + j1], vals[i1 + j1], u), v)); }
private void DisplayOldCells() { const string propName = "_Value"; CellLayer[] layers = _model.Stack.Layers; int layer0 = _currentLayer + 1; int layer1 = _model.CurrentLayer; for (int i = layer0; i <= layer1; i++) { foreach (var cell in layers[i].Cells) { // skip dead cells if (cell.State == 0) { continue; } // update cell material MeshRenderer renderer = cell.Renderer; if (cell.Age < 10) { renderer.enabled = false; } if (cell.Age >= 10) { renderer.enabled = true; } renderer.sharedMaterial = _ageMaterial; // set material properties { renderer.GetPropertyBlock(_properties); // normalize age float value = SlurMath.Normalize(cell.Age, _ageDisplayMin, _ageDisplayMax); _properties.SetFloat(propName, value); renderer.SetPropertyBlock(_properties); } } } _currentLayer = layer1; }
/// <summary> /// Calcuated as the exterior between adjacent faces. /// Result is in range [0 - 2Pi]. /// Assumes the given face normals are unitized. /// </summary>> public static double GetDihedralAngle <V, E, F>(this IHalfedge <V, E, F> hedge, Func <V, Vec3d> getPosition, Func <F, Vec3d> getNormal) where V : IHeVertex <V, E, F> where E : IHalfedge <V, E, F> where F : IHeFace <V, E, F> { Vec3d tangent = getPosition(hedge.End) - getPosition(hedge.Start); tangent.Unitize(); Vec3d x = getNormal(hedge.Face); Vec3d y = Vec3d.Cross(x, tangent); Vec3d d = getNormal(hedge.Twin.Face); double t = Math.Atan2(Vec3d.Dot(d, y), Vec3d.Dot(d, x)); t = (t < 0.0) ? t + SlurMath.TwoPI : t; // shift discontinuity to 0 return(SlurMath.Mod(t + Math.PI, SlurMath.TwoPI)); // add angle bw normals and faces }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { List <Mesh> mesh = new List <Mesh>(); IField3d <double> f0 = null; IField3d <double> f1 = null; List <double> t = new List <double>(); if (!DA.GetDataList(0, mesh)) { return; } if (!DA.GetData(1, ref f0)) { return; } if (!DA.GetData(2, ref f1)) { return; } if (!DA.GetDataList(3, t)) { return; } List <MeshField3d> fields = new List <MeshField3d>(); for (int i = 0; i < t.Count; i++) { List <double> currentBlend = new List <double>(); var currentField = MeshField3d.Double.Create(mesh[i].ToHeMesh()); foreach (Point3d p in mesh[i].Vertices) { double val = SlurMath.Lerp(f0.ValueAt(p), f1.ValueAt(p), t[i]); currentBlend.Add(val); currentField.Set(currentBlend); } fields.Add(currentField); } ; DA.SetDataList(0, fields); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { List <Mesh> mesh = new List <Mesh>(); IField3d <double> f0 = null; IField3d <double> f1 = null; List <double> t = new List <double>(); if (!DA.GetDataList(0, mesh)) { return; } if (!DA.GetData(1, ref f0)) { return; } if (!DA.GetData(2, ref f1)) { return; } if (!DA.GetDataList(3, t)) { return; } List <MeshField3d> fields = new List <MeshField3d>(); for (int i = 0; i < t.Count; i++) { var currentField = MeshField3d.Double.Create(mesh[i].ToHeMesh()); double[] currentBlend = new double[currentField.Mesh.Vertices.Count]; Parallel.For(0, currentField.Mesh.Vertices.Count, j => { currentBlend[j] = SlurMath.Lerp(f0.ValueAt(currentField.Mesh.Vertices[j].Position), f1.ValueAt(currentField.Mesh.Vertices[j].Position), t[i]); }); currentField.Set(currentBlend); fields.Add(currentField); } DA.SetDataList(0, fields); }
/// <inheritdoc /> protected sealed override double ValueAtLinear(Vec2d point) { point = ToGridSpace(point); double u = SlurMath.Fract(point.X, out int i0); double v = SlurMath.Fract(point.Y, out int j0); int i1 = WrapX(i0 + 1); int j1 = WrapY(j0 + 1) * CountX; i0 = WrapX(i0); j0 = WrapY(j0) * CountX; var vals = Values; return(SlurMath.Lerp( SlurMath.Lerp(vals[i0 + j0], vals[i1 + j0], u), SlurMath.Lerp(vals[i0 + j1], vals[i1 + j1], u), v)); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { Mesh mesh = null; Mesh inputMesh = null; double iso = 0d; if (!DA.GetData(0, ref mesh)) { return; } if (!DA.GetData(1, ref inputMesh)) { return; } if (!DA.GetData(2, ref iso)) { return; } var hem = mesh.ToHeMesh(); var field = MeshField3d.Double.Create(hem); List <double> val = new List <double>(); foreach (Point3d v in mesh.Vertices) { Point3d closestPt = inputMesh.ClosestPoint(v); double dist = v.DistanceTo(closestPt); val.Add(dist); } Interval interval = GetInterval(val); for (int i = 0; i < val.Count; i++) { val[i] = (SlurMath.Remap(val[i], interval.T0, interval.T1, -1, 1)) - iso; } field.Set(val); DA.SetData(0, Field3d.Create(v => field.ValueAt(v))); }
/// <summary> /// /// </summary> private IEnumerator DisplayColor() { while (true) { yield return(new WaitForSeconds(1f)); const string propName = "_Value"; CellLayer[] layers = _model.Stack.Layers; int layer0 = _currentLayer + 1; int layer1 = _model.CurrentLayer; for (int i = layer0; i <= layer1; i++) { foreach (var cell in layers[i].Cells) { // skip dead cells if (cell.State == 0) { continue; } // update cell material MeshRenderer renderer = cell.Renderer; renderer.sharedMaterial = _ageMaterial; // set material properties { renderer.GetPropertyBlock(_properties); // normalize age float value = SlurMath.Normalize(cell.Age, _ageDisplayMin, _ageDisplayMax); _properties.SetFloat(propName, value); renderer.SetPropertyBlock(_properties); } } } _currentLayer = layer1; yield return(new WaitForSeconds(0.1f)); } }
/// <summary> /// Returns a grid point at the given point. /// Assumes the point is within the bounds of the grid. /// </summary> /// <param name="point"></param> /// <param name="result"></param> public void GridPointAtUnsafe(Vec2d point, GridPoint2d result) { point = ToGridSpace(point); result.SetWeights( SlurMath.Fract(point.X, out int i0), SlurMath.Fract(point.Y, out int j0) ); j0 *= _nx; int i1 = i0 + 1; int j1 = j0 + _nx; var corners = result.Corners; corners[0] = i0 + j0; corners[1] = i1 + j0; corners[2] = i0 + j1; corners[3] = i1 + j1; }
private void AddKinematicToLowest() { _kinematicPercent = 0.0f; int roundN = 0; var minDistance = MinDistance(); var tolerance = 1.0f; foreach (var v in _verts) { v.Body.isKinematic = false; } foreach (var kinematic in _meshedTiles.Where (kinematic => SlurMath.ApproxEquals(kinematic.transform.position.y, minDistance, tolerance))) { kinematic.Body.isKinematic = true; _kinematicTiles++; } }
/// <summary> /// TODO move into SlurUnity /// </summary> /// <param name="colors"></param> /// <param name="factor"></param> /// <returns></returns> public static Color Lerp(IReadOnlyList <Color> colors, float factor) { int last = colors.Count - 1; int i; // object SlurMathf = null; factor = SlurMath.Fract(factor * last, out i); //Fract(factor * last, out i); if (i < 0) { return(colors[0]); } else if (i >= last) { return(colors[last]); } return(Color.LerpUnclamped(colors[i], colors[i + 1], factor)); }
private void AddKinematicToLowest() { var lowest = SmallestDistance(); var tolerance = 1.0f; foreach (var v in _meshedTiles) { if (v.transform.position.y == lowest) { v.Body.isKinematic = true; } } var meanKinematicPosition = _meshedTiles.Where(v => v.Body.isKinematic).Mean(v => v.transform.position); foreach (var v in _meshedTiles.Where(v => SlurMath.ApproxEquals(v.transform.position.y, lowest, tolerance))) { } }
/// <summary> /// Calcuated as the exterior between adjacent faces. /// Result is in range [0 - 2Pi]. /// Assumes the given face normals are unitized. /// </summary>> public static double GetDihedralAngle <V, E, F>(this IHalfedge <V, E, F> hedge, Func <V, Vec3d> getPosition, Func <F, Vec3d> getNormal) where V : IHeVertex <V, E, F> where E : IHalfedge <V, E, F> where F : IHeFace <V, E, F> { // TODO // refactor as per http://brickisland.net/DDGFall2017/2017/10/12/assignment-1-coding-investigating-curvature/ Vec3d tangent = getPosition(hedge.End) - getPosition(hedge.Start); tangent.Unitize(); Vec3d x = getNormal(hedge.Face); Vec3d y = Vec3d.Cross(x, tangent); Vec3d d = getNormal(hedge.Twin.Face); double t = Math.Atan2(Vec3d.Dot(d, y), Vec3d.Dot(d, x)); t = (t < 0.0) ? t + SlurMath.TwoPI : t; // shift discontinuity to 0 return(SlurMath.Mod(t + Math.PI, SlurMath.TwoPI)); // add angle bw normals and faces }
/// <summary> /// Returns the noise value at the given coordinates /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="z"></param> /// <returns></returns> public static double ValueAt(double x, double y, double z) { // separate whole and fractional components x = SlurMath.Fract(x, out int i); y = SlurMath.Fract(y, out int j); z = SlurMath.Fract(z, out int k); // wrap to perm table i &= 255; j &= 255; k &= 255; // calculate noise contributions from each corner double n000 = GradDot(ToIndex(i, j, k), x, y, z); double n100 = GradDot(ToIndex(i + 1, j, k), x - 1.0, y, z); double n010 = GradDot(ToIndex(i, j + 1, k), x, y - 1.0, z); double n110 = GradDot(ToIndex(i + 1, j + 1, k), x - 1.0, y - 1.0, z); double n001 = GradDot(ToIndex(i, j, k + 1), x, y, z - 1.0); double n101 = GradDot(ToIndex(i + 1, j, k + 1), x - 1.0, y, z - 1.0); double n011 = GradDot(ToIndex(i, j + 1, k + 1), x, y - 1.0, z - 1.0); double n111 = GradDot(ToIndex(i + 1, j + 1, k + 1), x - 1.0, y - 1.0, z - 1.0); // eased values for each dimension x = SlurMath.HermiteC2(x); y = SlurMath.HermiteC2(y); z = SlurMath.HermiteC2(z); // trilinear interpolation return(SlurMath.Lerp( SlurMath.Lerp( SlurMath.Lerp(n000, n100, x), SlurMath.Lerp(n010, n110, x), y), SlurMath.Lerp( SlurMath.Lerp(n001, n101, x), SlurMath.Lerp(n011, n111, x), y), z)); }
/// <summary> /// Returns the noise value at the given coordinates. /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public static double ValueAt(double x, double y) { // separate whole and fractional components x = SlurMath.Fract(x, out int i); y = SlurMath.Fract(y, out int j); // calculate noise contributions from each corner double n00 = GradDot(ToIndex(i, j), x, y); double n10 = GradDot(ToIndex(i + 1, j), x - 1.0, y); double n01 = GradDot(ToIndex(i, j + 1), x, y - 1.0); double n11 = GradDot(ToIndex(i + 1, j + 1), x - 1.0, y - 1.0); // eased values for x and y x = SlurMath.HermiteC2(x); y = SlurMath.HermiteC2(y); // bilinear interpolation return(SlurMath.Lerp( SlurMath.Lerp(n00, n10, x), SlurMath.Lerp(n01, n11, x), y)); }
/// <summary> /// Returns a grid point at the given point. /// </summary> /// <param name="point"></param> /// <param name="result"></param> public void GridPointAt(Vec2d point, GridPoint2d result) { point = ToGridSpace(point); result.SetWeights( SlurMath.Fract(point.X, out int i0), SlurMath.Fract(point.Y, out int j0) ); int i1 = WrapX(i0 + 1); int j1 = WrapY(j0 + 1) * _nx; i0 = WrapX(i0); j0 = WrapY(j0) * _nx; var corners = result.Corners; corners[0] = i0 + j0; corners[1] = i1 + j0; corners[2] = i0 + j1; corners[3] = i1 + j1; }
/// <summary> /// /// </summary> private void DisplayLayerDensity() { const string propName = "_Value"; CellLayer[] layers = _stack.Layers; //int layer0 = _currentLayer + 1; int layer0 = 0; int layer1 = _stack.Layers.Length; for (int i = layer0; i < layer1; i++) { CellLayer layer = layers[i]; float value = SlurMath.Normalize(layer.Density, _densityDisplayMin, _densityDisplayMax); foreach (var cell in layer.Cells) { // skip dead cells if (cell.State == 0) { continue; } // update cell material Renderer renderer = cell.Renderer; renderer.enabled = true; renderer.sharedMaterial = _densityMaterial; // set material properties renderer.GetPropertyBlock(_properties); _properties.SetFloat(propName, value); renderer.SetPropertyBlock(_properties); } } _currentLayer = layer1; }
private bool AreaAnalyzer() { return(SlurMath.ApproxEquals(AreaDeviation(), _neededArea, _areaTolerance)); }
/// <summary> /// Calculates L1 (Manhattan) geodesic distance via Dijksta's algorithm as detailed in /// http://www.numerical-tours.com/matlab/fastmarching_0_implementing/ /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="result"></param> public static void GeodesicDistanceL1(GridField2d <double> cost, IEnumerable <int> sources, double[] result) { // TODO handle wrap modes var costVals = cost.Values; int nx = cost.CountX; int ny = cost.CountY; (double dx, double dy) = Vec2d.Abs(cost.Scale).Components; var pq = new PriorityQueue <(double, int)>((a, b) => a.Item1.CompareTo(b.Item1)); result.SetRange(double.PositiveInfinity, 0, cost.Count); // enqueue sources foreach (int index in sources) { result[index] = 0.0; pq.Insert((0.0, index)); } // breadth first search from sources while (pq.Count > 0) { (double dist0, int index0) = pq.RemoveMin(); if (dist0 > result[index0]) { continue; // skip if node has already been processed } (int i0, int j0) = cost.IndicesAt(index0); // x neighbours for (int i = -1; i < 2; i += 2) { if (!SlurMath.Contains(i0 + i, nx)) { continue; } int index1 = index0 + i; double dist1 = dist0 + costVals[index1] * dx; if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert((dist1, index1)); } } // y neigbours for (int j = -1; j < 2; j += 2) { if (!SlurMath.Contains(j0 + j, ny)) { continue; } int index1 = index0 + j * nx; double dist1 = dist0 + costVals[index1] * dy; if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert((dist1, index1)); } } } }
/// <summary> /// /// </summary> /// <param name="weight"></param> /// <returns></returns> public float ToScale(float weight) { var t = SlurMath.Saturate(SlurMath.Normalize(weight, _weight0, _weight1)); return(SlurMath.Lerp(_scale0, _scale1, t)); }
/// <summary> /// /// </summary> /// <param name="cost"></param> /// <param name="sources"></param> /// <param name="tags"></param> /// <param name="result"></param> private static void GeodesicDistanceL2Impl(GridField2d <double> cost, IEnumerable <int> sources, bool[] tags, double[] result) { // TODO handle wrap modes var costVals = cost.Values; var nx = cost.CountX; var ny = cost.CountY; (var dx, var dy) = Vec2d.Abs(cost.Scale).Components; var pq = new PriorityQueue <(double, int)>((a, b) => a.Item1.CompareTo(b.Item1)); var eikonal = new Eikonal2d(dx, dy); result.SetRange(double.PositiveInfinity, 0, cost.Count); // enqueue sources foreach (int index in sources) { result[index] = 0.0; pq.Insert((0.0, index)); } // breadth first search from sources while (pq.Count > 0) { (double dist0, int index0) = pq.RemoveMin(); if (tags[index0]) { continue; // skip if already accepted } tags[index0] = true; (int i0, int j0) = cost.IndicesAt(index0); // x neigbours for (int i = -1; i < 2; i += 2) { if (!SlurMath.Contains(i0 + i, nx)) { continue; // skip if out of bounds } int index1 = index0 + i; if (!tags[index1]) { double minAdj = (j0 == 0) ? result[index1 + nx] : (j0 == ny - 1) ? result[index1 - nx] : Math.Min(result[index1 - nx], result[index1 + nx]); double dist1 = (minAdj > double.MaxValue) ? dist0 + dx * costVals[index1] : eikonal.Evaluate(dist0, minAdj, costVals[index1]); if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert((dist1, index1)); } } } // y neigbours for (int j = -1; j < 2; j += 2) { if (!SlurMath.Contains(j0 + j, ny)) { continue; // skip if out of bounds } int index1 = index0 + j * nx; if (!tags[index1]) { double minAdj = (i0 == 0) ? result[index1 + 1] : (i0 == nx - 1) ? result[index1 - 1] : Math.Min(result[index1 - 1], result[index1 + 1]); double dist1 = (minAdj > double.MaxValue) ? dist0 + dy * costVals[index1] : eikonal.Evaluate(minAdj, dist0, costVals[index1]); if (dist1 < result[index1]) { result[index1] = dist1; pq.Insert((dist1, index1)); } } } } }
/// <summary> /// Returns a linearly interpolated value at the given parameter along the halfedge. /// </summary> public static double Lerp <V, E>(this IHalfedge <V, E> hedge, Func <V, double> getValue, double t) where V : IHeVertex <V, E> where E : IHalfedge <V, E> { return(SlurMath.Lerp(getValue(hedge.Start), getValue(hedge.End), t)); }