protected IPlantCell MoveUpOrDown(IFluidCarrier <TFluid> carrier, IPlantPart part)
        {
            var cells = part.Cells;

            var currentTop = carrier.Current.Geometry.TopCenter.Y;

            var destTop = carrier.Destination.Geometry.BottomCenter.Y;

            IPlantCell next;

            if (IsWithinHeight(carrier.Current.Geometry, carrier.Destination.Geometry))
            {
                next = MoveTowardsDestination(carrier, cells);
            }
            else if (currentTop >= destTop)
            {
                next = FindUpOrDown(false, carrier.Current, part);
            }
            else
            {
                next = FindUpOrDown(true, carrier.Current, part);
            }

            return(next);
        }
        private IPlantPart FindTopInternode(out int leafCount)
        {
            int count = 0;

            IPlantPart upperInternode = null;

            Stack <IPlantPart> parts = new Stack <IPlantPart>(new[] { plant.ShootSystem.Stem.Internode });

            while (parts.Count > 0)
            {
                var part = parts.Pop();

                foreach (var conn in part.Connections)
                {
                    parts.Push(conn);
                }

                if (part.PartType == PlantPartType.Petiole)
                {
                    count++;
                }

                if (part.PartType == PlantPartType.Internode && !((Internode)part).HasUpperNode())
                {
                    upperInternode = part;
                }
            }

            leafCount = count > 0 ? count : 1;

            return(upperInternode);
        }
        private IPlantCell FindInConnection(bool up, IPlantCell cell, IPlantPart part)
        {
            foreach (var conn in part.Connections)
            {
                FindUpOrDown(up, cell, conn);
            }

            return(null);
        }
 private void HandlePlantPart(IPlantPart plantPart, bool isShoot)
 {
     if (isShoot)
     {
         HandleShootPart(plantPart);
     }
     else
     {
         HandleRootPart(plantPart);
     }
 }
        public void Develop(IPlantPart plantPart, SimulationStateSnapshot snapshot)
        {
            switch (plantPart)
            {
            case Internode internode:
                internodeDevelopment.Develop(internode, snapshot);
                break;

            case Root root:
                rootDevelopment.Develop(root, snapshot);
                break;
            }
        }
示例#6
0
        public IPlantCell[] Divide(IPlantCell cell, IPlantPart plantPart)
        {
            ICellGeometry geo = cell.Geometry;

            Vector3 halfPoint = GetCellHalfWay(geo);

            ICellGeometry topCellGeometry    = new CellGeometry(geo.TopCenter, halfPoint, geo.Face);
            ICellGeometry bottomCellGeometry = new CellGeometry(halfPoint, geo.BottomCenter, geo.Face);

            IPlantCell[] cells = new IPlantCell[2];

            cells[0] = CreatePlantCell(cell.CellType, topCellGeometry, cell.Vacuole, cell.CellWall);
            cells[1] = CreatePlantCell(cell.CellType, bottomCellGeometry, cell.Vacuole, cell.CellWall);

            return(cells);
        }
示例#7
0
        public void Solve(IPlantPart part)
        {
            var cells = part.Cells.ToArray();

            do
            {
                DoubleIterateCells(cells, (a, b) =>
                {
                    if (a.Equals(b) || !collisionDetection.Colliding(a, b, false))
                    {
                        return;
                    }

                    SolveCell(a, b);
                });
            } while (DoesAnyCollide(cells));
        }
        private void IteratePlantParts(IPlantPart start, bool isShoot)
        {
            var postponedParts = new Stack <IPlantPart>(new[] { start });

            while (postponedParts.Count > 0)
            {
                IPlantPart part = postponedParts.Pop();

                PushConnections(part.Connections, postponedParts);

                sucroseTransporter.Transport(part);

                HandlePlantPart(part, isShoot);

                cellBodySystem.Solve(part);
            }
        }
示例#9
0
        private int GetThickness(IPlantPart part)
        {
            switch (part.PartType)
            {
            case PlantPartType.Stem when part.BranchCount > 0:
                return(7);

            case PlantPartType.Petiole:
                return(5);

            case PlantPartType.Root:
                return(7);

            default:
                return(10);
            }
        }
