@youssef_aboualghar wrote:
Alright, so I’m trying to map boids on a surface to make a flocking behavior on a surface for my new plugin
(based on long Nguyen’s workshop)My approach was to convert positions to UV parameters by remapping x,y values of points in 2d to surface domain in U and V.
It doesn’t give the desired effect can anyone help me with this ?
thanks.
here is the codeusing System;
using System.Collections.Generic;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Types;
using Rhino.Geometry;namespace SurfaceTrails2.FlockingMapToSurface
{
public class GhcFlockingSimulation : GH_Component
{
private FlockSystem flockSystem;public GhcFlockingSimulation() : base( "Flocking Map To Surface", "FlockingMapToSurface", "Flocking Map To Surface", "YFAtools", "AgentBased") { } protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) { pManager.AddBooleanParameter("Reset", "Reset", "Reset", GH_ParamAccess.item, false); pManager.AddBooleanParameter("Play", "Play", "Play", GH_ParamAccess.item, false); pManager.AddBooleanParameter("3D", "3D", "3D", GH_ParamAccess.item, true); pManager.AddSurfaceParameter("srf", "srf", "srf", GH_ParamAccess.item); pManager.AddIntegerParameter("Count", "Count", "Number of Agents", GH_ParamAccess.item, 50); pManager.AddNumberParameter("Timestep", "Timestep", "Timestep", GH_ParamAccess.item, 0.02); pManager.AddNumberParameter("Neighbourhood Radius", "Neighbourhood Radius", "Neighbourhood Radius", GH_ParamAccess.item, 3.5); pManager.AddNumberParameter("Alignment", "Alignment", "Alignment", GH_ParamAccess.item, 0.5); pManager.AddNumberParameter("Cohesion", "Cohesion", "Cohesion", GH_ParamAccess.item, 0.5); pManager.AddNumberParameter("Separation", "Separation", "Separation", GH_ParamAccess.item, 0.5); pManager.AddNumberParameter("Separation Distance", "Separation Distance", "Separation Distance", GH_ParamAccess.item, 1.5); pManager.AddCircleParameter("Repellers", "Repellers", "Repellers", GH_ParamAccess.list); pManager[10].Optional = true; pManager.AddBooleanParameter("Use Parallel", "Use Parallel", "Use Parallel", GH_ParamAccess.item, false); pManager.AddBooleanParameter("Use R-Tree", "Use R-Tree", "Use R-Tree", GH_ParamAccess.item, false); } protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) { pManager.AddTextParameter("Info", "Info", "Information", GH_ParamAccess.item); pManager.AddPointParameter("Positions", "Positions", "The agent positions", GH_ParamAccess.list); pManager.AddVectorParameter("Velocities", "Velocities", "The agent veloctiies", GH_ParamAccess.list); } protected override void SolveInstance(IGH_DataAccess DA) { // =============================================================================================== // Read input parameters // =============================================================================================== bool iReset = true; bool iPlay = false; bool i3D = false; Surface baseSurface = null; int iCount = 0; double iTimestep = 0.0; double iNeighbourhoodRadius = 0.0; double iAlignment = 0.0; double iCohesion = 0.0; double iSeparation = 0.0; double iSeparationDistance = 0.0; List<Circle> iRepellers = new List<Circle>(); bool iUseParallel = false; bool iUseRTree = false; DA.GetData("Reset", ref iReset); DA.GetData("Play", ref iPlay); DA.GetData("3D", ref i3D); DA.GetData("srf", ref baseSurface); DA.GetData("Count", ref iCount); DA.GetData("Timestep", ref iTimestep); DA.GetData("Neighbourhood Radius", ref iNeighbourhoodRadius); DA.GetData("Alignment", ref iAlignment); DA.GetData("Cohesion", ref iCohesion); DA.GetData("Separation", ref iSeparation); DA.GetData("Separation Distance", ref iSeparationDistance); DA.GetDataList("Repellers", iRepellers); DA.GetData("Use Parallel", ref iUseParallel); DA.GetData("Use R-Tree", ref iUseRTree); // =============================================================================================== // Read input parameters // =============================================================================================== if (iReset || flockSystem == null) { flockSystem = new FlockSystem(iCount, i3D); } else { // =============================================================================================== // Assign the input parameters to the corresponding variables in the "flockSystem" object // =============================================================================================== flockSystem.Timestep = iTimestep; flockSystem.NeighbourhoodRadius = iNeighbourhoodRadius; flockSystem.AlignmentStrength = iAlignment; flockSystem.CohesionStrength = iCohesion; flockSystem.SeparationStrength = iSeparation; flockSystem.SeparationDistance = iSeparationDistance; flockSystem.Repellers = iRepellers; flockSystem.UseParallel = iUseParallel; // =============================================================================== // Update the flock // =============================================================================== if (iUseRTree) flockSystem.UpdateUsingRTree(); else flockSystem.Update(); if (iPlay) ExpireSolution(true); } // =============================================================================== // Output the agent positions and velocities so we can see them on display // =============================================================================== List<GH_Point> positions = new List<GH_Point>(); List<GH_Vector> velocities = new List<GH_Vector>(); List<GH_Point> surfacePositions = new List<GH_Point>(); var surface = baseSurface.ToNurbsSurface(); foreach (FlockAgent agent in flockSystem.Agents) { positions.Add(new GH_Point(agent.Position)); velocities.Add(new GH_Vector(agent.Velocity)); // =============================================================================== // Position on surface // =============================================================================== Interval u = new Interval(0, 1); Interval v = new Interval(0, 1); surface.SetDomain(0, u); surface.SetDomain(1, v); var remappedU = NumberOperations.remap(0,1,surface.Domain(0).T0,surface.Domain(0).T1,agent.Position.X); var remappedV = NumberOperations.remap(0,1,surface.Domain(1).T0,surface.Domain(1).T1,agent.Position.Y); surfacePositions.Add(new GH_Point(surface.PointAt(remappedU, remappedV)/*surface.PointAt(agent.Position.X, agent.Position.Y*/)); } DA.SetDataList("Positions", surfacePositions); DA.SetDataList("Velocities", velocities); } protected override System.Drawing.Bitmap Icon { get { return Properties.Resources._28_8_18_FlockSimulation; } } public override Guid ComponentGuid { get { return new Guid("7066d2ac-3c0a-47db-b22f-4d8c25bf8baa"); } } }
}
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Rhino.Geometry;namespace SurfaceTrails2.FlockingMapToSurface
{
public class FlockSystem
{
public List Agents;public double Timestep; public double NeighbourhoodRadius; public double AlignmentStrength; public double CohesionStrength; public double SeparationStrength; public double SeparationDistance; public List<Circle> Repellers; public bool UseParallel; public FlockSystem(int agentCount, bool is3D) { Agents = new List<FlockAgent>(); if (is3D) for (int i = 0; i < agentCount; i++) { FlockAgent agent = new FlockAgent( Util.GetRandomPoint(0.0, 30.0, 0.0, 30.0, 0.0, 30.0), Util.GetRandomUnitVector() * 4.0); agent.FlockSystem = this; Agents.Add(agent); } else for (int i = 0; i < agentCount; i++) { FlockAgent agent = new FlockAgent( Util.GetRandomPoint(0.0, 30.0, 0.0, 30.0, 0.0, 0.0), Util.GetRandomUnitVectorXY() * 4.0); agent.FlockSystem = this; Agents.Add(agent); } } private List<FlockAgent> FindNeighbours(FlockAgent agent) { List<FlockAgent> neighbours = new List<FlockAgent>(); foreach (FlockAgent neighbour in Agents) if (neighbour != agent && neighbour.Position.DistanceTo(agent.Position) < NeighbourhoodRadius) neighbours.Add(neighbour); return neighbours; } private void ComputeAgentDesiredVelocity(FlockAgent agent) { List<FlockAgent> neighbours = FindNeighbours(agent); agent.ComputeDesiredVelocity(neighbours); } public void Update() { if (UseParallel) Parallel.ForEach(Agents, ComputeAgentDesiredVelocity); else foreach (FlockAgent agent in Agents) ComputeAgentDesiredVelocity(agent); // Once the desired velocity for each agent has been computed, we update each position and velocity foreach (FlockAgent agent in Agents) agent.UpdateVelocityAndPosition(); } public void UpdateUsingRTree() { /* First, build the R-Tree */ RTree rTree = new RTree(); for (int i = 0; i < Agents.Count; i++) rTree.Insert(Agents[i].Position, i); /* Then, we use the R-Tree to find the neighbours and compute the desired velocity */ foreach (FlockAgent agent in Agents) { List<FlockAgent> neighbours = new List<FlockAgent>(); EventHandler<RTreeEventArgs> rTreeCallback = (object sender, RTreeEventArgs args) => { if (Agents[args.Id] != agent) neighbours.Add(Agents[args.Id]); }; rTree.Search(new Sphere(agent.Position, NeighbourhoodRadius), rTreeCallback); agent.ComputeDesiredVelocity(neighbours); } // Once the desired velocity for each agent has been computed, we can update each position and velocity foreach (FlockAgent agent in Agents) agent.UpdateVelocityAndPosition(); } }
}
using System.Collections.Generic;
using Rhino.Geometry;namespace SurfaceTrails2.FlockingMapToSurface
{
public class FlockAgent
{
public Point3d Position;
public Vector3d Velocity;public FlockSystem FlockSystem; private Vector3d desiredVelocity; private double boundingBoxSize = 1; public double BoundingBox { get { return boundingBoxSize;} set { boundingBoxSize=value; } } public FlockAgent(Point3d position, Vector3d velocity) { Position = position; Velocity = velocity; } public void UpdateVelocityAndPosition() { Velocity = 0.97 * Velocity + 0.03 * desiredVelocity; if (Velocity.Length > 8.0) Velocity *= 8.0 / Velocity.Length; else if (Velocity.Length < 4.0) Velocity *= 4.0 / Velocity.Length; Position += Velocity * FlockSystem.Timestep; } public void ComputeDesiredVelocity(List<FlockAgent> neighbours) { // First, reset the desired velocity to 0 desiredVelocity = new Vector3d(0.0, 0.0, 0.0); // =============================================================================== // Pull the agent back if it gets out of the bounding box // =============================================================================== if (Position.X < 0.0) desiredVelocity += new Vector3d(-Position.X, 0.0, 0.0); else if (Position.X > boundingBoxSize) desiredVelocity += new Vector3d(boundingBoxSize - Position.X, 0.0, 0.0); if (Position.Y < 0.0) desiredVelocity += new Vector3d(0.0, -Position.Y, 0.0); else if (Position.Y > boundingBoxSize) desiredVelocity += new Vector3d(0.0, boundingBoxSize - Position.Y, 0.0); if (Position.Z < 0.0) desiredVelocity += new Vector3d(0.0, 0.0, -Position.Z); else if (Position.Z > boundingBoxSize) desiredVelocity += new Vector3d(0.0, 0.0, boundingBoxSize - Position.Z); // =============================================================================== // If there are no neighbours nearby, the agent will maintain its veloctiy, // else it will perform the "alignment", "cohension" and "separation" behaviours // =============================================================================== if (neighbours.Count == 0) desiredVelocity += Velocity; // maintain the current velocity else { // ------------------------------------------------------------------------------- // "Alignment" behavior // ------------------------------------------------------------------------------- Vector3d alignment = Vector3d.Zero; foreach (FlockAgent neighbour in neighbours) alignment += neighbour.Velocity; // We divide by the number of neighbours to actually get their average velocity alignment /= neighbours.Count; desiredVelocity += FlockSystem.AlignmentStrength * alignment; // ------------------------------------------------------------------------------- // "Cohesion" behavior // ------------------------------------------------------------------------------- Point3d centre = Point3d.Origin; foreach (FlockAgent neighbour in neighbours) centre += neighbour.Position; // We divide by the number of neighbours to actually get their centre of mass centre /= neighbours.Count; Vector3d cohesion = centre - Position; desiredVelocity += FlockSystem.CohesionStrength * cohesion; // ------------------------------------------------------------------------------- // "Separation" behavior // ------------------------------------------------------------------------------- Vector3d separation = Vector3d.Zero; foreach (FlockAgent neighbour in neighbours) { double distanceToNeighbour = Position.DistanceTo(neighbour.Position); if (distanceToNeighbour < FlockSystem.SeparationDistance) { Vector3d getAway = Position - neighbour.Position; /* We scale the getAway vector by inverse of distanceToNeighbour to make the getAway vector bigger as the agent gets closer to its neighbour */ separation += getAway / (getAway.Length * distanceToNeighbour); } } desiredVelocity += FlockSystem.SeparationStrength * separation; } // =============================================================================== // Avoiding the obstacles (repellers) // =============================================================================== foreach (Circle repeller in FlockSystem.Repellers) { double distanceToRepeller = Position.DistanceTo(repeller.Center); Vector3d repulsion = Position - repeller.Center; // Repulstion gets stronger as the agent gets closer to the repeller repulsion /= (repulsion.Length * distanceToRepeller); // Repulsion strength is also proportional to the radius of the repeller circle/sphere // This allows the user to tweak the repulsion strength by tweaking the radius repulsion *= 30.0 * repeller.Radius; desiredVelocity += repulsion; } } }
}
Posts: 3
Participants: 2