AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77812297
Accepted
user366312
user366312
Asked: 2024-01-14 00:58:48 +0800 CST2024-01-14 00:58:48 +0800 CST 2024-01-14 00:58:48 +0800 CST

A função não consegue detectar interseções de duas curvas

  • 772

O código-fonte abaixo deve encontrar uma interseção entre duas curvas.

No entanto, a função não consegue detectar o ponto de intersecção.

Como posso consertar isso?

insira a descrição da imagem aqui

using MathNet.Numerics.Interpolation;
using System.Collections.Generic;
using System.Linq;

public static Vec2 FindIntersectionOfTwoCurves(List<double> xList1, List<double> yList1,
                                               List<double> xList2, List<double> yList2)
{
    if (xList1 == null || yList1 == null || xList2 == null || yList2 == null ||
        xList1.Count != yList1.Count || xList2.Count != yList2.Count)
        return null;

    IInterpolation interpolation1 = Interpolate.Linear(xList1, yList1);
    IInterpolation interpolation2 = Interpolate.Linear(xList2, yList2);

    double lowerBound = Math.Max(xList1.Min(), xList2.Min());
    double upperBound = Math.Min(xList1.Max(), xList2.Max());

    double step = (upperBound - lowerBound) / 1000; // adjust the step size as needed
    for (double x = lowerBound; x <= upperBound; x += step)
    {
        double y1 = interpolation1.Interpolate(x);
        double y2 = interpolation2.Interpolate(x);

        if (Math.Abs(y1 - y2) < 1e-7)
        {
            return new Vec2(x, y1);
        }
    }

    return null;
}

public class Vec2
{
    public double X { get; set; }
    public double Y { get; set; }

    public Vec2(double x, double y)
    {
        X = x;
        Y = y;
    }
}
c#
  • 2 2 respostas
  • 87 Views