示例#10
0
        private PlantNodeModelState CreateStateFromPlantPart(IPlantPart part)
        {
            var asTop      = part.PartType == PlantPartType.Root;
            var descriptor = descriptorService.Describe(part, asTop);

            var top3 = descriptor.Top;
            var bot3 = descriptor.Bottom;

            var top = new Vector2(top3.X, top3.Y);
            var bot = new Vector2(bot3.X, bot3.Y);

            return(new PlantNodeModelState
            {
                Thickness = ComputeThickness(descriptor),
                Description = $"{part.PartType} ({part.BranchCount})",
                Connections = new PlantNodeModelState[0],
                Coordinates = new[] { bot, top }
            });
        }
        public override void Transport(IPlantPart part)
        {
            if (!part.Cells.Any())
            {
                return;
            }

            var inTransit = CarrierCollection.GetInTransit();

            foreach (var transit in inTransit)
            {
                if (MoveCarrier(transit, part))
                {
                    Logger.LogDebug("{Transit} reached goal", transit.Destination.Geometry.TopCenter);

                    // transit.Current.StarchStorage.Amount += transit.Fluid.Amount;

                    CarrierCollection.Delete(transit.Destination);
                }
            }
        }
        protected IPlantCell FindUpOrDown(bool up, IPlantCell cell, IPlantPart part)
        {
            foreach (var c in part.Cells)
            {
                if (c.CellType == cell.CellType && CollisionDetection.Neighbors(cell, c, true))
                {
                    if (up && cell.Geometry.TopCenter.Y <= c.Geometry.BottomCenter.Y)
                    {
                        return(c);
                    }
                    if (!up && cell.Geometry.BottomCenter.Y >= c.Geometry.TopCenter.Y)
                    {
                        return(c);
                    }
                }
            }

            // If we end up here, that means that there are no cells above or below the current cell
            // which could mean that it must go to next plant part connection
            return(FindInConnection(up, cell, part));
        }
        protected virtual Vector3 DetermineGrowthDirection(IPlantCell cell, IPlantPart part)
        {
            var geo = cell.Geometry;

            var direction = new Vector3(0, 1, 0);

            var outwards = Vector3.Zero;

            if (part.BranchCount > 0)
            {
                if (geo.BottomCenter.X > 0)
                {
                    outwards += new Vector3(2, 0, 0);
                }
                else if (geo.BottomCenter.X < 0)
                {
                    outwards += new Vector3(-2, 0, 0);
                }
            }

            return(direction + outwards);
        }
        protected bool MoveCarrier(IFluidCarrier <TFluid> carrier, IPlantPart part)
        {
            // Get all the cells in the current plant part
            var cells = part.Cells;

            // The current carrier placement
            var current = carrier.Current;

            // Get the neighbors for the current carrier placement
            var neighbors = GetNeighboringCells(current, cells);

            IPlantCell next;

            // If the carrier is at the destination
            if (carrier.Current.Geometry.TopCenter.Equals(carrier.Destination.Geometry.TopCenter))
            {
                return(true);
            }

            // If the carrier is in a transport cell, it must move up or down
            if (carrier.IsInTransportCell)
            {
                next = MoveUpOrDown(carrier, part);
            }
            // If the carrier is not in a transport cell then it must move towards a transport cell
            // or the destination based on the height of the current placement
            else
            {
                next = GetClosestCellTowards(carrier, neighbors);
            }

            if (next != null)
            {
                carrier.Current = next;
            }

            return(false);
        }
示例#15
0
        private IEnumerable <PlantNodeModelState> IterateSystem(IPlantPart startPart)
        {
            IList <PlantNodeModelState> states = new List <PlantNodeModelState>();

            Stack <IPlantPart> stack = new Stack <IPlantPart>(new[] { startPart });

            while (stack.Count > 0)
            {
                var part = stack.Pop();

                if (!SkipTypes.Contains(part.PartType))
                {
                    states.Add(CreateStateFromPlantPart(part));
                }

                foreach (var connection in part.Connections)
                {
                    stack.Push(connection);
                }
            }

            return(states);
        }
 public void GrowRootCell(IPlantCell cell, IPlantPart part, SimulationStateSnapshot state)
 {
     MoveBottomPointDownwards(cell, part, state);
 }
 private void HandleRootPart(IPlantPart part)
 {
     plantPartDeveloper.Develop(part, currentState);
 }
