freeCodeCamp/curriculum/challenges/ukrainian/10-coding-interview-prep/rosetta-code/sutherland-hodgman-polygon-...

5.5 KiB
Raw Blame History

id title challengeType forumTopicId dashedName
5a23c84252665b21eecc8045 Відсікання багатокутників алгоритмом Сазерленд-Ходжман 5 302336 sutherland-hodgman-polygon-clipping

--description--

[ алгоритм відсікання Сазерленд-Ходжман ](https://en.wikipedia.org/wiki/Sutherland-Hodgman clipping algorithm)знаходить багатокутники, які перетинаються між довільним багатокутником( "багатокутник-об'єкт") і опуклим багатокутником (" багатокутником який потрібно відсікти"). Це використовується в комп'ютерній графіці(особливо у 2D графіці), щоб зменшити складність відображення сцен шляхом усунення частин багатокутника, який не повинен відображатися. Візьміть замкнутий багатокутник, визначений точками:

[(50, 150), (200, 50), (350, 150), (350, 300), (250, 300), (200, 250), (150, 350), (100, 250), (100, 200)]

і обріжте його за допомогою прямокутника, визначеного точками:

[(100, 100), (300, 100), (300, 300), (100, 300)]

--instructions--

Напишіть функцію, яка врахує 2 масиви як параметр. Перший масив вміщує у собі точки багатокутника-суб'єкта, а другий містить точки багатокутника, що відсікається. Функція має повернути масив, який вміщує точки відсіченого багатокутника. Кожне число має бути округлене до 3-х десяткових знаків після коми.

--hints--

clip має бути функцією.

assert(typeof clip == 'function');

clip([[50, 150], [200, 50], [350, 150], [350, 300], [250, 300], [200, 250], [150, 350], [100, 250], [100, 200]], [[100, 100], [300, 100], [300, 300], [100, 300]]) має повернути масив.

assert(
  Array.isArray(
    clip(
      [
        [50, 150],
        [200, 50],
        [350, 150],
        [350, 300],
        [250, 300],
        [200, 250],
        [150, 350],
        [100, 250],
        [100, 200]
      ],
      [
        [100, 100],
        [300, 100],
        [300, 300],
        [100, 300]
      ]
    )
  )
);

clip([[50, 150], [200, 50], [350, 150], [350, 300], [250, 300], [200, 250], [150, 350], [100, 250], [100, 200]], [[100, 100], [300, 100], [300, 300], [100, 300]]) має повернути [[100, 116.667], [125, 100], [275, 100], [300, 116.667], [300, 300], [250, 300], [200, 250], [175, 300], [125, 300], [100, 250]].

assert.deepEqual(
  clip(
    [
      [50, 150],
      [200, 50],
      [350, 150],
      [350, 300],
      [250, 300],
      [200, 250],
      [150, 350],
      [100, 250],
      [100, 200]
    ],
    [
      [100, 100],
      [300, 100],
      [300, 300],
      [100, 300]
    ]
  ),
  [
    [100, 116.667],
    [125, 100],
    [275, 100],
    [300, 116.667],
    [300, 300],
    [250, 300],
    [200, 250],
    [175, 300],
    [125, 300],
    [100, 250]
  ]
);

clip([[150, 200], [400, 450], [30, 50]], [[10, 10], [300, 200], [400, 600], [100, 300]]) має повернути [[150, 200], [350, 400], [348.611, 394.444], [30, 50]].

assert.deepEqual(
  clip(
    [
      [150, 200],
      [400, 450],
      [30, 50]
    ],
    [
      [10, 10],
      [300, 200],
      [400, 600],
      [100, 300]
    ]
  ),
  [
    [150, 200],
    [350, 400],
    [348.611, 394.444],
    [30, 50]
  ]
);

clip([[250, 200], [100, 450], [130, 250]], [[50, 60], [100, 230], [400, 600], [100, 300]])має повернути[[129.167, 329.167], [119.565, 319.565], [121.854, 304.305]].

assert.deepEqual(
  clip(
    [
      [250, 200],
      [100, 450],
      [130, 250]
    ],
    [
      [50, 60],
      [100, 230],
      [400, 600],
      [100, 300]
    ]
  ),
  [
    [129.167, 329.167],
    [119.565, 319.565],
    [121.854, 304.305]
  ]
);

--seed--

--seed-contents--

function clip(subjectPolygon, clipPolygon) {

}

--solutions--

function clip(subjectPolygon, clipPolygon) {
  var cp1, cp2, s, e, i, j;
  var inside = function(p) {
    return (
      (cp2[0] - cp1[0]) * (p[1] - cp1[1]) > (cp2[1] - cp1[1]) * (p[0] - cp1[0])
    );
  };
  var intersection = function() {
    var dc = [cp1[0] - cp2[0], cp1[1] - cp2[1]],
      dp = [s[0] - e[0], s[1] - e[1]],
      n1 = cp1[0] * cp2[1] - cp1[1] * cp2[0],
      n2 = s[0] * e[1] - s[1] * e[0],
      n3 = 1.0 / (dc[0] * dp[1] - dc[1] * dp[0]);
    return [(n1 * dp[0] - n2 * dc[0]) * n3, (n1 * dp[1] - n2 * dc[1]) * n3];
  };
  var outputList = subjectPolygon;
  cp1 = clipPolygon[clipPolygon.length - 1];
  for (j in clipPolygon) {
    var cp2 = clipPolygon[j];
    var inputList = outputList;
    outputList = [];
    s = inputList[inputList.length - 1]; //last on the input list
    for (i in inputList) {
      var e = inputList[i];
      if (inside(e)) {
        if (!inside(s)) {
          outputList.push(intersection());
        }
        outputList.push(e);
      } else if (inside(s)) {
        outputList.push(intersection());
      }
      s = e;
    }
    cp1 = cp2;
  }
  return outputList.map(e => e.map(f => Math.round(f * 1000) / 1000));
}