Прямоугольники, пересекающиеся даже не должны - PullRequest
0 голосов
/ 02 мая 2018

Если я создаю два прямоугольника рядом друг с другом и проверяю их на пересечение, он всегда возвращает истину, даже если не должен.

Как вы можете видеть из скрипки, если есть прямоугольник, начинающийся с x=0 и width=50px, второй прямоугольник должен начинаться с x=50, чтобы избежать разрыва между ними. Однако, чтобы избежать пересечения, должен быть зазор 2 пикселя.

Почему это так и как я могу обойти это?

canvas = new fabric.Canvas('canvas');

// Starting at x=0
var rect1 = new fabric.Rect({
      left: 0, top: 0, fill: 'black', width: 50, height: 50, selectable: false,
    });

// Starting 50px right of the previous
var rect2 = new fabric.Rect({
      left: 50, top: 0, fill: 'blue', width: 50, height: 50, selectable: false,
    });

// Starting 51px right of the previous
var rect3 = new fabric.Rect({
      left: 101, top: 0, fill: 'black', width: 50, height: 50, selectable: false,
    });

// Starting 52px right of the previous
var rect4 = new fabric.Rect({
      left: 153, top: 0, fill: 'blue', width: 50, height: 50, selectable: false,
    });

canvas.add(rect1, rect2, rect3, rect4);

console.log(rect1.aCoords.tr, rect2.aCoords.tr, rect3.aCoords.tr, rect4.aCoords.tr);

if (rect1.intersectsWithObject(rect2))
    console.log("1st intersecting with 2nd.");
else
  console.log("No intersection between 1st and 2nd.");

if (rect2.intersectsWithObject(rect3))
    console.log("2nd intersecting with 3rd.");
else
  console.log("No intersection between 2nd and 3rd.");

if (rect3.intersectsWithObject(rect4))
    console.log("3rd intersecting with 4th.");
else
  console.log("No intersection between 3rd and 4th.");
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.2.3/fabric.js"></script>
<p>Open console to see the rectangles absolute positions.</p>
<canvas id="canvas" width="300px" height="75px"></canvas>

Мой jsfiddle

Ответы [ 3 ]

0 голосов
/ 06 мая 2018

Я решил это с помощью низкоуровневых функций Fabric.js. Если пересечение найдено, я проверяю, существует ли только одна точка пересечения и является ли эта точка углом одного из наших объектов. Если это правда, у нас есть «поддельное пересечение».

    function isIntersecting(obj1, obj2) {
  var result = new fabric.Intersection(),
	points1 = obj1.getCoords(true, false),
	points2 = obj2.getCoords(true, false),
	length1 = points1.length,
	length2 = points2.length,
	a1, a2, b1, b2;
      
  // Check if one object lies within the other.
  if (obj1.isContainedWithinObject(obj2, false, true) || obj2.isContainedWithinObject(obj1, false, true))
  	return true;
  
  // Check for intersection between all edges.
  for (var i = 0; i < length1; i++) {
        a1 = points1[i];
        a2 = points1[(i + 1) % length1];
      
      for (var j = 0; j < length2; j++) {
        b1 = points2[j];
        b2 = points2[(j + 1) % length2];
      	result = fabric.Intersection.intersectLineLine(a1, a2, b1, b2);
        
        if (result.status == 'Intersection') {
          // It's not an intersection if we have only 1 intersection point and if this one is the end of one of our lines.
          let allPoints = [a1, a2, b1, b2];
          if (result.points.length > 1 || !polygonIncludesPoint(allPoints, result.points[0])) {
          	return true;
          }
          else if (obj2.containsPoint(a1) || obj2.containsPoint(a2)	||
          		obj1.containsPoint(b1) || obj1.containsPoint(b2)) {
          	// But it is if one corner of an edge is within the other object.	
            return true;
          }
        }
      }
  }
  
  return false;
}

function polygonIncludesPoint(points, point) {
  for (var i = 0; i < points.length; i++) {
        if (points[i].eq(point))
    	  return true;
  }
  return false;
}

var canvas = new fabric.Canvas('canvas');

var center = new fabric.Rect({
      left: 50, top: 50, fill: 'black', width: 50, height: 50, selectable: false, strokeWidth: 0
    });

var tl = new fabric.Rect({
      left: 0, top: 0, fill: 'blue', width: 50, height: 50, selectable: false, strokeWidth: 0
    });

var tm = new fabric.Rect({
      left: 50, top: 0, fill: 'grey', width: 50, height: 50, selectable: false, strokeWidth: 0
    });

var tr = new fabric.Rect({
      left: 100, top: 0, fill: 'blue', width: 50, height: 50, selectable: false, strokeWidth: 0
    });
    
var ml = new fabric.Rect({
      left: 0, top: 50, fill: 'grey', width: 50, height: 50, selectable: false, strokeWidth: 0
    });
    
