protected override void SolveInstance(IGH_DataAccess DA) { //CONTINUE HERE!!!! UpdateTask = new Task <int>(() => Update()); FlexParams param = new FlexParams(); FlexCollisionGeometry geom = new FlexCollisionGeometry(); List <FlexForceField> forceFields = new List <FlexForceField>(); List <FlexScene> scenes = new List <FlexScene>(); List <ConstraintSystem> constraints = new List <ConstraintSystem>(); FlexSolverOptions options = new FlexSolverOptions(); bool reset = false; bool go = false; DA.GetData(6, ref reset); DA.GetData(7, ref go); if (reset) { //reset everything related to time tracking counter = 0; totalTimeMs = 0; totalUpdateTimeMs = 0; sw.Stop(); sw.Reset(); outInfo = new List <string>(); //retrieve relevant data DA.GetData(0, ref param); DA.GetData(1, ref geom); DA.GetDataList(2, forceFields); DA.GetDataList(3, scenes); DA.GetDataList(4, constraints); DA.GetData(5, ref options); sceneTimeStamps = new List <int>(); forceFieldTimeStamps = new List <int>(); //destroy old Flex instance if (flex != null) { flex.Destroy(); } //Create new instance and assign everything flex = new Flex(); flex.SetParams(param); flex.SetCollisionGeometry(geom); flex.SetForceFields(forceFields); foreach (FlexForceField f in forceFields) { forceFieldTimeStamps.Add(f.TimeStamp); } FlexScene scene = new FlexScene(); foreach (FlexScene s in scenes) { scene.AppendScene(s); sceneTimeStamps.Add(s.TimeStamp); } foreach (ConstraintSystem c in constraints) { scene.RegisterCustomConstraints(c.AnchorIndices, c.ShapeMatchingIndices, c.ShapeStiffness, c.SpringPairIndices, c.SpringStiffnesses, c.SpringTargetLengths, c.TriangleIndices, c.TriangleNormals); constraintTimeStamps.Add(c.TimeStamp); } flex.SetScene(scene); flex.SetSolverOptions(options); } else if (go && flex != null && flex.IsReady()) { DA.GetData(5, ref options); if (options.TimeStamp != optionsTimeStamp) { flex.SetSolverOptions(options); } if (options.SceneMode == 0 || options.SceneMode == 1) { //update params if timestamp expired DA.GetData(0, ref param); if (param.TimeStamp != paramsTimeStamp) { flex.SetParams(param); paramsTimeStamp = param.TimeStamp; } //update geom if timestamp expired if (DA.GetData(1, ref geom)) { if (geom.TimeStamp != geomTimeStamp) { flex.SetCollisionGeometry(geom); geomTimeStamp = geom.TimeStamp; } } else if (geom != null) { flex.SetCollisionGeometry(new FlexCollisionGeometry()); } //update forcefields where timestamp expired DA.GetDataList(2, forceFields); bool needsUpdate = false; for (int i = forceFieldTimeStamps.Count; i < forceFields.Count; i++) { forceFieldTimeStamps.Add(forceFields[i].TimeStamp); needsUpdate = true; } for (int i = 0; i < forceFields.Count; i++) { if (forceFields[i].TimeStamp != forceFieldTimeStamps[i]) { needsUpdate = true; forceFieldTimeStamps[i] = forceFields[i].TimeStamp; } } if (needsUpdate) { flex.SetForceFields(forceFields); } //update scenes where timestamp expired DA.GetDataList(3, scenes); for (int i = sceneTimeStamps.Count; i < scenes.Count; i++) { sceneTimeStamps.Add(scenes[i].TimeStamp); } for (int i = 0; i < scenes.Count; i++) { if (scenes[i].TimeStamp != sceneTimeStamps[i]) { if (options.SceneMode == 0) { flex.SetScene(flex.Scene.AlterScene(scenes[i], false)); } else { flex.SetScene(flex.Scene.AppendScene(scenes[i])); } sceneTimeStamps[i] = scenes[i].TimeStamp; } } DA.GetDataList(4, constraints); for (int i = constraintTimeStamps.Count; i < constraints.Count; i++) { constraintTimeStamps.Add(constraints[i].TimeStamp); } for (int i = 0; i < constraints.Count; i++) { ConstraintSystem c = constraints[i]; if (c.TimeStamp != constraintTimeStamps[i]) { if (!flex.Scene.RegisterCustomConstraints(c.AnchorIndices, c.ShapeMatchingIndices, c.ShapeStiffness, c.SpringPairIndices, c.SpringStiffnesses, c.SpringTargetLengths, c.TriangleIndices, c.TriangleNormals)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Custom constraint indices exceeded particle count. No constraints applied!"); } flex.SetScene(flex.Scene); constraintTimeStamps[i] = constraints[i].TimeStamp; } } } //Add timing info outInfo = new List <string>(); counter++; outInfo.Add(counter.ToString()); long currentTickTimeMs = sw.ElapsedMilliseconds; sw.Restart(); totalTimeMs += currentTickTimeMs; outInfo.Add(totalTimeMs.ToString()); outInfo.Add(currentTickTimeMs.ToString()); float avTotalTickTime = ((float)totalTimeMs / (float)counter); outInfo.Add(avTotalTickTime.ToString()); //start update UpdateTask.Start(); //Add solver timing info int tickTimeSolver = UpdateTask.Result; totalUpdateTimeMs += tickTimeSolver; float ratUpdateTime = ((float)totalUpdateTimeMs / (float)counter); outInfo.Add(tickTimeSolver.ToString()); outInfo.Add(ratUpdateTime.ToString()); } if (go && options.FixedTotalIterations < 1) { ExpireSolution(true); } else if (flex != null && UpdateTask.Status == TaskStatus.Running) { UpdateTask.Dispose(); } if (flex != null) { DA.SetData(0, flex); } DA.SetDataList(1, outInfo); }
/// <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 <Plane> planes = new List <Plane>(); List <Surface> spheres = new List <Surface>(); List <Box> boxes = new List <Box>(); List <Mesh> meshes = new List <Mesh>(); List <Mesh> cmeshes = new List <Mesh>(); FlexCollisionGeometry geom = new FlexCollisionGeometry(); DA.GetDataList(0, planes); DA.GetDataList(1, spheres); DA.GetDataList(2, boxes); DA.GetDataList(3, meshes); DA.GetDataList(4, cmeshes); foreach (Plane p in planes) { double[] pe = p.GetPlaneEquation(); geom.AddPlane((float)pe[0], (float)pe[1], (float)pe[2], (float)pe[3]); } foreach (Surface s in spheres) { Sphere sph; if (!s.TryGetSphere(out sph)) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "At least one sphere is not a sphere"); } else { geom.AddSphere(new float[] { (float)sph.Center.X, (float)sph.Center.Y, (float)sph.Center.Z }, (float)sph.Radius); } } foreach (Box b in boxes) { if (!b.IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid box!"); } else { Plane p = Plane.WorldXY; p.Origin = b.Center; Quaternion q = Quaternion.Rotation(Plane.WorldXY, b.Plane); geom.AddBox(new float[] { (float)(b.X.Length * 0.5), (float)(b.Y.Length * 0.5), (float)(b.Z.Length * 0.5) }, new float[] { (float)b.Center.X, (float)b.Center.Y, (float)b.Center.Z }, new float[] { (float)q.Vector.X, (float)q.Vector.Y, (float)q.Vector.Z, (float)q.Scalar }); } } foreach (Mesh m in meshes) { if (!m.IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid mesh!"); } else { //Flex wants face normals to be pointing inward m.Flip(false, false, true); float[] vertices = new float[m.Vertices.Count * 3]; int[] faces = new int[m.Faces.Count * 3]; for (int i = 0; i < vertices.Length / 3; i++) { vertices[i * 3] = m.Vertices[i].X; vertices[i * 3 + 1] = m.Vertices[i].Y; vertices[i * 3 + 2] = m.Vertices[i].Z; } for (int i = 0; i < faces.Length / 3; i++) { faces[i * 3] = m.Faces[i].A; faces[i * 3 + 1] = m.Faces[i].B; faces[i * 3 + 2] = m.Faces[i].C; } //add mesh geom.AddMesh(vertices, faces); if (!m.IsClosed) { Mesh mm = m.DuplicateMesh(); mm.Flip(true, true, true); vertices = new float[mm.Vertices.Count * 3]; faces = new int[mm.Faces.Count * 3]; for (int i = 0; i < vertices.Length / 3; i++) { vertices[i * 3] = mm.Vertices[i].X; vertices[i * 3 + 1] = mm.Vertices[i].Y; vertices[i * 3 + 2] = mm.Vertices[i].Z; } for (int i = 0; i < faces.Length / 3; i++) { faces[i * 3] = mm.Faces[i].A; faces[i * 3 + 1] = mm.Faces[i].B; faces[i * 3 + 2] = mm.Faces[i].C; } //add mesh geom.AddMesh(vertices, faces); } } } foreach (Mesh m in cmeshes) { if (!m.IsClosed || !m.IsValid) { AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid mesh!"); } else { int planeCount = m.Faces.Count; m.FaceNormals.ComputeFaceNormals(); float[] cPlanes = new float[planeCount * 4]; float[] upperLimit = new float[3] { (float)m.Vertices[0].X, (float)m.Vertices[0].Y, (float)m.Vertices[0].Z }; float[] lowerLimit = new float[3] { (float)m.Vertices[0].X, (float)m.Vertices[0].Y, (float)m.Vertices[0].Z }; foreach (Point3d v in m.Vertices) { if (v.X > upperLimit[0]) { upperLimit[0] = (float)v.X; } if (v.Y > upperLimit[1]) { upperLimit[1] = (float)v.Y; } if (v.Z > upperLimit[2]) { upperLimit[2] = (float)v.Z; } if (v.X < lowerLimit[0]) { lowerLimit[0] = (float)v.X; } if (v.Y < lowerLimit[1]) { lowerLimit[1] = (float)v.Y; } if (v.Z < lowerLimit[2]) { lowerLimit[2] = (float)v.Z; } } for (int i = 0; i < planeCount; i++) { Point3d faceCenter = new Point3d((m.Vertices[m.Faces[i].A].X + m.Vertices[m.Faces[i].B].X + m.Vertices[m.Faces[i].C].X) / 3.0, (m.Vertices[m.Faces[i].A].Y + m.Vertices[m.Faces[i].B].Y + m.Vertices[m.Faces[i].C].Y) / 3.0, (m.Vertices[m.Faces[i].A].Z + m.Vertices[m.Faces[i].B].Z + m.Vertices[m.Faces[i].C].Z) / 3.0); Plane p = new Plane(faceCenter, m.FaceNormals[i] * -1); double[] ABCD = p.GetPlaneEquation(); cPlanes[i * 4] = (float)ABCD[0]; cPlanes[i * 4 + 1] = (float)ABCD[1]; cPlanes[i * 4 + 2] = (float)ABCD[2]; cPlanes[i * 4 + 3] = (float)ABCD[3]; } //add convex mesh geom.AddConvexShape(cPlanes, upperLimit, lowerLimit); } } DA.SetData(0, geom); }