示例#18
0
 public bool ShouldDivide(IPlantCell cell, IPlantPart plantPart, SimulationStateSnapshot state)
 {
     return(false);
 }
 public abstract void Transport(IPlantPart part);
示例#20
0
        /// <summary>
        /// Describe the physical properties of a plant part
        /// </summary>
        /// <param name="part">The plant part to describe</param>
        /// <param name="centerTop">Whether to compute the center as the sum of top- or bottom max</param>
        /// <returns>A PlantPartDescriptor object describing the provided plant part</returns>
        /// <remarks>Involves looping over all cells in the plant part</remarks>
        public IPlantPartDescriptor Describe(IPlantPart part, bool centerTop)
        {
            // Sum coordinates for computing averages
            float sumX = 0;
            float sumY = 0;
            float sumZ = 0;

            // Max and min values of all the x, y and z coordinates
            float xMax = float.MinValue;
            float yMax = float.MinValue;
            float zMax = float.MinValue;
            float xMin = float.MaxValue;
            float yMin = float.MaxValue;
            float zMin = float.MaxValue;

            // Cell counter
            var cellCount = 0;

            // Compute the above values
            foreach (var cell in part.Cells)
            {
                var top    = cell.Geometry.TopCenter;
                var bottom = cell.Geometry.BottomCenter;

                xMax = Math.Max(xMax, top.X);
                yMax = Math.Max(yMax, top.Y);
                zMax = Math.Max(zMax, top.Z);
                xMin = Math.Min(xMin, bottom.X);
                yMin = Math.Min(yMin, bottom.Y);
                zMin = Math.Min(zMin, bottom.Z);

                if (centerTop)
                {
                    sumX += top.X;
                    sumY += top.Y;
                    sumZ += top.Z;
                }
                else
                {
                    sumX += bottom.X;
                    sumY += bottom.Y;
                    sumZ += bottom.Z;
                }

                cellCount++;
            }

            // The average is computed by the total X and Z divided by the cellCount
            var center = new Vector2(sumX / cellCount, sumZ / cellCount);

            // The highest and lowest point, so that Y is yMax and yMin with the center as X and Z.
            var highest = new Vector3(center.X, yMax, center.Y);
            var lowest  = new Vector3(center.X, yMin, center.Y);

            // The plant height is the euclidean distance between the highest and lowest point
            var height = Vector3.Distance(highest, lowest);

            var widestX = new Vector2(xMax, center.Y);
            var minX    = new Vector2(xMin, center.Y);
            var widestZ = new Vector2(center.X, zMax);
            var minZ    = new Vector2(center.X, zMin);

            // Thickness is computed by the euclidean distance between the center and widest coordinate
            var thicknessX = Vector2.Distance(center, widestX);
            var thicknessZ = Vector2.Distance(center, widestZ);

            return(new PlantPartDescriptor
            {
                Top = highest,
                Bottom = lowest,
                Height = height,
                MaxX = xMax,
                MaxY = yMax,
                MaxZ = zMax,
                MinX = xMin,
                MinY = yMin,
                MinZ = zMin,
                WidthX = thicknessX,
                WidthZ = thicknessZ
            });
        }
 public void GrowShootCell(IPlantCell cell, IPlantPart part, SimulationStateSnapshot state)
 {
     MoveTopPointUpwards(cell, part, state);
 }
        protected virtual Vector3 DetermineGrowth(IPlantCell cell, IPlantPart part, SimulationStateSnapshot state)
        {
            var growth = DetermineGrowthDirection(cell, part) * DetermineGrowthFactor(cell, state);

            return(growth);
        }
        private void MoveBottomPointDownwards(IPlantCell cell, IPlantPart part, SimulationStateSnapshot state)
        {
            var geo = cell.Geometry;

            geo.BottomCenter -= DetermineGrowth(cell, part, state);
        }
        private void MoveTopPointUpwards(IPlantCell cell, IPlantPart part, SimulationStateSnapshot state)
        {
            var geo = cell.Geometry;

            geo.TopCenter += DetermineGrowth(cell, part, state);
        }