Beispiel #1
0
        private static Point3D?CastRay_Cylinder(Point3D point, Vector3D direction, double radius, RayHitTestParameters mouseDownClickRay, RayHitTestParameters mouseDownCenterRay, RayHitTestParameters currentClickRay)
        {
            // Get points on the cylinder
            Point3D?mouseDownClickPoint  = null;
            Point3D?mouseDownCenterPoint = null;
            Point3D?currentClickPoint    = null;

            Point3D[] nearestCylinderPoints, nearestLinePoints;
            if (Math3D.GetClosestPoints_Cylinder_Line(out nearestCylinderPoints, out nearestLinePoints, point, direction, radius, currentClickRay.Origin, currentClickRay.Direction, Math3D.RayCastReturn.ClosestToRay))
            {
                currentClickPoint = nearestCylinderPoints[0];

                if (Math3D.GetClosestPoints_Cylinder_Line(out nearestCylinderPoints, out nearestLinePoints, point, direction, radius, mouseDownClickRay.Origin, mouseDownClickRay.Direction, Math3D.RayCastReturn.ClosestToRay))
                {
                    mouseDownClickPoint = nearestCylinderPoints[0];

                    if (Math3D.GetClosestPoints_Cylinder_Line(out nearestCylinderPoints, out nearestLinePoints, point, direction, radius, mouseDownCenterRay.Origin, mouseDownCenterRay.Direction, Math3D.RayCastReturn.ClosestToRay))
                    {
                        mouseDownCenterPoint = nearestCylinderPoints[0];
                    }
                }
            }

            if (mouseDownCenterPoint == null || mouseDownClickPoint == null || currentClickPoint == null)
            {
                return(currentClickPoint);               // it doesn't matter if this one is null or not, the offset can't be determined, so just return the raw click value
            }

            // Circle only cared about an offset angle, but cylinder needs two things:
            //		Offset line (the part of the offset that is parallel to the cylinder's axis)
            //		Offset angle (the part of the offset that is perpendicular to the cylinder's axis)
            Vector3D   offsetLinear = (mouseDownCenterPoint.Value - mouseDownClickPoint.Value).GetProjectedVector(direction);
            Quaternion offsetRadial = GetRotation_Circle(point, direction, mouseDownClickPoint.Value, mouseDownCenterPoint.Value);



            //TODO: Get the radial offset working as well (sphere is also messed up, the same fix should work for both)



            //TODO: See if this is the most effiecient way or not
            Transform3DGroup transform = new Transform3DGroup();

            //transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(offsetRadial)));
            transform.Children.Add(new TranslateTransform3D(offsetLinear));

            //TODO: Bring currentClickPoint into local coords, do the transform, then put it back into global coords

            // Find the point along the cylinder's axis that is nearest to the current click.  This will become the center of the model coords
            Point3D modelCenter = Math3D.GetClosestPoint_Line_Point(point, direction, currentClickPoint.Value);

            // Shift the click point into model coords
            Vector3D modelClick = currentClickPoint.Value - modelCenter;

            // Adjust by the offset transform (needed to put into model coords, because there is a rotation)
            modelClick = transform.Transform(modelClick);

            // Now put back into world coords
            return(modelCenter + modelClick);
        }
Beispiel #2
0
        private double?GetClickDistanceNearSwarm_ALLBOTS(RayHitTestParameters clickRay)
        {
            Point3D?closestPoint = null;
            double  minDist      = double.MaxValue;

            foreach (SwarmBot1a bot in _map.GetItems <SwarmBot1a>(false))
            {
                Point3D botPos = bot.PositionWorld;

                Point3D closest = Math3D.GetClosestPoint_Line_Point(clickRay.Origin, clickRay.Direction, botPos);
                if (Vector3D.DotProduct(closest - clickRay.Origin, clickRay.Direction) < 0)
                {
                    // It's behind the camera
                    continue;
                }

                double lenSqr = (botPos - closest).LengthSquared;

                if (lenSqr < minDist)
                {
                    minDist      = lenSqr;
                    closestPoint = closest;
                }
            }

            if (closestPoint == null)
            {
                return(null);
            }

            return((closestPoint.Value - clickRay.Origin).Length);
        }