var mr = new fabric.Rect({
      left: 100, top: 50, fill: 'grey', width: 50, height: 50, selectable: false, strokeWidth: 0
    });
    
var bl = new fabric.Rect({
      left: 0, top: 100, fill: 'blue', width: 50, height: 50, selectable: false, strokeWidth: 0
    });
    
var bm = new fabric.Rect({
      left: 50, top: 100, fill: 'grey', width: 50, height: 50, selectable: false, strokeWidth: 0
    });
    
var br = new fabric.Rect({
      left: 80, top: 80, fill: 'blue', width: 50, height: 50, selectable: false, strokeWidth: 0
    });
    
var center2 = new fabric.Rect({
      left: 180, top: 20, fill: 'black', width: 50, height: 50, selectable: false, strokeWidth: 0
    });
    
var bigRect = new fabric.Rect({
      left: 180, top: 20, fill: 'rgba(0, 0, 255, 0.3)', width: 90, height: 90, selectable: false, strokeWidth: 0
    });
    
var center3 = new fabric.Rect({
      left: 310, top: 40, fill: 'black', width: 50, height: 50, selectable: false, strokeWidth: 0
    });
    
var bigRect2 = new fabric.Rect({
      left: 290, top: 20, fill: 'rgba(0, 0, 255, 0.3)', width: 90, height: 90, selectable: false, strokeWidth: 0
    });
    
    

canvas.add(center, tl, tm, tr, ml, mr, bl, bm, br, center2, bigRect, center3, bigRect2);

var objects = canvas.getObjects('rect');

// Check 1st case
console.log("1st case:");
objects.forEach(function (targ) {
  if (targ === center || targ === center2 || targ === bigRect || targ === center3 || targ === bigRect2) return;

  if (isIntersecting(center, targ))
  	console.log("Intersection");
  else
  	console.log("No intersection");
});

// Check 2nd case
console.log("2nd case:");
if (isIntersecting(center2, bigRect))
	console.log("Intersection");
else
  console.log("No intersection");
  
// Check 3rd case
console.log("3rd case");
if (isIntersecting(center3, bigRect2))
	console.log("Intersection");
else
	console.log("No intersection");
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.2.3/fabric.min.js"></script>
<p>See console for results.</p>
<canvas id="canvas" width="400px" height="200px"></canvas>

Мой jsfiddle

0 голосов
/ 07 мая 2018

@ Дурга центрирует точку, штрих создает пересечения.

Чтобы добавить больше деталей, вы должны учитывать, что это пересечение между путями, а не пикселями.

Прямоугольник шириной 50 и начинающийся с 0, фактически пересекается с другим, начинающимся с 50, учитывая, что его стороны идеально перекрываются, между двумя канатами нет места, они соприкасаются друг с другом.

Я согласен, что можно добавить параметр, чтобы не учитывать перекрытие при возврате логического значения.

0 голосов
/ 02 мая 2018

Я считаю, что это происходит из-за невидимой ширины обводки (то есть по умолчанию 1).

Таким образом, в прямоугольниках им нужно расстояние в 2 пикселя (1 пиксель для левого и 1 пиксель для правого). Я установил на вашем образце ширину обводки для 0px и снова запустил тест.

canvas = new fabric.Canvas('canvas');

// Starting at x=0
var rect1 = new fabric.Rect({
      left: 0, top: 0, fill: 'black', width: 50, height: 50, selectable: false, strokeWidth: 0
    });

// Starting 50px right of the previous
var rect2 = new fabric.Rect({
      left: 51, top: 0, fill: 'blue', width: 50, height: 50, selectable: false, strokeWidth: 0
    });

// Starting 51px right of the previous
var rect3 = new fabric.Rect({
      left: 102, top: 0, fill: 'black', width: 50, height: 50, selectable: false, strokeWidth: 0
    });

// Starting 52px right of the previous
var rect4 = new fabric.Rect({
      left: 153, top: 0, fill: 'blue', width: 50, height: 50, selectable: false, strokeWidth: 0
    });

//canvas.add(rect1, rect2, rect3, rect4);
canvas.add(rect1);
canvas.add(rect2);
canvas.add(rect3);
canvas.add(rect4);

console.log(rect1.aCoords.tr, rect2.aCoords.tr, rect3.aCoords.tr, rect4.aCoords.tr);

if (rect1.intersectsWithObject(rect2))
    console.log("1st intersecting with 2nd.");
else
  console.log("No intersection between 1st and 2nd.");

if (rect2.intersectsWithObject(rect3))
    console.log("2nd intersecting with 3rd.");
else
  console.log("No intersection between 2nd and 3rd.");

if (rect3.intersectsWithObject(rect4))
    console.log("3rd intersecting with 4th.");
else
  console.log("No intersection between 3rd and 4th.");
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.2.3/fabric.min.js"></script>
<p>Open console to see the rectangles absolute positions.</p>
<canvas id="canvas" width="300px" height="75px"></canvas>

Проверьте это скрипка .

...