Các điểm cách đều nhau dọc theo một đường cong bezier


10

Tôi đã nhìn xung quanh một lúc và tôi không thể tìm ra giải pháp cho vấn đề này. Giả sử tôi có một đường cong hình khối (được xác định bởi 4 điểm) và tôi muốn có được một tập hợp các điểm được đặt cách đều nhau dọc theo đường cong. Hãy nghĩ về việc đặt một văn bản dọc theo một đường cong cho một ví dụ.

Bây giờ vấn đề là nếu tôi nhập t(giá trị nội suy từ 0-1) với gia số không đổi thì các điểm không cách đều nhau. Khoảng cách dọc theo đường cong nhỏ hơn khi đường cong rẽ và dài hơn khi đường cong thẳng.

Vì vậy, làm thế nào để tôi đặt điểm đều dọc theo một đường cong bezier?


4
Bạn đang tìm kiếm một giải pháp "hoàn toàn toán học" (hoặc đặc biệt hiệu quả)? Mặt khác, cách tiếp cận đơn giản là: Chuyển đổi đường cong thành một đường đa tuyến, bằng cách đi dọc theo đường cong, tăng, ttrong 100 bước và đo khoảng cách giữa các điểm kết quả. Sau đó, nội suy dọc theo polyline này như mong muốn.
Marco13

Tôi nghĩ rằng bạn đang tìm kiếm từ khóa "tham số chiều dài cung", đã được trả lời ví dụ trong câu hỏi này .
wonderra

Những gì @ Marco13 nói!
david van brink

Theo các câu trả lời / bình luận, cách tiếp cận mà tôi đề cập không chỉ đơn giản mà còn khá phổ biến. Đây có phải là một ngôn ngữ cụ thể? Có lẽ ai đó sẽ đăng một vài dòng mã sau đó ...
Marco13

Câu trả lời:


3

Đó là nhiều hơn một câu hỏi toán học. Vì vậy, một đường cong bezier có công thức sau , cả trong xythành phần.

B_x(t) = (1-t)^3 * P0_x + (1-t)^2 * t * P1_x + (1-t) * t^2 * P2_x + t^3 * P3_x
B_y(t) = (1-t)^3 * P0_y + (1-t)^2 * t * P1_y + (1-t) * t^2 * P2_x + t^3 * P3_y

Độ dài di chuyển tdọc theo một đường cong gammađược cho bởi:

length_gamma(t) = integration( sqrt( derivative(  gamma_x(s)  ) ^2 + derivative(  gamma_y(s)  ) ^2 ) )

Không có giải pháp nào có thể ghi được cho con người cho tích phân, vì vậy bạn phải tính gần đúng.

Thay thế gamma(t)biểu thức B(t)để có được độ dài length_Bdi chuyển tdọc theo đoạn bezier. Hãy nói rằng nó đi từ 0đếnL .

Bây giờ chọn ncác giá trị giữa 0Ltương ứng với các điểm cách đều nhau. Ví dụ: độ dài của biểu mẫu k*L/ncho ktừ 0đếnn .

Bây giờ bạn cần nghịch đảo hàm length_B, vì vậy bạn có thể tính toán mặt tsau từ độ dài l. Đó là khá nhiều toán học và tôi lười biếng như địa ngục, hãy thử tự làm nó. Nếu bạn không thể, bạn có thể đi đến stackexchange toán học . Để có câu trả lời đầy đủ hơn, dù sao bạn cũng có thể đến đó.

Khi bạn có hàm nghịch đảo đó length_B(hoặc xấp xỉ hợp lý), bạn xử lý khá đơn giản.

  • Tạo độ dài l[k]của khoảng cách đường dẫn đã cho từ gốc(P0_x,P1_x) .
  • Tính toán tương ứng của họ t[k]bằng cách sử dụnglength_B_inverse .
  • Đặt điểm sử dụng (B_x(t[k]),B_y(t[k])).

1
Cảm ơn bạn! Hóa ra toán học bạn cần để tích hợp đa thức bernstein là một cơn ác mộng. Tôi đã có thể sử dụng giải pháp
foaly 4/2/2017


0

Chỉ để mở rộng những gì Marco nói, một kỹ thuật phổ biến để thực hiện điều này là đi xuống đường cong với bước tăng nhỏ hơn nhiều so với các bước có độ dài cố định mà bạn muốn thực hiện và lưu trữ điểm đầu ra kết quả (và có lẽ là khoảng cách?) Trong một bảng.

Sau đó, bạn đi qua bảng và loại bỏ tất cả các mục ngoại trừ những điểm gần nhất với bội số nguyên của khoảng cách bạn muốn đi bộ.

