Ejemplo n.º 1
0
        internal int FindNearestNodeIndex(float range = 0.03f)
        {
            CameraData cameraData = DynaShapeViewExtension.CameraData;

            Triple camZ = new Triple(
                cameraData.LookDirection.X,
                -cameraData.LookDirection.Z,
                cameraData.LookDirection.Y).Normalise();

            Triple camY = new Triple(
                cameraData.UpDirection.X,
                -cameraData.UpDirection.Z,
                cameraData.UpDirection.Y).Normalise();

            Triple camX = camY.Cross(camZ).Normalise();

            Triple mousePosition2D = new Triple(
                DynaShapeViewExtension.MouseRayDirection.Dot(camX),
                DynaShapeViewExtension.MouseRayDirection.Dot(camY),
                DynaShapeViewExtension.MouseRayDirection.Dot(camZ));

            mousePosition2D /= mousePosition2D.Z;

            int nearestNodeIndex = -1;

            float minDistSquared = range * range;

            for (int i = 0; i < Nodes.Count; i++)
            {
                Triple v = Nodes[i].Position - DynaShapeViewExtension.MouseRayOrigin;
                v = new Triple(v.Dot(camX), v.Dot(camY), v.Dot(camZ));
                Triple nodePosition2D = v / v.Z;

                float distSquared = (mousePosition2D - nodePosition2D).LengthSquared;

                if (distSquared < minDistSquared)
                {
                    minDistSquared   = distSquared;
                    nearestNodeIndex = i;
                }
            }

            return(nearestNodeIndex);
        }
Ejemplo n.º 2
0
        private void RenderGUI()
        {
            //============================================================================
            // Render a visual marker to highlight the node that is being manipulated
            //============================================================================

            if (solver.HandleNodeIndex != -1 || solver.NearestNodeIndex != -1)
            {
                CameraData camera = DynaShapeViewExtension.CameraData;

                Triple camOrigin = new Triple(camera.EyePosition.X, -camera.EyePosition.Z, camera.EyePosition.Y);
                Triple camZ      = new Triple(camera.LookDirection.X, -camera.LookDirection.Z, camera.LookDirection.Y).Normalise();
                Triple camY      = new Triple(camera.UpDirection.X, -camera.UpDirection.Z, camera.UpDirection.Y).Normalise();
                Triple camX      = camZ.Cross(camY);

                int    nodeIndex      = solver.HandleNodeIndex != -1 ? solver.HandleNodeIndex : solver.NearestNodeIndex;
                Triple v              = solver.Nodes[nodeIndex].Position - camOrigin;
                float  screenDistance = (float)camera.NearPlaneDistance + 0.1f;
                v = camOrigin + v * screenDistance / v.Dot(camZ);

                float markerSize = 0.025f * screenDistance;

                Triple v1 = v + camX * markerSize;
                Triple v2 = v - camY * markerSize;
                Triple v3 = v - camX * markerSize;
                Triple v4 = v + camY * markerSize;

                lineGeometry.Positions.Add(v1.ToVector3());
                lineGeometry.Positions.Add(v3.ToVector3());
                lineGeometry.Positions.Add(v2.ToVector3());
                lineGeometry.Positions.Add(v4.ToVector3());

                markerSize *= 0.5f;
                v1          = v + camX * markerSize;
                v2          = v - camY * markerSize;
                v3          = v - camX * markerSize;
                v4          = v + camY * markerSize;

                lineGeometry.Positions.Add(v1.ToVector3());
                lineGeometry.Positions.Add(v2.ToVector3());
                lineGeometry.Positions.Add(v2.ToVector3());
                lineGeometry.Positions.Add(v3.ToVector3());
                lineGeometry.Positions.Add(v3.ToVector3());
                lineGeometry.Positions.Add(v4.ToVector3());
                lineGeometry.Positions.Add(v4.ToVector3());
                lineGeometry.Positions.Add(v1.ToVector3());


                int temp = lineGeometry.Indices.Count;
                for (int i = 0; i < 12; i++)
                {
                    lineGeometry.Indices.Add(temp + i);
                    lineGeometry.Colors.Add(Color.OrangeRed);
                }
            }
        }
