コード例 #1
0
        public void Transfer(float radians, Gear target)
        {
            var ratio         = this.NumberOfTeeth / (float)target.NumberOfTeeth;
            var targetRadians = radians * ratio;

            target.Spin(targetRadians * target.Direction);

            // Solve colisions due to small inaccuracies

            // 1. Find tooth closest to target gear
            var targetPosition2D = new Vector2(target.Position.X, target.Position.Z);

            var myClosestTooth = GetToothClosestToPoint(targetPosition2D);


            // 2. Find tooth from target gear to us
            var myClosestToothCom  = myClosestTooth.CenterOfMassTransformed();
            var targetClosestTooth = target.GetToothClosestToPoint(myClosestToothCom);

            // 3. Check if they overlap
            if (Direction == 1)
            {
                if (LineMath.PenetrationOfAIntoB(myClosestTooth.CounterClockwiseLine.OutlineTransformed, targetClosestTooth.ClockwiseLine.OutlineTransformed, out var point))
                {
                    var adjustment = (MathHelper.TwoPi / target.NumberOfTeeth) / 300.0f;
                    target.Spin(adjustment * target.Direction);
                }
                else if (LineMath.PenetrationOfAIntoB(myClosestTooth.ClockwiseLine.OutlineTransformed, targetClosestTooth.CounterClockwiseLine.OutlineTransformed, out var point2))
                {
                    var adjustment = -(MathHelper.TwoPi / target.NumberOfTeeth) / 300.0f;
                    target.Spin(adjustment * target.Direction);
                }
            }
            // TODO: code path for when we rotate in the other direction
        }
コード例 #2
0
ファイル: LineMath.cs プロジェクト: nopponaim603/ProtoWorld
    public LineMath PerpendicularAtAPointOnLine(Vector3 point)
    {
        LineMath lm = new LineMath();

        // TODO Check if it on the line
        lm.p1 = point;
        if (IsNaNorIsInfinity(m))
        {
            var x = point.x + 1;
            var z = point.z;
            lm.p2 = new Vector3(x, point.y, z);
            return(lm);
        }
        else if (m != 0)
        {
            var perpM = -1 / m;
            var perpB = point.z - point.x * perpM;
            var x     = point.x + 5;
            var z     = perpM * x + perpB;
            lm.p2 = new Vector3(x, point.y, z);
            return(lm);
        }
        else
        {
            var x = point.x;
            var z = point.z + 1;
            lm.p2 = new Vector3(x, point.y, z);
            return(lm);
        }
    }
コード例 #3
0
ファイル: Gear.cs プロジェクト: roy-t/gear-physics
        public void Transfer(Gear to, float step)
        {
            var intersects        = false;
            var intersectionPoint = Vector2.Zero;

            for (var f = 0; f < this.Lines.Count; f++)
            {
                for (var t = 0; t < to.Lines.Count; t++)
                {
                    var fromLine = this.Lines[f];
                    var toLine   = to.Lines[t];

                    if (LineMath.Intersection(fromLine.OutlineTransformed, toLine.OutlineTransformed, out intersectionPoint))
                    {
                        intersects = true;
                        goto outside;
                    }
                }
            }

outside:
            if (intersects)
            {
                var ratio = this.Teeth / (float)to.Teeth;
                to.Spin(step * ratio);
            }
        }