Sau đó, bạn còn lại một bảng bạn có thể lập chỉ mục trực tiếp trong thời gian chạy rất nhanh. Nếu bạn muốn đi đến điểm gấp 5 lần kích thước khoảng cách bạn nhìn trong bảng của mình tại chỉ mục [5].

Lưu ý rằng bạn có thể thực hiện hai bước trong một và không thực sự lưu trữ các mục bổ sung trong bảng để bắt đầu, nhưng sẽ dễ hình dung và hiểu hơn trong hai bước.

Tôi đã từng thấy một kỹ thuật thực sự tính toán điều này một cách nhanh chóng mà không cần tính toán trước một bảng (nó cũng không sử dụng tìm kiếm lặp / gốc!), Nhưng thật không may là tôi không thể nhớ chi tiết nào cả):

Nếu tôi nhớ nó hoặc tìm thấy nó, tôi sẽ đăng thông tin!


1
điều này cũng có thể khiến bạn quan tâm: math.stackexchange.com/questions/15896/iêu
Alan Wolfe

0

Bước 1 - Tạo điểm N + 1 bằng cách nội suy đường cong theo gia số 1 / N. N phải đủ lớn để có kết quả hình ảnh tốt nhưng đủ nhỏ để dễ dàng tính toán. Giá trị 50 sẽ ổn đối với hầu hết các tình huống nhưng nó phải được điều chỉnh cho trường hợp cụ thể của bạn. Tôi sẽ gọi đây là "điểm nội suy".

Ngoài ra, bạn có thể tạo một danh sách ngắn các phân đoạn và phá vỡ đệ quy từng phân đoạn dài hơn độ dài phân khúc tối đa mong muốn (ban đầu bạn nên tạo ít nhất bốn phân đoạn để giải thích cho các đường cong S nơi bắt đầu rất gần cuối).

Bước 2 - "Đi bộ trên đường" bằng cách sử dụng các điểm được nội suy và khoảng cách bạn muốn giữa mỗi điểm.

Tôi sẽ để nó ở đây mã Unity của tôi:

public static Vector2[] InterpolateBezier(Vector2 start, Vector2 startControlPoint,
    Vector2 end, Vector2 endControlPoint, int segments)
{
    Vector2[] interpolated = new Vector2[segments + 1];
    interpolated[0] = start;
    interpolated[segments] = end;

    float step = 1f / segments;
    for (int i = 1; i < segments; i++)
    {
        interpolated[i] = GetBezierPosition(start, startControlPoint, end,
            endControlPoint, i * step);
    }

    return interpolated;
}

public static Vector2 GetBezierPosition(Vector2 start, Vector2 startControlPoint,
    Vector2 end, Vector2 endControlPoint, float t)
{
    float omt = 1f - t;
    float omt2 = omt * omt;
    float t2 = t * t;

    return
        start * (omt2 * omt) +
        startControlPoint * (3f * omt2 * t) +
        endControlPoint * (3f * omt * t2) +
        end * (t2 * t);
}

public static List<Vector2> WalkLine(Vector2[] points, float spacing, float offset = 0)
{
    List<Vector2> result = new List<Vector2>();

    spacing = spacing > 0.00001f ? spacing : 0.00001f;

    float distanceNeeded = offset;
    while (distanceNeeded < 0)
    {
        distanceNeeded += spacing;
    }

    Vector2 current = points[0];
    Vector2 next = points[1];
    int i = 1;
    int last = points.Length - 1;
    while (true)
    {
        Vector2 diff = next - current;
        float dist = diff.magnitude;

        if (dist >= distanceNeeded)
        {
            current += diff * (distanceNeeded / dist);
            result.Add(current);
            distanceNeeded = spacing;
        }
        else if (i != last)
        {
            distanceNeeded -= dist;
            current = next;
            next = points[++i];
        }
        else
        {
            break;
        }
    }

    return result;
}

-1

Đây là một số thuật toán cho kết quả khá ok:

  Point Index(float pos) const
  {
    int count = p.NumPoints();
    Vector val(0.0,0.0,0.0);
    for(int i=0;i<count;i++)
      { 
        val += bin(pos,i,count-1)*Vector(p.Points(i));
      }
    return Point(val);
  }
  float bin(float pos, int i, int n) const
  { 
    return float(ni(n,i)) * pow(double(pos), double(i))*pow(double(1.0-pos), double(n-i));
  }
  int ni(int n, int i) const
  {
    if (i==0) { return 1; }
    if (n==i) { return 1; }
    return ni(n-1,i-1)+ni(n-1,i);
  }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.