سؤال

أنا أرسم الرسوم البيانية في WinForms Picturebox. الآن أنا أبحث عن إمكانية "تكرار" خط (مجموعة من النقاط) ، بحيث يتم وضع الخطين الناتج على مسافة ثابتة بعيدًا عن الخط الأصلي. كما في هذه الصورة ، لدي الخط الأحمر وأريد الحصول على الأسود:

صورة الخطوط http://img227.imageshack.us/img227/2341/linesb.png

فكرت في مجرد تحريك الخط بضع وحدات بكسل للأعلى/اليمين/الصدارة ، ولكن هذا يؤدي إلى خطوط متداخلة غريبة.

هل هناك أي نهج آخر يفعل ما أريد؟ اي افكار يمكن ان تكون رائعه للعرض. شكرًا!

هل كانت مفيدة؟

المحلول

لقد قمت بإنشاء وظيفة تعمل بالضبط ما تحتاجه قبل بضعة أشهر كجزء من خوارزمية تخطيط الرسم البياني. كتبت ذلك في بيثون و pyqt. لقد لصق الرمز للتو هنا في Codepad. يجب أن يكون من السهل جدًا ترجمة C#.

تحديث:

ترجمته واحدًا إلى واحد من مقتطف بيثون الخاص بي (أحب أن أفعل ذلك الرسومات :)). نظرًا لأن الكود الأصلي الخاص بي قد تم تصميمه لأكثر من خطين للإخراج ، فقد أخذت ذلك في إصدار C# أيضًا. لخطين أسود يكون 20 بكسل بعيدا عن الحمراء ، فقط مرر width = 40 و num = 2. يمثل الصفيف المسدوب الذي تم إرجاعه مجموعة من الخطوط (الصفيف الخارجي) ، مع تمثيل كل سطر بمجموعة من النقاط (الداخلية).

public PointF[][] MultiplyLine(PointF[] line, int width, int num)
{
    if (num == 1) return new PointF[][] { line };
    if (num < 1) throw new ArgumentOutOfRangeException();
    if (line.Length < 2) return Enumerable.Range(0, num)
                  .Select(x => line).ToArray();

    Func<float, float, PointF> normVec = (x, y) => {
        float len = (float)Math.Sqrt((double)(x * x + y * y));
        return len == 0 ? new PointF(1f, 0f) : new PointF(x / len, y / len);
    };

    PointF[][] newLines = Enumerable.Range(0, num)
                  .Select(x => new PointF[line.Length]).ToArray();

    float numinv = 1f / (float)(num - 1), cor = 0f;
    PointF vec1 = PointF.Empty, vec2 = PointF.Empty, vec3 = PointF.Empty;

    int j = -1, i = -1;
    foreach (PointF p in line)
    {
        bool first = j == -1, last = j == line.Length - 2; j++;

        if (!last)
            vec1 = normVec(line[j + 1].Y - p.Y, -line[j + 1].X + p.X);
        if (!first)
            vec2 = normVec(-line[j - 1].Y + p.Y, line[j - 1].X - p.X);
        if (!first && !last)
        {
            vec3 = normVec(vec1.X + vec2.X, vec1.Y + vec2.Y);
            cor = (float)Math.Sin((Math.PI - 
                  Math.Acos(vec1.X * vec2.X + vec1.Y * vec2.Y)) / 2);
            cor = cor == 0 ? 1 : cor;
            vec3 = new PointF(vec3.X / cor, vec3.Y / cor);
        }

        i = -1;
        foreach (PointF[] newLine in newLines)
        {
            i++; cor = (float)width * ((float)i * numinv - 0.5f);
            vec1 = first ? vec1 : last ? vec2 : vec3;
            newLine[j] = new PointF(vec1.X * cor + p.X, vec1.Y * cor + p.Y);
        }
    }

    return newLines;
}

لتجربتها ، أخذت هذه العينة الصغيرة (نفس العينة كما في رمز PYQT الخاص بي):

PointF[] pts = new PointF[] { 
    new PointF(100f, 100f), new PointF(300f, 200f), 
    new PointF(500f, 200f), new PointF(300f, 500f), 
    new PointF(600f, 450f), new PointF(650f, 180f), 
    new PointF(800f, 180f), new PointF(800f, 500f), 
    new PointF(200f, 700f)
};

pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using(Graphics g = Graphics.FromImage(pictureBox1.Image)){
    g.DrawLines(new Pen(Color.Red), pts);

    foreach (PointF[] line in MultiplyLine(pts, 80, 14))
        g.DrawLines(new Pen(Color.Black), line);
}

مما أدى إلى هذا الرسم:

الخطوط العريضة حول الخط http://img41.imageshack.us/img41/8606/lines2.th.png

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top