Beispiel #3
0
        private static Quaternion GetRotation_Circle(Point3D center, Vector3D normal, Point3D from, Point3D to)
        {
            // Get the two angles, it doesn't matter where they are along that normal
            Vector3D fromLine = from - Math3D.GetClosestPoint_Line_Point(center, normal, from);
            Vector3D toLine   = to - Math3D.GetClosestPoint_Line_Point(center, normal, to);

            return(Math3D.GetRotation(fromLine, toLine));                // I was about to just take the angle, since I already have the normal, but the angle could be greater than 180, so the axis would flip, and the math3d method already accounts for that, so I'm just using it
        }
Beispiel #4
0
        private static Point3D?CastRay_LinesCircles(IEnumerable <RayHitTestParameters> lines, IEnumerable <CircleDefinition> circles, Point3D testPoint)
        {
            Point3D?retVal   = null;
            double  distance = double.MaxValue;

            if (lines != null)
            {
                // Cast onto each line, and return the point that's closest to the test point
                foreach (RayHitTestParameters line in lines)
                {
                    Point3D point = Math3D.GetClosestPoint_Line_Point(line.Origin, line.Direction, testPoint);

                    double localDistance = (point - testPoint).LengthSquared;
                    if (retVal == null || localDistance < distance)
                    {
                        retVal   = point;
                        distance = localDistance;
                    }
                }
            }

            if (circles != null)
            {
                // Cast onto each circle, and return the point that's closest to the test point
                foreach (CircleDefinition circle in circles)
                {
                    Point3D?point = Math3D.GetClosestPoint_Circle_Point(circle.Plane, circle.Center, circle.Radius, testPoint);
                    if (point != null)
                    {
                        double localDistance = (point.Value - testPoint).LengthSquared;
                        if (retVal == null || localDistance < distance)
                        {
                            retVal   = point.Value;
                            distance = localDistance;
                        }
                    }
                }
            }

            return(retVal);
        }