コード例 #4
0
ファイル: LineScreen.cs プロジェクト: roy-t/gear-physics
        public void Update(GameTime gameTime, KeyboardState keyboard)
        {
            if (keyboard.IsKeyDown(Keys.Space))
            {
                LineList[0].Spin(0.75);
                //LineList[1].Spin(-0.75);
            }
            else
            {
                //LineList[0].Spin(0);
                //LineList[1].Spin(0);
            }

            for (var i = 0; i < LineList.Count; i++)
            {
                LineList[i].Update(gameTime);
            }

            var shortest     = LineMath.ShortestDistance(LineList[0].OutlineTransformed[0], LineList[0].OutlineTransformed[1], LineList[1].OutlineTransformed[0]);
            var shortestLine = LineMath.ShortestDistance(LineList[0].OutlineTransformed.ToArray(), LineList[1].OutlineTransformed.ToArray());

            Indicators.Clear();

            //Indicators.Add(new Shape(Device, Color.Green, PointToCross(LineList[1].OutlineTransformed[0], 0.2f), false));
            //Indicators.Add(new Shape(Device, Color.Pink, PointToCross(LineList[0].OutlineTransformed[0], 0.2f), false));
            //Indicators.Add(new Shape(Device, Color.Purple, PointToCross(LineList[0].OutlineTransformed[1], 0.2f), false));
            //Indicators.Add(new Shape(Device, Color.Orange, PointToCross(shortest, 0.4f), false));


            //Indicators.Add(new Shape(Device, Color.Yellow, PointToCross(shortestLine[0], 0.04f), false));
            //Indicators.Add(new Shape(Device, Color.Yellow, PointToCross(shortestLine[1], 0.04f), false));

            if (LineMath.Intersection(LineList[0].OutlineTransformed.ToArray(), LineList[1].OutlineTransformed.ToArray(), out var intersectionPoint))
            {
                Indicators.Add(new Shape(Device, Color.Yellow, PointToCross(intersectionPoint, 0.1f), false));

                // Proportional increase in angular velocity so that things get unstuck
                var d      = LineMath.PenetrationOfAIntoB(LineList[0].OutlineTransformed.ToArray(), intersectionPoint);
                var dRatio = d / LineList[0].Length;

                LineList[1].Spin(-LineList[0].AngularVelocity * (1.0 + dRatio));

                Console.WriteLine($"Penetration {d:F4}, L0: {LineList[0].AngularVelocity:F4}, L1: {LineList[1].AngularVelocity:F4}");

                // TODO: what if things intersect and the velocity of line 0 is 0, or quickly decreases?
            }
        }
コード例 #5
0
        private double?Gear(Line a, Line b, float amount)
        {
            // TODO leading on leading should add speed, while trailing on trailing should reduce speed
            if (LineMath.Intersection(a.OutlineTransformed.ToArray(), b.OutlineTransformed.ToArray(), out var intersectionPoint))
            {
                Indicators.Add(new Shape(Device, Color.Yellow, PointToCross(intersectionPoint, 0.1f), false));

                // Proportional increase in angular velocity so that things get unstuck
                var d      = LineMath.PenetrationOfAIntoB(a.OutlineTransformed.ToArray(), intersectionPoint);
                var dRatio = d / a.Length;

                var spin = -a.AngularVelocity * (1.0 + dRatio);

                return(amount);
            }

            return(null);
        }
コード例 #6
0
ファイル: LineMath.cs プロジェクト: nopponaim603/ProtoWorld
    public Vector3 Intersect(LineMath secondLine)
    {
        if (IsNaNorIsInfinity(m) && IsNaNorIsInfinity(secondLine.m)) // x=a1 and x=a2
        {
            // check if they are the same line, or parallel and have no intersection.
            if (p1.x == secondLine.p1.x)
            {
                // Same line, return either end of first line, or start of the second line
                return(p2);
            }
            else
            {
                return(new Vector3(float.NaN, float.NaN, float.NaN));
            }
        }
        else if (IsNaNorIsInfinity(m))
        {
            return(new Vector3(p1.x, p1.y, p1.x * secondLine.m + secondLine.b));
        }
        else if (IsNaNorIsInfinity(secondLine.m))
        {
            return(new Vector3(secondLine.p1.x, secondLine.p1.y, secondLine.p1.x * m + b));
        }
        else if (m == secondLine.m)
        {
            if (b == secondLine.b)
            {
                // Same line, return either end of first line, or start of the second line
                return(p2);
            }
            else
            {
                return(new Vector3(float.NaN, float.NaN, float.NaN));
            }
        }

        var     intersectionX = (secondLine.b - b) / (m - secondLine.m);
        var     intersectionZ = m * intersectionX + b;
        Vector3 intersection  = new Vector3(intersectionX, p1.y, intersectionZ);

        return(intersection);
    }