2 respostas

  • Voted
  1. Best Answer
    Ahmed AEK
    2024-01-14T01:54:39+08:002024-01-14T01:54:39+08:00

    como você está tentando encontrar uma interseção de duas curvas com uma primeira derivada não contínua, você deve usar o método Bisection .

    uma implementação C# escrita rapidamente é a seguinte, a implementação da pesquisa binária é daqui , a pesquisa binária pode ser substituída por uma interpolação linear mais simples se Xfor linearmente espaçada.

    namespace ConsoleApp2
    {
        public class LinearInterpolator
        {
            private static int BinarySearch<T>(IList<T> list, T value)
            {
                if (list == null)
                    throw new ArgumentNullException("list");
                var comp = Comparer<T>.Default;
                int lo = 0, hi = list.Count - 1;
                while (lo < hi)
                {
                    int m = (hi + lo) / 2;  // this might overflow; be careful.
                    if (comp.Compare(list[m], value) < 0) lo = m + 1;
                    else hi = m - 1;
                }
                if (comp.Compare(list[lo], value) < 0) lo++;
                return lo;
            }
    
            private static int FindFirstIndexGreaterThanOrEqualTo<T>
                                      (List<T> sortedList, T key)
            {
                return BinarySearch(sortedList, key);
            }
    
            List<double> x_values;
            List<double> y_values;
            public LinearInterpolator(List<double> x, List<double> y)
            {
                // quick argsort
                List<int> indicies = x.AsEnumerable().Select((v,i) => new {obj = v, index = i}).OrderBy(c=> c.obj).Select(c => c.index).ToList();
                x_values = indicies.Select(i => x[i]).ToList();
                y_values = indicies.Select(i => y[i]).ToList();
            }
    
            public double Interpolate(double x)
            {
                int index = FindFirstIndexGreaterThanOrEqualTo(x_values, x);
                if (index == 0)
                {
                    return y_values[0];
                }
                double y1 = y_values[index-1];
                double y2 = y_values[index];
                double x1 = x_values[index-1];
                double x2 = x_values[index];
                return (x - x1) / (x2 - x1) * (y2 - y1) + y1;
            }
    
        }
    
        class IntersectionFinder
        {
            public static Nullable<(double,double)> FindIntersectionOfTwoCurves(List<double> xList1, List<double> yList1,
                                                       List<double> xList2, List<double> yList2)
            {
                if (xList1 == null || yList1 == null || xList2 == null || yList2 == null ||
                    xList1.Count != yList1.Count || xList2.Count != yList2.Count)
                    return null;
    
                LinearInterpolator interpolator1 = new LinearInterpolator(xList1, yList1);
                LinearInterpolator interpolator2 = new LinearInterpolator(xList2, yList2);
    
                double lowerBound = Math.Max(xList1.Min(), xList2.Min());
                double upperBound = Math.Min(xList1.Max(), xList2.Max());
    
                if (lowerBound > upperBound) // X axes don't overlap
                {
                    return null;
                }
    
                double diff_start = interpolator1.Interpolate(lowerBound) - interpolator2.Interpolate(lowerBound);
                double diff_end = interpolator1.Interpolate(upperBound) - interpolator2.Interpolate(upperBound);
    
                if ((diff_start > 0 && diff_end > 0) || (diff_start < 0 && diff_end < 0)) // intersection doesn't exist
                {
                    return null;
                }
    
                double mid = (lowerBound + upperBound) / 2;
                double diff_mid = interpolator1.Interpolate(mid) - interpolator2.Interpolate(mid);
    
                int iterations = 0;
                while (Math.Abs(diff_mid) > 1e-7)
                {
                    if (diff_start > diff_end) // list1 is higher
                    {
                        if (diff_mid > 0) // mid is also higher, intersection in right side
                        {
                            lowerBound = mid;
                            diff_start = diff_mid;
                        }
                        else // mid is lower, intersection in left side
                        {
                            upperBound = mid;
                            diff_end = diff_mid;
                        }
                    }
                    else // list 2 is higher
                    {
                        if (diff_mid < 0) 
                        {
                            lowerBound = mid;
                            diff_start = diff_mid;
                        }
                        else 
                        {
                            upperBound = mid;
                            diff_end = diff_mid;
                        }
                    }
                    mid = (lowerBound + upperBound) / 2;
                    diff_mid = interpolator1.Interpolate(mid) - interpolator2.Interpolate(mid);
                    iterations++;
                    if (iterations > 10000) // prevent infinite loop if Y is discontinuous
                    {
                        return null;
                    }
                }
    
                return new (mid, interpolator1.Interpolate(mid));
            }
        }
    
        internal class Program
        {
            static void Main(string[] args)
            {
                List<double> xList1 = [ 1, 1.5, 2, 3.5, 4 ];
                List<double> xList2 = [ 1, 2, 3, 4, 5 ];
                List<double> yList1 = [ 0, 2, 4, 6,  8 ];
                List<double> yList2 = [ 8, 6, 4, 2, 0 ];
                Console.WriteLine(IntersectionFinder.FindIntersectionOfTwoCurves(xList1, yList1, xList2, yList2).ToString());
            }
        }
    }
    
    (2.5999999940395355, 4.799999992052714)
    

    insira a descrição da imagem aqui

    • 1
  2. Wyck
    2024-01-14T01:57:47+08:002024-01-14T01:57:47+08:00

    Esta pequena mudança pode resolver seu problema. Não espere que Math.Abs(y1 - y2)seja menor que algum épsilon (por exemplo 1e-7). Em vez disso, observe o sinal de y1 - y2mudança para que seja diferente da iteração anterior. Isso é chamado de procurar um cruzamento zero .

    Por exemplo:

    int? prevSign = null;
    for (double x = lowerBound; x <= upperBound; x += step) {
        double y1 = interpolation1.Interpolate(x);
        double y2 = interpolation2.Interpolate(x);
        int sign = Math.Sign(y1 - y2);
        if (prevSign.HasValue) {
            if (sign != prevSign.Value) {
                return new Vec2(x, y1);
            }
        } else {
            prevSign = sign;
        }
    }
    
    • 1

relate perguntas

  • Polly DecorrelatedJitterBackoffV2 - como calcular o tempo máximo necessário para concluir todas as novas tentativas?

  • Wpf. Role o DataGrid dentro do ScrollViewer

  • A pontuação que ganhei na página do jogo com .NET MAUI MVVM não é visível em outras páginas. Como posso manter os dados de pontuação no dispositivo local

  • Use a hierarquia TreeView com HierarchicalDataTemplate de dentro de um DataTemplate

  • Como posso melhorar essa interface de validação no .NET?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve