Bin
2025-12-16 9e0b2ba2c317b1a86212f24cbae3195ad1f3dbfa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
Feature("Brush relations").tag("@regress");
 
const IMAGE = "https://data.heartex.net/open-images/train_0/mini/0030019819f25b28.jpg";
 
const config = `<View>
    <Image name="img" value="$image"></Image>
    <BrushLabels name="tag" toName="img">
        <Label value="Test" background="orange"></Label>
    </BrushLabels>
  </View>`;
 
function getPointAtSpiral(t, v, w) {
  return { x: v * t * Math.cos(w * t), y: v * t * Math.sin(w * t) };
}
 
function generateSpiralPoints(x0, y0, R, v, w) {
  let t = 1;
  let x;
  let y;
  const points = [];
 
  do {
    ({ x, y } = getPointAtSpiral(t++, v, w));
    points.push([x + x0, y + y0]);
  } while (x ** 2 + y ** 2 < R ** 2);
  return points;
}
 
Scenario(
  "Brush relations shouldn't crash everything",
  async ({ I, LabelStudio, AtImageView, AtOutliner, AtDetails }) => {
    const params = {
      config,
      data: { image: IMAGE },
    };
 
    I.amOnPage("/");
    LabelStudio.init(params);
    LabelStudio.waitForObjectsReady();
    AtOutliner.seeRegions(0);
    await AtImageView.lookForStage();
    const canvasSize = await AtImageView.getCanvasSize();
    const regionsCentralPoints = [];
 
    // create 4 brush regions
    for (let i = 0; i < 4; i++) {
      // find start position
      const x = (canvasSize.width / 4) * ((i % 2) * 2 + 1);
      const y = (canvasSize.height / 4) * ((Math.floor(i / 2) % 2) * 2 + 1);
      // generate points in a spiral
      const points = generateSpiralPoints(
        x,
        y,
        Math.min(canvasSize.width / 6, canvasSize.height / 6),
        0.4,
        Math.PI / 18,
      );
 
      // select the brush label
      I.pressKey("1");
      // draw a brush region
      AtImageView.drawThroughPoints(points);
      AtOutliner.seeRegions(i + 1);
      // unselect the region
      I.pressKey("u");
      // save the central point
      regionsCentralPoints.push({ x, y });
    }
    // switch to the move tool for easy region selecting
    I.pressKey("v");
    // select the first region
    AtImageView.clickAt(regionsCentralPoints[0].x, regionsCentralPoints[0].y);
    // create relation to the second region
    I.pressKey(["alt", "r"]);
    AtImageView.clickAt(regionsCentralPoints[1].x, regionsCentralPoints[1].y);
    // check that the relation has been created
 
    AtDetails.seeRelations(1);
 
    // Check that relations work fine on a brush restoration (from rle)
    {
      // export annotation
      const annotation = await LabelStudio.serialize();
 
      // reload LS with that datalabel studio logo
      LabelStudio.init({
        ...params,
        annotations: [{ id: "imported", result: annotation }],
      });
 
      LabelStudio.waitForObjectsReady();
      // Check that relation still exist
      AtDetails.seeRelations(1);
      // move tool is already selected and stored so we don't need to select it again
      // I.pressKey("v");
      // select the third region
      AtImageView.clickAt(regionsCentralPoints[2].x, regionsCentralPoints[2].y);
      // create relation to the fourth region
      I.pressKey(["alt", "r"]);
      AtImageView.clickAt(regionsCentralPoints[3].x, regionsCentralPoints[3].y);
      // check that the relation has been created
      AtDetails.seeRelations(2);
 
      /// The potential errors should be caught by `errorsCollector` plugin
    }
  },
);