コード例 #7
0
ファイル: Rout.cs プロジェクト: pavadik/cnc_machine
        /// <summary>
        /// Returns the distance to the closest line on the rout
        /// </summary>
        /// <param name="p"></param>
        public virtual float DistanceTo(Vector2 p)
        {
            Box2 b = BoundingBox();

            if ((p.X > b.Right || p.X < b.Left) && (p.Y > b.Top || p.Y < b.Bottom))
            {
                return(float.PositiveInfinity);
            }

            float closest = float.PositiveInfinity;

            for (int i = 0; i < Points.Count; i++)
            {
                float l = LineMath.Length(Points[i], p);
                if (closest > l)
                {
                    closest      = l;
                    closestPoint = i;
                }
            }
            if (closest < width / 2)
            {
                closestIsPoint = true;
                return(closest);
            }
            closestIsPoint = false;

            closest = float.PositiveInfinity;
            for (int i = 0; i < (Points.Count - 1); i++)
            {
                float newValue = LineMath.DistanceTo(Points[i], Points[i + 1], p);
                if (newValue < closest)
                {
                    closest      = newValue;
                    closestPoint = i;
                }
            }
            return(closest);
        }
コード例 #8
0
        // To recognize a scribble we require the simplified line to reverse
        // direction at least three times. There are separate criteria for
        // erasing a shape currently being drawn and for erasing existing
        // shapes.
        //
        // The key difference between an "erase scribble" and a "cancel
        // scribble" is that an erase scribble starts out as such, while
        // a cancel scribble indicates that the user changed his mind, so
        // the line will not appear to be a scribble at the beginning.
        // The difference is detected by timestamps. For example, the
        // following diagram represents an "erase" operation and a "cancel"
        // operation. Assume the input points are evenly spaced in time,
        // and that the dots represent points where the input reversed
        // direction.
        //
        // Input points         ..........................
        // Reversals (erase)      .  .  .  .     .     .
        // Reversals (cancel)              .   .   .   .
        //
        // So, a scribble is considered an erasure if it satisfies t0 < t1,
        // where t0 is the time between mouse-down and the first reversal,
        // and t1 is the time between the first and third reversals. A cancel
        // operation satisfies t0 > t1 instead.
        //
        // Both kinds of scribble need to satisfy the formula LL*c > CHA,
        // where c is a constant factor in pixels, LL is the drawn line
        // length and CHA is the area of the Convex Hull that outlines the
        // drawn figure. This formula basically detects that the user
        // is convering the same ground repeatedly; if the pen reverses
        // direction repeatedly but goes to new places each time, it's not
        // considered an erasure scribble. For a cancel scribble, LL is
        // computed starting from the first reversal.
        IEnumerable <Shape> RecognizeScribbleForEraseOrCancel(DragState state, out bool cancel, out List <PointT> simplifiedSS)
        {
            cancel       = false;
            simplifiedSS = null;
            var tolerance    = state._inputTransform.Transform(new VectorT(0, 10)).Length();
            var simplifiedMP = LineMath.SimplifyPolyline(
                state.UnfilteredMousePoints.Select(p => p.Point), tolerance);
            List <int> reversals = FindReversals(simplifiedMP, 3);

            if (reversals.Count >= 3)
            {
                simplifiedSS = simplifiedMP.Select(p => state._inputTransform.Transform(p)).ToList();
                // 3 reversals confirmed. Now decide: erase or cancel?
                int[] timeStampsMs = FindTimeStamps(state.UnfilteredMousePoints, simplifiedMP);
                int   t0 = timeStampsMs[reversals[0]], t1 = timeStampsMs[reversals[2]] - t0;
                cancel = t0 > t1 + 500;

                // Now test the formula LL*c > CHA as explained above
                IListSource <PointT> simplifiedMP_ = cancel ? simplifiedMP.Slice(reversals[0]) : simplifiedMP.AsListSource();
                float LL   = simplifiedMP_.AdjacentPairs().Sum(pair => pair.A.Sub(pair.B).Length());
                var   hull = PointMath.ComputeConvexHull(simplifiedMP);
                float CHA  = PolygonMath.PolygonArea(hull);
                if (LL * EraseNubWidth > CHA)
                {
                    // Erasure confirmed.
                    if (cancel)
                    {
                        return(EmptyList <Shape> .Value);
                    }

                    // Figure out which shapes to erase. To do this, we compute for
                    // each shape the amount of the scribble that overlaps that shape.
                    var simplifiedSS_ = simplifiedSS;
                    return(_doc.Shapes.Where(s => ShouldErase(s, simplifiedSS_)).ToList());
                }
            }
            return(null);
        }