Ejemplo n.º 3
0
        public void Step(bool momentum = true)
        {
            if (momentum)
            {
                foreach (Node node in Nodes)
                {
                    node.Position += node.Velocity;
                }
            }

            Parallel.ForEach(Goals, goal => goal.Compute(Nodes));

            Triple[] nodeMoveSums   = new Triple[Nodes.Count];
            float[]  nodeWeightSums = new float[Nodes.Count];

            foreach (Goal goal in Goals)
            {
                for (int i = 0; i < goal.NodeCount; i++)
                {
                    nodeMoveSums[goal.NodeIndices[i]]   += goal.Moves[i] * goal.Weight;
                    nodeWeightSums[goal.NodeIndices[i]] += goal.Weight;
                }
            }


            //=================================================================================

            if (HandleNodeIndex != -1)
            {
                float mouseInteractionWeight = 30f;
                nodeWeightSums[HandleNodeIndex] += mouseInteractionWeight;

                Triple clickRayOrigin    = new Triple(ClickRay.Origin.X, ClickRay.Origin.Y, ClickRay.Origin.Z);
                Triple clickRayDirection = new Triple(ClickRay.Direction.X, ClickRay.Direction.Y, ClickRay.Direction.Z);
                clickRayDirection = clickRayDirection.Normalise();
                Triple v        = Nodes[HandleNodeIndex].Position - clickRayOrigin;
                Triple grabMove = v.Dot(clickRayDirection) * clickRayDirection - v;
                nodeMoveSums[HandleNodeIndex] += mouseInteractionWeight * grabMove;
            }

            //=================================================================================

            for (int i = 0; i < Nodes.Count; i++)
            {
                Triple move = nodeMoveSums[i] / nodeWeightSums[i];
                Nodes[i].Position += move;
                if (momentum)
                {
                    Nodes[i].Velocity += move;
                }
                if (Nodes[i].Velocity.Dot(move) < 0.0)
                {
                    Nodes[i].Velocity *= 0.9f;
                }
            }
        }
Ejemplo n.º 4
0
        public void Tessellate(IRenderPackage package, TessellationParameters parameters)
        {
            for (int i = 0; i < solver.Nodes.Count; i++)
            {
                GeometryRender.DrawPoint(package, solver.Nodes[i].Position);
            }

            for (int i = 0; i < solver.GeometryBinders.Count; i++)
            {
                solver.GeometryBinders[i].DrawGraphics(package, parameters, solver.Nodes);
            }


            //=======================================================================================
            // Draw a cursor to highlight the node that is being manipulated by the mouse
            // ... the curor is 2D, so we need to draw it in the camera coordinate system, manually
            //=======================================================================================

            CameraData camera    = ((HelixWatch3DViewModel)Solver.Viewport).Camera.Dispatcher.Invoke(() => Solver.Viewport.GetCameraInformation());
            Triple     camOrigin = new Triple(camera.EyePosition.X, -camera.EyePosition.Z, camera.EyePosition.Y);
            Triple     camZ      = new Triple(camera.LookDirection.X, -camera.LookDirection.Z, camera.LookDirection.Y).Normalise();
            Triple     camY      = new Triple(camera.UpDirection.X, -camera.UpDirection.Z, camera.UpDirection.Y).Normalise();
            Triple     camX      = camZ.Cross(camY);


            if (solver.HandleNodeIndex != -1 || solver.NearestNodeIndex != -1)
            {
                int   i           = solver.HandleNodeIndex != -1 ? solver.HandleNodeIndex : solver.NearestNodeIndex;
                Color handleColor = solver.HandleNodeIndex != -1 ? Color.OrangeRed : Color.Black;

                Triple v = solver.Nodes[i].Position - camOrigin;
                v = camOrigin + ((float)camera.NearPlaneDistance + 0.5f) * v / v.Dot(camZ);

                float handleSize = 0.008f;

                Triple v1 = v + camX * handleSize;
                Triple v2 = v - camY * handleSize;
                Triple v3 = v - camX * handleSize;
                Triple v4 = v + camY * handleSize;
                GeometryRender.DrawPolyline(package, new List <Triple> {
                    v1, v2, v3, v4, v1
                }, handleColor);

                handleSize = 0.015f;
                v1         = v + camX * handleSize;
                v2         = v - camY * handleSize;
                v3         = v - camX * handleSize;
                v4         = v + camY * handleSize;

                GeometryRender.DrawLine(package, v1, v3, handleColor);
                GeometryRender.DrawLine(package, v2, v4, handleColor);
            }
        }