Beispiel #5
0
        private static BezierSegment3D[][] GetModel_Second_Curves(AxeSecondProps arg)
        {
            BezierSegment3D[][] retVal = new BezierSegment3D[5][];

            AxeSecondProps[] argLevels = new AxeSecondProps[5];

            argLevels[2] = arg;     // Edge
            #region Middle

            argLevels[1] = UtilityCore.Clone_Shallow(arg);

            // Right
            argLevels[1].EndTR = new Point3D(argLevels[1].EndTR.X * .8, argLevels[1].EndTR.Y * .9, .15);

            Vector3D   offsetTR = new Point3D(argLevels[1].EndTR.X, argLevels[1].EndTR.Y, 0) - arg.EndTR;
            Quaternion angleTR  = Math3D.GetRotation((arg.EndTL - arg.EndTR), offsetTR);

            Vector3D rotated = (arg.EndBL_1 - arg.EndBR).ToUnit() * offsetTR.Length;
            rotated = rotated.GetRotatedVector(angleTR.Axis, angleTR.Angle * -1.3);

            argLevels[1].EndBR = new Point3D(argLevels[1].EndBR.X + rotated.X, argLevels[1].EndBR.Y + rotated.Y, .15);      // can't just use percents of coordinates.  Instead use the same offset angle,distance that top left had

            // Left
            argLevels[1].EndTL = new Point3D(argLevels[1].EndTL.X, argLevels[1].EndTL.Y * .95, .3);

            if (argLevels[1].EndBL_2 == null)
            {
                argLevels[1].EndBL_1 = new Point3D(argLevels[1].EndBL_1.X, argLevels[1].EndBL_1.Y * .9, .3);
            }
            else
            {
                Vector3D offsetBL1 = arg.EndBR - arg.EndBL_1;
                double   lengthBL1 = (new Point3D(argLevels[1].EndBR.X, argLevels[1].EndBR.Y, 0) - arg.EndBR).Length;
                offsetBL1 = offsetBL1.ToUnit() * (offsetBL1.Length - lengthBL1);

                argLevels[1].EndBL_1 = argLevels[1].EndBR - offsetBL1;
                argLevels[1].EndBL_1 = new Point3D(argLevels[1].EndBL_1.X, argLevels[1].EndBL_1.Y, .18);

                argLevels[1].EndBL_2 = new Point3D(argLevels[1].EndBL_2.Value.X, argLevels[1].EndBL_2.Value.Y * .9, .3);
            }

            argLevels[3] = argLevels[1].CloneNegateZ();

            #endregion
            #region Far

            argLevels[0] = UtilityCore.Clone_Shallow(arg);

            argLevels[0].EndTL = new Point3D(argLevels[0].EndTL.X, argLevels[0].EndTL.Y * .7, .4);

            argLevels[0].EndTR = new Point3D(argLevels[0].EndTR.X * .5, argLevels[0].EndTR.Y * .6, .25);

            if (argLevels[0].EndBL_2 == null)
            {
                argLevels[0].EndBR   = new Point3D(argLevels[0].EndBR.X * .5, argLevels[0].EndBR.Y * .6, .25);
                argLevels[0].EndBL_1 = new Point3D(argLevels[0].EndBL_1.X, argLevels[0].EndBL_1.Y * .6, .4);
            }
            else
            {
                // Bottom Right
                Vector3D offset     = (argLevels[1].EndBR - argLevels[1].EndBL_1) * .5;
                Point3D  startPoint = argLevels[1].EndBL_1 + offset;    // midway along bottom edge

                offset = argLevels[1].EndTR - startPoint;

                argLevels[0].EndBR = startPoint + (offset * .15);                                  // from midway point toward upper right point
                argLevels[0].EndBR = new Point3D(argLevels[0].EndBR.X, argLevels[0].EndBR.Y, .25); // fix z

                // Left of bottom right (where the circle cutout ends)
                offset = argLevels[1].EndBR - argLevels[1].EndBL_1;
                argLevels[0].EndBL_1 = Math3D.GetClosestPoint_Line_Point(argLevels[0].EndBR, offset, argLevels[0].EndBL_1);

                offset *= .05;
                Point3D  minBL1     = argLevels[0].EndBR - offset;
                Vector3D testOffset = argLevels[0].EndBL_1 - argLevels[0].EndBR;
                if (Vector3D.DotProduct(testOffset, offset) < 0 || testOffset.LengthSquared < offset.LengthSquared)
                {
                    argLevels[0].EndBL_1 = minBL1;
                }

                // Bottom Left
                argLevels[0].EndBL_2 = new Point3D(argLevels[0].EndBL_2.Value.X, argLevels[0].EndBL_2.Value.Y * .6, .4);

                // Reduce the curve a bit
                argLevels[0].B2AngleL   = argLevels[0].B2AngleL * .9;
                argLevels[0].B2PercentL = argLevels[0].B2PercentL * .95;

                argLevels[0].B2AngleR   = argLevels[0].B2AngleR * .85;
                argLevels[0].B2PercentR = argLevels[0].B2PercentR * .95;
            }

            argLevels[4] = argLevels[0].CloneNegateZ();

            #endregion

            for (int cntr = 0; cntr < 5; cntr++)
            {
                BezierSegment3D[] segments = GetModel_Second_Segments(argLevels[cntr]);
                retVal[cntr] = segments;
            }

            return(retVal);
        }
