1
votes

Comment produire des paires de coordonnées d'un point de départ à un point final?

Je souhaite créer des paires de coordonnées illustrant un chemin entre deux points. Si elle est disponible, la fonction doit d'abord créer un chemin diagonal, puis les coordonnées restantes doivent être verticales ou horizontales.

J'ai calculé les valeurs absolues X et Y entre deux points. Ensuite, si X ou Y est supérieur à zéro, la fonction le diminue et donne le résultat.

  // Start point (10, 10), end point (5, 3)
  // Actual results: 
  [2, -2]
  [3, -1]
  [4, 0]
  [5, 1]
  [5, 2]
  [5, 3]

  // Desired: 
  [10, 10]
  [9, 9]
  [8, 8]
  [7, 7]
  [6, 6]
  [5, 5]
  [5, 4]
  [5, 3]

  // If I reverse start and end points the result is as expected:
  [5, 3]
  [6, 4]
  [7, 5]
  [8, 6]
  [9, 7]
  [10, 8]
  [10, 9]
  [10, 10]

Le problème ici est si le point de départ est plus éloigné de l'origine que la fin point que cela ne fonctionne pas.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var start = new Point(10, 10);
            var end = new Point(5, 3);
            var coordinates = new List<Point>(Coordinates(start, end));
            foreach (var coord in coordinates)
            {
                Console.WriteLine("[" + coord.X + ", " + coord.Y + "]");
            }
            Console.ReadKey();
        }

        public static IEnumerable<Point> Coordinates(Point start, Point end)
        {
            var difX = Math.Abs(end.X - start.X + 1);
            var difY = Math.Abs(end.Y - start.Y + 1);
            var iterations = (difX > difY) ? difX : difY;
            for (var i = 0; i < iterations; i++)
            {
                if (difX > 0)
                {
                    difX--;
                }

                if (difY > 0)
                {
                    difY--;
                }
                yield return new Point(end.X - difX, end.Y - difY);
            }
        }
    }

    internal struct Point
    {
        public double X { get; set; }
        public double Y { get; set; }

        public Point(double x, double y)
        {
            X = x;
            Y = y;
        }
    }
}


5 commentaires

Pourriez-vous fournir un exemple avec les résultats souhaités et réels?


LineDDA effectuera ce travail pour code non géré. Je ne sais pas s'il existe un équivalent géré.


@DmitryBychenko J'ai ajouté un exemple.


@Jacop: faute de frappe? La 1ère séquence commence à partir de [10, 10] (le point initial n'est pas inclus) lorsque la deuxième commence à partir de [5, 3] est inclus.


@DmitryBychenko Désolé, je l'ai manqué, j'ai édité la question.


3 Réponses :


0
votes

Vous Math.Abs ​​lorsque vous calculez combien vous avez besoin de pas, ce qui perd le sens de votre pas et tous vos chemins ne peuvent donc avancer que dans une direction positive. Au lieu de cela, gardez le pas comme positif ou négatif:

    public static IEnumerable<Point> Coordinates(Point start, Point end)
    {
        int difX = end.X - start.X;
        int difY = end.Y - start.Y;
        var iterations = (difX > difY) ? difX : difY;

        //reduce the stepping to either +1 or -1 for each 
        difX = difX/Math.Abs(difX);
        difY = difY/Math.Abs(difY);

        //start off one behind, because we'll increment in the loop
        int newX = start.X - difX; 
        int newY = start.Y - difY;

        //now when you loop, only apply the stepping if you didnt already reach the end
        for (var i = 0; i < iterations; i++)
        {
            //only move if we didn't reach the end
            if(newX != end.X) 
              newX += difX;
            if(newY != end.Y)
              newY += difY;

            yield return new Point(newX, newY);
        }
    }


4 commentaires

Ne serait-ce pas une ligne droite entre les points? D'après la description, OP donne, je pensais qu'il voulait un angle de 45 ° jusqu'à ce qu'un "mur" soit touché, puis 0 ° ou 90 ° respectivement pour le reste du chemin (si cela a du sens).


@Fildor oui c'est ça. J'aurais dû mieux le formuler.


(Le concept est le même, mais au lieu d'utiliser des étapes fractionnaires, arrêtez de pas à pas lorsque x ou y est égal à la fin)


Ajustement du code; essentiellement les mêmes que les autres solutions maintenant, l'esprit



0
votes

AVIS DE NON-RESPONSABILITÉ: non testé!

Voici comment j'aborderais ceci:

public static IEnumerable<Point> Coordinates(Point start, Point end)
{
    double dirX = start.X < end.X ? +1 : -1;
    double dirY = start.Y < end.Y ? +1 : -1;

    double x = start.X;
    double y = start.Y;

    do
    {
        if (!coordsEqual(x, end.X)) x = x+dirX;
        if (!coordsEqual(y, end.Y)) x = y+dirY;
        yield return new Point(x,y);
    }while( !shouldStop(x,y,end) );
}

static bool shouldStop( double x, double y, Point target )
{
    // Basically x == end.X && y == end.Y , just considering floating point issues.
    return coordsEqual( x, target.X ) && coordsEqual( y, target.Y );
}

static bool coordsEqual( double d1, double d2 )
{
    // TODO
}

Attention, j'ai laissé du travail à faire. Vérifier l'égalité sur les doubles a pas mal de pièges, donc je vous ai laissé le soin d'en savoir plus.

BTW: Vous semblez n'utiliser que des valeurs entières. La vérification de l'égalité est beaucoup plus facile si vous utilisez int au lieu de double.


0 commentaires

0
votes

Une simple boucle en vérifiant si nous atteignons le point end ou non:

Code:

{X=10,Y=10} 
{X=9,Y=9}
{X=8,Y=8}
{X=7,Y=7}
{X=6,Y=6}
{X=5,Y=5}
{X=5,Y=4}
{X=5,Y=3}

{X=5,Y=3} 
{X=6,Y=4}
{X=7,Y=5}
{X=8,Y=6}
{X=9,Y=7}
{X=10,Y=8}
{X=10,Y=9}
{X=10,Y=10}   

Démo: strong> p>

Console.WriteLine(string.Join(Environment.NewLine, 
  Coordinates(new Point(10, 10), new Point(5, 3))));

Console.WriteLine();

Console.WriteLine(string.Join(Environment.NewLine, 
  Coordinates(new Point(5, 3), new Point(10, 10))));


1 commentaires

@Jacop: Vous êtes les bienvenus! Cependant, devons-nous inclure ou exclure le point de départ (ou l’inclure dans certains cas uniquement)?