Ejemplo n.º 5
0
        internal int FindNearestNodeIndex(IRay clickRay, float range = 0.03f)
        {
            CameraData cameraData = Viewport.GetCameraInformation();
            Triple     camZ       = new Triple(cameraData.LookDirection.X, -cameraData.LookDirection.Z,
                                               cameraData.LookDirection.Y).Normalise();
            Triple camY = new Triple(cameraData.UpDirection.X, -cameraData.UpDirection.Z, cameraData.UpDirection.Y)
                          .Normalise();
            Triple camX = camY.Cross(camZ).Normalise();

            Triple clickRayOrigin    = new Triple(clickRay.Origin.X, clickRay.Origin.Y, clickRay.Origin.Z);
            Triple clickRayDirection = new Triple(clickRay.Direction.X, clickRay.Direction.Y, clickRay.Direction.Z);

            Triple mousePosition2D = new Triple(clickRayDirection.Dot(camX), clickRayDirection.Dot(camY),
                                                clickRayDirection.Dot(camZ));

            mousePosition2D /= mousePosition2D.Z;

            int nearestNodeIndex = -1;

            float minDistSquared = range * range;

            for (int i = 0; i < Nodes.Count; i++)
            {
                Triple v = Nodes[i].Position - clickRayOrigin;
                v = new Triple(v.Dot(camX), v.Dot(camY), v.Dot(camZ));
                Triple nodePosition2D = v / v.Z;

                float distSquared = (mousePosition2D - nodePosition2D).LengthSquared;

                if (distSquared < minDistSquared)
                {
                    minDistSquared   = distSquared;
                    nearestNodeIndex = i;
                }
            }

            return(nearestNodeIndex);
        }
Ejemplo n.º 6
0
        public Triple Rotate(Triple origin, Triple Axis, float angle)
        {
            Triple z = Axis.Normalise();
            Triple x = z.GeneratePerpendicular().Normalise();
            Triple y = z.Cross(x).Normalise();

            Triple v = this - origin;

            float vx = x.Dot(v);
            float vy = y.Dot(v);
            float vz = z.Dot(v);

            float sin = (float)Math.Sin(angle);
            float cos = (float)Math.Cos(angle);

            float vx_ = cos * vx - sin * vy;
            float vy_ = sin * vx + cos * vy;

            return(origin + x * vx_ + y * vy_ + z * vz);
        }
