protected override bool OnClickStart(ScreenPoint cursorPos, Line cursorRay)
        {
            IDocObject selection    = null;
            IDocObject preselection = InteractionContext.Preselection;
            var        desFace      = preselection as DesignFace;

            if (desFace != null)
            {
                WriteBlock.ExecuteTask("Create Sphere Set", () => selection = SphereSet.Create(desFace, count, strength, radius, color).Subject);
            }
            else
            {
                SphereSet sphereSet = SphereSet.GetWrapper(preselection as CustomObject);
                if (sphereSet != null)
                {
                    selection = sphereSet.Subject;

                    CountSlider.Value    = sphereSet.Count;
                    StrengthSlider.Value = sphereSet.Strength;
                    ColorComboBox.Value  = sphereSet.Color;
                    RadiusSlider.Value   = sphereSet.Radius;
                }
            }

            Window.ActiveContext.Selection = new[] { selection };
            return(false);
        }
        void radiusSliderCommand_TextChanged(object sender, CommandTextChangedEventArgs e)
        {
            radius = RadiusSlider.Value;

            SphereSet sphereSet = SelectedSphereSet;

            if (sphereSet != null)
            {
                WriteBlock.ExecuteTask("Adjust radius", () => sphereSet.Radius = radius);
            }
        }
        void colorCommand_TextChanged(object sender, CommandTextChangedEventArgs e)
        {
            color = ColorComboBox.Value;

            SphereSet sphereSet = SelectedSphereSet;

            if (sphereSet != null)
            {
                WriteBlock.ExecuteTask("Adjust color", () => sphereSet.Color = color);
            }
        }
        void strengthSliderCommand_TextChanged(object sender, CommandTextChangedEventArgs e)
        {
            strength = StrengthSlider.Value;

            SphereSet sphereSet = SelectedSphereSet;

            if (sphereSet != null)
            {
                WriteBlock.ExecuteTask("Adjust radius", () => sphereSet.Strength = strength);
            }
        }
        protected override void OnInitialize(Command command)
        {
            SphereSet.InitializeGraphics();

            ColorComboBox.Initialize();
            CountSlider.Initialize();
            StrengthSlider.Initialize();
            AnimateStepButton.Initialize();
            AnimatePlayButton.Initialize();
            RadiusSlider.Initialize();
            CreateSpheresButton.Initialize();
        }
        private static void CalculateFrame(SphereSet sphereSet)
        {
            Point[]  positions         = sphereSet.Positions;
            Point[]  newPositions      = new Point[positions.Length];
            Vector[] forces            = new Vector[positions.Length];
            Body     body              = sphereSet.DesFace.Shape.Body;
            Random   random            = new Random();
            double   idealRadius       = sphereSet.IdealRadius;
            double   idealRadiusComped = idealRadius * Math.Sqrt(sphereSet.Count);
            double   minRadiusFactor   = 0.05;

            double scale   = 1E-3 * idealRadius;
            double maxCalc = 16 * idealRadius * idealRadius;

            for (int i = 0; i < positions.Length; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    Vector separation      = positions[i] - positions[j];
                    double distanceSquared = separation.MagnitudeSquared();
                    if (distanceSquared > maxCalc)
                    {
                        continue;
                    }

                    double x = distanceSquared / (idealRadiusComped * idealRadius);

                    Vector force;
                    if (x > minRadiusFactor)
                    {
                        force = separation.Direction * ((double)1 / (x * x) - (double)1 / x);
                    }
                    else
                    {
                        force = Math.Sqrt(sphereSet.Count) / minRadiusFactor * 4 * Vector.Create(random.NextDouble() - 0.5, random.NextDouble() - 0.5, random.NextDouble() - 0.5);
                    }

                    forces[i] += force;
                    forces[j] -= force;
                }
            }

            Face face;

            for (int i = 0; i < positions.Length; i++)
            {
                newPositions[i] = body.ProjectPointToShell(positions[i] + scale * forces[i], out face).Point;
            }

            sphereSet.Positions = newPositions;
        }
        public override int Advance(int frame)
        {
            Debug.Assert(frame >= 1);

            SphereSet sphereSet = DistributeSpheresTool.SelectedSphereSet;

            if (sphereSet == null)
            {
                return(frame);
            }

            WriteBlock.ExecuteTask("Animate Spheres", () => CalculateFrame(sphereSet));

            return(frame + 2);
        }
        protected override bool OnMouseMove(ScreenPoint cursorPos, Line cursorRay, MouseButtons button)
        {
            if (button != MouseButtons.None)
            {
                return(false);
            }

            IDocObject preselection = InteractionContext.Preselection;
            DesignFace desFace      = null;

            SphereSet existingSphereSet = SphereSet.GetWrapper(preselection as CustomObject);

            if (existingSphereSet != null)
            {
                desFace = existingSphereSet.DesFace;
            }
            if (desFace == null)
            {
                desFace = preselection as DesignFace;
            }
            if (desFace == null) // selection filtering is not applied if you (pre)select in the tree
            {
                return(false);
            }

            if (SphereSet.AllSphereSets.Where(s => s.DesFace == desFace).Count() > 0)
            {
                return(false);
            }

            Body body = desFace.Shape.Body;

            GraphicStyle style = null;

            if (existingSphereSet == null)
            {
                style = new GraphicStyle {
                    EnableDepthBuffer = true,
                    FillColor         = color
                };

                Rendering = Graphic.Create(style, null, SphereSet.GetGraphics(SphereSet.GetInitialPositions(body, count, true), radius));
            }

            return(false); // if we return true, the preselection won't update
        }
        void createSphereCommand_Execute(object sender, CommandExecutingEventArgs e)
        {
            SphereSet sphereSet = SelectedSphereSet;

            if (sphereSet == null)
            {
                return;
            }

            Part sphereRootPart = Part.Create(Window.Document, "Spheres");

            Component.Create(Window.ActiveWindow.Scene as Part, sphereRootPart);
            Part innerSpherePart = Part.Create(Window.Document, "Inner Spheres");
            Part outerSpherePart = Part.Create(Window.Document, "Outer Spheres");

            Component.Create(sphereRootPart, innerSpherePart);
            Component.Create(sphereRootPart, outerSpherePart);

            Part spherePart = Part.Create(Window.Document, "Sphere");

            ShapeHelper.CreateSphere(Point.Origin, sphereSet.Radius * 2, spherePart);

            Body body = sphereSet.DesFace.Shape.Body;

            foreach (Point point in sphereSet.Positions)
            {
                bool isEdge = false;
                foreach (Edge edge in body.Edges.Where(edge => edge.Faces.Count == 1))
                {
                    if ((edge.ProjectPoint(point).Point - point).MagnitudeSquared() < (sphereSet.Radius * sphereSet.Radius))
                    {
                        isEdge = true;
                        break;
                    }
                }

                Component component = Component.Create(isEdge ? outerSpherePart : innerSpherePart, spherePart);
                component.Placement = Matrix.CreateTranslation(point.Vector);
            }
        }