コード例 #9
0
    void UpdateBegun()
    {
        var blockPoses = LineMath.IntegerPoints(lastMousePosition, mousePosition);

        if (blockPoses.Count > 0)
        {
            Vector2Int lastBlockPos = Vector2Int.zero;
            foreach (var blockPos in blockPoses)
            {
                Direction direction = BlockDirection(lastBlockPos, blockPos);
                int       xStep     = 0;
                int       yStep     = 0;
                switch (direction)
                {
                case Direction.East:
                    xStep = 1;
                    break;

                case Direction.South:
                    yStep = -1;
                    break;

                case Direction.West:
                    xStep = -1;
                    break;

                case Direction.North:
                    yStep = 1;
                    break;
                }
                int          x            = blockPos.x;
                int          y            = blockPos.y;
                List <Block> blocksToMove = new List <Block> ();
                for (var block = board.GetDisplayBlock(x, y);
                     block != null && block != begunBlock;
                     x += xStep, y += yStep, block = board.GetDisplayBlock(x, y))
                {
                    blocksToMove.Add(block);
                }
                foreach (var block in blocksToMove)
                {
                    block.DisplayX += xStep;
                    block.DisplayY += yStep;
                }
                lastBlockPos = blockPos;
            }
            begunBlock.DisplayX = lastBlockPos.x;
            begunBlock.DisplayY = lastBlockPos.y;
            var blockMoved = true;
            while (blockMoved)
            {
                blockMoved = false;
                foreach (var block in board.GetBlocks())
                {
                    if (block != begunBlock)
                    {
                        if (block.DisplayX != block.X)
                        {
                            var dist    = block.X - block.DisplayX;
                            var desired = block.DisplayX + dist / Mathf.Abs(dist);
                            if (board.GetDisplayBlock(desired, block.DisplayY) == null)
                            {
                                block.DisplayX = desired;
                                blockMoved     = true;
                            }
                        }
                        if (block.DisplayY != block.Y)
                        {
                            var dist    = block.Y - block.DisplayY;
                            var desired = block.DisplayY + dist / Mathf.Abs(dist);
                            if (board.GetDisplayBlock(block.DisplayX, desired) == null)
                            {
                                block.DisplayY = desired;
                                blockMoved     = true;
                            }
                        }
                    }
                }
            }
        }

        if (Input.GetMouseButtonUp(0))
        {
            if (board.WithinBoundary(begunBlock.DisplayX, begunBlock.DisplayY))
            {
                var blocksToRemove = new List <Block> ();
                foreach (var block in board.GetBlocks())
                {
                    if (!board.WithinBoundary(block.DisplayX, block.DisplayY))
                    {
                        blocksToRemove.Add(block);
                    }
                    else
                    {
                        if (block.DisplayX != block.X || block.DisplayY != block.Y)
                        {
                            block.OnFire         = false;
                            block.OnWarning      = false;
                            block.NoFireCount    = 0;
                            block.OnWarningCount = 0;
                        }
                        block.SetAllPosition(block.DisplayX, block.DisplayY);
                    }
                }
                foreach (var block in blocksToRemove)
                {
                    board.RemoveBlock(block);
                    block.gameObject.SetActive(false);
                    Destroy(block.gameObject);
                }
                soundManager.PlayDrop();
            }
            else
            {
                board.RemoveBlock(begunBlock);
                prepareArea.AddBlock(begunBlock);
                foreach (var block in board.GetBlocks())
                {
                    block.SetAllPosition(block.X, block.Y);
                }
            }
            begunBlock = null;
            state      = State.Idle;
        }
    }