Ejemplo n.º 7
0
        public static bool ComputeBestFitCircle(List <Triple> points, out Triple circleCenter, out Triple circleNormal,
                                                out float circleRadius)
        {
            // Apporach: Project the input points to the best fit plane, then fit a circle through these points using the the analytical approach ...
            // ... described in the paper "A simple approach for the estimation of circular arc center and its radius" by Thomas S & Chan Y.

            Triple planeOrigin, planeNormal;
            int    planeFittingResult = ComputeBestFitPlane(points, out planeOrigin, out planeNormal);

            if (planeFittingResult < 2) // The points are either all identical, or colinear (i.e. already on the same "circle" of infinite radius)
            {
                circleCenter = circleNormal = new Triple(float.NaN);
                circleRadius = float.NaN;
                return(false);
            }

            Triple planeBasisX = planeNormal.GeneratePerpendicular().Normalise();
            Triple planeBasisY = planeNormal.Cross(planeBasisX);

            float sumX   = 0f;
            float sumY   = 0f;
            float sumX2  = 0f;
            float sumY2  = 0f;
            float sumXY  = 0f;
            float sumX3  = 0f;
            float sumY3  = 0f;
            float sumX2Y = 0f;
            float sumXY2 = 0f;

            float x, y;

            for (int i = 0; i < points.Count; i++)
            {
                Triple p = points[i] - planeOrigin;
                x       = p.Dot(planeBasisX);
                y       = p.Dot(planeBasisY);
                sumX   += x;
                sumY   += y;
                sumX2  += x * x;
                sumY2  += y * y;
                sumXY  += x * y;
                sumX3  += x * x * x;
                sumY3  += y * y * y;
                sumX2Y += x * x * y;
                sumXY2 += x * y * y;
            }

            float n = points.Count;

            float a1 = 2f * (sumX * sumX - n * sumX2);
            float a2 = 2f * (sumX * sumY - n * sumXY);
            float b1 = a2;
            float b2 = 2f * (sumY * sumY - n * sumY2);
            float c1 = sumX2 * sumX - n * sumX3 + sumX * sumY2 - n * sumXY2;
            float c2 = sumX2 * sumY - n * sumY3 + sumY * sumY2 - n * sumX2Y;

            float temp = 1f / (a1 * b2 - a2 * b1);

            x = (c1 * b2 - c2 * b1) * temp;
            y = (a1 * c2 - a2 * c1) * temp;

            circleCenter = planeOrigin + (x * planeBasisX + y * planeBasisY);
            circleRadius =
                (float)Math.Sqrt((sumX2 - 2f * sumX * x + n * x * x + sumY2 - 2f * sumY * y + n * y * y) / n);
            circleNormal = planeNormal;
            return(true);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Approximate the circle that best fit a set of input points
        /// </summary>
        /// <param name="points">The input points</param>
        /// <param name="circleCenter">Center of the best fit circle</param>
        /// <param name="circleNormal">Normal of the best fit circle</param>
        /// <param name="circleRadius">Radius of the best fit circle</param>
        /// <param name="tolerance">The tolerance that is used the determined if the input points are coincidental, colinear, or non-colinear</param>
        /// <returns>False if the input points are coincidental or colinear; True otherwise</returns>
        public static bool ComputeBestFitCircle(List <Triple> points, out Triple circleCenter, out Triple circleNormal, out float circleRadius, float tolerance = 1E-10f)
        {
            // The core idea is to project the input points to the best fit plane, then fit a circle through these points via an analytical approach.
            // Reference: Thomas S & Chan Y: "A simple approach for the estimation of circular arc center and its radius

            int planeFittingResult = ComputeBestFitPlane(points, out Triple planeOrigin, out Triple planeNormal, tolerance);

            // Case 0: The input points are either coincidental or colinear
            if (planeFittingResult < 2)
            {
                circleCenter = circleNormal = new Triple(float.NaN);
                circleRadius = float.NaN;
                return(false);
            }

            // Case 1: The input points are neither coincidental nor colinear
            Triple planeBasisX = planeNormal.GeneratePerpendicular().Normalise();
            Triple planeBasisY = planeNormal.Cross(planeBasisX);

            float sumX   = 0f;
            float sumY   = 0f;
            float sumX2  = 0f;
            float sumY2  = 0f;
            float sumXY  = 0f;
            float sumX3  = 0f;
            float sumY3  = 0f;
            float sumX2Y = 0f;
            float sumXY2 = 0f;

            float x, y;

            for (int i = 0; i < points.Count; i++)
            {
                Triple p = points[i] - planeOrigin;
                x       = p.Dot(planeBasisX);
                y       = p.Dot(planeBasisY);
                sumX   += x;
                sumY   += y;
                sumX2  += x * x;
                sumY2  += y * y;
                sumXY  += x * y;
                sumX3  += x * x * x;
                sumY3  += y * y * y;
                sumX2Y += x * x * y;
                sumXY2 += x * y * y;
            }

            float n = points.Count;

            float a1 = 2f * (sumX * sumX - n * sumX2);
            float a2 = 2f * (sumX * sumY - n * sumXY);
            float b1 = a2;
            float b2 = 2f * (sumY * sumY - n * sumY2);
            float c1 = sumX2 * sumX - n * sumX3 + sumX * sumY2 - n * sumXY2;
            float c2 = sumX2 * sumY - n * sumY3 + sumY * sumY2 - n * sumX2Y;

            float temp = 1f / (a1 * b2 - a2 * b1);

            x = (c1 * b2 - c2 * b1) * temp;
            y = (a1 * c2 - a2 * c1) * temp;

            circleCenter = planeOrigin + (x * planeBasisX + y * planeBasisY);
            circleRadius = (float)Math.Sqrt((sumX2 - 2f * sumX * x + n * x * x + sumY2 - 2f * sumY * y + n * y * y) / n);
            circleNormal = planeNormal;
            return(true);
        }
Ejemplo n.º 9
0
        public void Iterate()
        {
            CurrentIteration++;

            //=================================================================================
            // Apply momentum
            //=================================================================================

            if (EnableMomentum)
            {
                foreach (Node node in Nodes)
                {
                    node.Position += node.Velocity;
                }
            }

            //=================================================================================
            // Process each goal independently, in parallel
            //=================================================================================

            Parallel.ForEach(Goals, goal => goal.Compute(Nodes));

            //=================================================================================
            // Compute the total move vector that acts on each node
            //=================================================================================

            Triple[] nodeMoveSums   = new Triple[Nodes.Count];
            float[]  nodeWeightSums = new float[Nodes.Count];

            for (int j = 0; j < Goals.Count; j++)
            {
                Goal goal = Goals[j];
                for (int i = 0; i < goal.NodeCount; i++)
                {
                    nodeMoveSums[goal.NodeIndices[i]]   += goal.Moves[i] * goal.Weights[i];
                    nodeWeightSums[goal.NodeIndices[i]] += goal.Weights[i];
                }
            }

            //=================================================================================
            // Move the manipulated node toward the mouse ray
            //=================================================================================

#if CLI == false
            if (HandleNodeIndex != -1)
            {
                float manipulationWeight = 30f;
                nodeWeightSums[HandleNodeIndex] += manipulationWeight;

                Triple v            = Nodes[HandleNodeIndex].Position - DynaShapeViewExtension.MouseRayOrigin;
                Triple mouseRayPull = v.Dot(DynaShapeViewExtension.MouseRayDirection) * DynaShapeViewExtension.MouseRayDirection - v;
                nodeMoveSums[HandleNodeIndex] += manipulationWeight * mouseRayPull;
            }
#endif

            //=============================================================================================
            // Move the nodes to their new positions
            //=============================================================================================

            if (EnableMomentum)
            {
                for (int i = 0; i < Nodes.Count; i++)
                {
                    if (nodeWeightSums[i] == 0f)
                    {
                        continue;
                    }
                    Triple move = nodeMoveSums[i] / nodeWeightSums[i];
                    Nodes[i].Move      = move;
                    Nodes[i].Position += move;
                    Nodes[i].Velocity += move;
                    //if (Nodes[i].Velocity.Dot(move) <= 0.0)
                    Nodes[i].Velocity *= DampingFactor;
                }
            }
            else
            {
                for (int i = 0; i < Nodes.Count; i++)
                {
                    if (nodeWeightSums[i] == 0f)
                    {
                        continue;
                    }
                    Triple move = nodeMoveSums[i] / nodeWeightSums[i];
                    Nodes[i].Move      = move;
                    Nodes[i].Position += move;
                    Nodes[i].Velocity  = Triple.Zero;
                }
            }
        }
Ejemplo n.º 10
0
        public void Iterate3()
        {
            CurrentIteration++;

            //=================================================================================
            // Apply momentum
            //=================================================================================


            foreach (Node node in Nodes)
            {
                node.Position += node.Velocity;
            }

            for (int k = 0; k < 50; k++)
            {
                //=================================================================================
                // Process each goal indepently, in parallel
                //=================================================================================

                Parallel.ForEach(Goals, goal => goal.Compute(Nodes));


                //=================================================================================
                // Compute the total move vector that acts on each node
                //=================================================================================

                Triple[] nodeMoveSums   = new Triple[Nodes.Count];
                float[]  nodeWeightSums = new float[Nodes.Count];

                for (int j = 0; j < Goals.Count; j++)
                {
                    Goal goal = Goals[j];
                    for (int i = 0; i < goal.NodeCount; i++)
                    {
                        nodeMoveSums[goal.NodeIndices[i]]   += goal.Moves[i] * goal.Weight;
                        nodeWeightSums[goal.NodeIndices[i]] += goal.Weight;
                    }
                }

                //=================================================================================
                // Move the manipulated node toward the mouse ray
                //=================================================================================

                if (HandleNodeIndex != -1)
                {
                    float mouseInteractionWeight = 30f;
                    nodeWeightSums[HandleNodeIndex] += mouseInteractionWeight;

                    Triple v            = Nodes[HandleNodeIndex].Position - DynaShapeViewExtension.MouseRayOrigin;
                    Triple mouseRayPull = v.Dot(DynaShapeViewExtension.MouseRayDirection) *
                                          DynaShapeViewExtension.MouseRayDirection - v;
                    nodeMoveSums[HandleNodeIndex] += mouseInteractionWeight * mouseRayPull;
                }


                for (int i = 0; i < Nodes.Count; i++)
                {
                    Triple move = nodeMoveSums[i] / nodeWeightSums[i];
                    Nodes[i].Position += move;
                    Nodes[i].Velocity += move;
                    if (Nodes[i].Velocity.Dot(move) < 0.0)
                    {
                        Nodes[i].Velocity *= 0.99f;
                    }
                }
            }
        }