Beispiel #6
0
        /// <summary>
        /// This returns the normal of the drag shape relative to the point passed in
        /// NOTE: I'll wait till this method is needed before finishing it
        /// </summary>
        /// <remarks>
        /// This is important for cases where they are dragging an object across a cylinder or sphere.  You would want that object's orientation
        /// to change so it appears to be stuck to the side of the shape
        ///
        /// Drag shape of line(s) just returns null
        /// </remarks>
        public Vector3D?GetNormal(Point3D point)
        {
            // Can't do this, because if the point goes under the plane, the normal gets reversed
            //// This should handle most cases
            //Point3D? pointOnShape = CastRay(point);
            //if (pointOnShape != null && !Math3D.IsNearValue(point, pointOnShape.Value))
            //{
            //    return point - pointOnShape.Value;
            //}

            Vector3D?retVal = null;

            // The request point is sitting on the shape.  Some of the shapes can get more generic

            switch (_shape)
            {
            case ShapeType.Plane:
                #region Plane

                retVal = _plane.NormalUnit;

                // No need to do all this.  Execution only gets here when the request point is sitting on the plane
                //Point3D pointOnPlane = Math3D.GetClosestPoint_Point_Plane(_plane, point);

                //if (!Math3D.IsNearValue(point, pointOnPlane) && Vector3D.DotProduct(point - pointOnPlane, retVal.Value) < 0)
                //{
                //    // The test point is away from the normal, reverse it
                //    retVal = retVal.Value * -1;
                //}

                #endregion
                break;

            case ShapeType.Cylinder:
                #region Cylinder

                // Execution gets here when the request point is sitting on the surface of the cylinder.  Treat it like a line and try again

                Point3D nearestAxisPoint = Math3D.GetClosestPoint_Line_Point(_point, _direction, point);

                if (!Math3D.IsNearValue(nearestAxisPoint, point))
                {
                    retVal = point - nearestAxisPoint;
                }

                #endregion
                break;

            case ShapeType.Sphere:
                #region Sphere

                if (!Math3D.IsNearValue(_point, point))
                {
                    retVal = point - _point;
                }

                #endregion
                break;
            }

            return(retVal);
        }
Beispiel #7
0
        /// <summary>
        /// This overload returns a point on the shape that is closest to the point passed in
        /// </summary>
        public Point3D?CastRay(Point3D point)
        {
            Point3D?retVal = null;

            switch (_shape)
            {
            case ShapeType.Line:
                #region Line

                retVal = Math3D.GetClosestPoint_Line_Point(_point, _direction, point);

                #endregion
                break;

            case ShapeType.Lines:
                #region Lines

                retVal = CastRay_LinesCircles(_lines, null, point);

                #endregion
                break;

            case ShapeType.Plane:
                #region Plane

                retVal = Math3D.GetClosestPoint_Plane_Point(_plane, point);

                #endregion
                break;

            case ShapeType.Circle:
                #region Circle

                retVal = Math3D.GetClosestPoint_Circle_Point(_plane, _point, _radius, point);

                #endregion
                break;

            case ShapeType.Circles:
                #region Circles

                retVal = CastRay_LinesCircles(null, _circles, point);

                #endregion
                break;

            case ShapeType.LinesCircles:
                #region LinesCircles

                retVal = CastRay_LinesCircles(_lines, _circles, point);

                #endregion
                break;

            case ShapeType.Cylinder:
                #region Cylinder

                retVal = Math3D.GetClosestPoint_Cylinder_Point(_point, _direction, _radius, point);

                #endregion
                break;

            case ShapeType.Sphere:
                #region Sphere

                retVal = Math3D.GetClosestPoint_Sphere_Point(_point, _radius, point);

                #endregion
                break;

            case ShapeType.Mesh:
                throw new ApplicationException("finish this");

            case ShapeType.None:
                retVal = null;
                break;

            default:
                throw new ApplicationException("Unknown ShapeType: " + _shape.ToString());
            }

            return(retVal);
        }