Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

iOverlay

Balloons

Introduction

  • The iOverlay is a poly-bool library that supports main operations such as union, intersection, difference, xor, and self-intersection.

Features

  • Operations: union, intersection, difference, and exclusion.
  • Polygons: with holes, self-intersections, and multiple paths.
  • Simplification: removes degenerate vertices and merges collinear edges.
  • Buffering: offsets paths and polygons.
  • Fill Rules: even-odd, non-zero, positive and negative.

Source Code

Demo

This section showcases interactive examples built using iOverlay.

Use the demos below to explore how the library performs boolean operations on 2D shapes in real time.

Stars Rotation

Stars Rotation

Subject Star

Clip Star

Shapes Editor

Shapes Editor

Title

Stroke

Stroke Offset

Title

Outline

Outline

Title

Overlay Editor

Overlay Editor

Your browser does not support WebGPU.

Please use a WebGPU-supported browser, such as the latest version of Chrome.

WebGPU not supported

Performance Comparison

Benchmark project is here.

For Rust-only solver precision benchmarks, see Rust iOverlay Solver Benchmarks.

All tests were run on a machine with the following specifications:
3 GHz 6-Core Intel Core i5, 40GB 2667 MHz DDR4

All results are presented in seconds.

Solvers:

  • iOverlay(Rust) v1.9.0 (multithreading on/off)
  • iOverlay(Swift) v1.13.0
  • Clipper2(C++) v1.4.0
  • Boost(C++) v1.86.0

Checkerboard Test

Checkerboard Test

SquaresSwiftRust (mt off)Rust (mt on)Clipper2Boost
50.0000140.0000060.0000060.0000070.000045
250.0001000.0000360.0000360.0000380.000595
1130.0005890.0001970.0001960.0002080.004446
4810.0041050.0011170.0011170.0010170.060791
19850.0126430.0049140.0049350.0051821.103624
80650.0556640.0206740.0197850.02401321.080339
325130.2348400.0918710.0832850.154054412.630289
1305610.9939200.4246430.3729781.067439––
5232654.4103022.0435702.0083398.346041––
209510518.4516469.2913847.93681073.312335––
838451378.71930538.63966633.742216644.337867––

Not Overlap Test

Not Overlap Test

SquaresSwiftRust (mt off)Rust (mt on)Clipper2Boost
50.0000090.0000030.0000030.0000050.000003
250.0000410.0000120.0000110.0000210.000021
1130.0002040.0000610.0000620.0000970.000223
4810.0010520.0003460.0003440.0004570.002621
19850.0049780.0016790.0016680.0021140.036257
80650.0213360.0059120.0054250.0107830.558494
325130.0895230.0284540.0247180.0562818.852867
1305610.3755940.1274480.1074850.369146146.041905
5232651.6630870.6358980.5380602.695334––
20951056.9479322.7085492.47021020.665812––
838451328.77756913.5148469.601191167.966801––

Lines Net Test

Lines Net Test

SquaresSwiftRust (mt off)Rust (mt on)Clipper2Boost
40.0000140.0000040.0000040.0000040.000014
80.0000490.0000140.0000140.0000120.000054
160.0001950.0000490.0000500.0000430.000370
320.0012950.0001950.0001960.0001760.003175
640.0049940.0010130.0010160.0007490.055749
1280.0212390.0040460.0039700.00344123.531991
2560.0914270.0188150.0208700.018417412.528984
5120.2559890.0886010.0967450.115229––
10241.1468420.4171280.3974700.759640––
20484.8085481.8447541.5373855.595165––
409620.1901017.5145487.69692045.934461––

Spiral Test

Spiral Test * There is now boost results for this test

SquaresSwiftRust (mt off)Rust (mt on)Clipper2
20.0000060.0000020.0000020.000002
40.0000100.0000050.0000050.000004
80.0000190.0000090.0000090.000007
160.0000400.0000200.0000200.000014
320.0000950.0000480.0000480.000031
640.0002180.0001290.0001270.000083
1280.0004900.0003040.0003050.000202
2560.0011050.0006680.0006690.000476
5120.0033850.0015990.0016060.001195
10240.0061740.0035720.0035600.002941
20480.0132000.0050000.0049300.007578
40960.0260650.0095760.0095280.020287
81920.0559440.0175830.0187790.054647
163840.1123750.0401450.0402630.181050
327680.2374120.0766420.0766090.606854
655360.4738470.1819120.1813872.013809
1310720.9817290.3439170.3310466.547658
2621441.9795410.7817700.83381621.171540
5242884.1019121.4171441.47262472.147615
10485768.2541083.1885093.232834259.866180

Windows Test

Windows Test

SquaresSwiftRust (mt off)Rust (mt on)Clipper2Boost
80.0000160.0000060.0000060.0000080.000006
320.0000620.0000210.0000210.0000280.000037
1280.0002760.0000960.0000970.0001120.000266
5120.0013060.0005190.0005160.0005070.002482
20480.0055430.0016750.0015480.0024540.030949
81920.0238050.0075190.0067800.0123640.448009
327680.1048220.0388320.0341490.0768507.013886
1310720.4457120.1923380.1596850.568316109.745463
5242881.8623710.8350500.7031474.142673––
20971527.6578153.7618083.18236233.165570––
838860830.83397315.47674412.058687265.387333––

Nested Squares Test

Nested_Squares Test

SquaresSwiftRust (mt off)Rust (mt on)Clipper2Boost
40.0000220.0000090.0000090.0000120.000153
80.0000450.0000170.0000170.0000230.000387
160.0000980.0000350.0000340.0000500.000792
320.0002380.0000810.0000810.0001180.001757
640.0006240.0002100.0002170.0002910.004145
1280.0018530.0005940.0006080.0008060.010646
2560.0023980.0019920.0020160.0034150.036101
5120.0050130.0025550.0026410.0159890.141906
10240.0160670.0078510.0059250.0812670.560183
20480.0331940.0245230.0187770.4618832.425802
40960.1506010.0605160.0447562.34720911.419096
81920.3116910.2451600.16553910.61242449.299261
163840.7523570.4856050.33165546.205474206.646450
327682.5819911.8149931.148905251.260857––
6553610.3687944.0316312.1974933502.233611––
13107223.25074615.7317058.194153––––
26214448.52955530.80976015.285741––––

Rust iOverlay Solver Benchmarks

All results were measured on Apple M4, 24 GB. Values are seconds per operation. The benchmark project is in performance/rust_app in the iOverlay repository.

  • i16/i32/64 math solvers
  • on/off multithreading feature

Average Comparison

Average relative time

Checkerboard Test

Checkerboard Test

Ni16 offi32 offi64 offi16 oni32 oni64 on
20.0000020.0000020.0000030.0000030.0000020.000003
40.0000150.0000150.0000170.0000150.0000150.000017
80.0000820.0000820.0000990.0000830.0000810.000099
160.0004260.0004120.0004980.0004370.0004090.000501
320.0022360.0023180.0027330.0023050.0022990.002752
640.0080700.0086590.0103880.0071400.0072430.008616
1280.0375590.0405120.0500850.0278570.0289860.035981
2560.1673750.1784250.2196220.1206060.1257110.158665
5120.7767310.8272641.0117030.5689570.5927680.724087
10243.3858743.6111254.3938802.4136212.6104313.127404

Not Overlap Test

Not Overlap Test

Ni16 offi32 offi64 offi16 oni32 oni64 on
50.0000010.0000010.0000010.0000010.0000010.000001
250.0000050.0000050.0000060.0000050.0000050.000006
1130.0000240.0000240.0000270.0000240.0000240.000028
4810.0001360.0001330.0001520.0001380.0001320.000151
19850.0009010.0009120.0010460.0009080.0009080.001053
80650.0024610.0027250.0031780.0021760.0023220.002579
325130.0112720.0123190.0147190.0083770.0089560.010409
1305610.0482140.0534200.0651000.0344380.0369010.044266
5232650.2203640.2406640.3015770.1580550.1771180.217189
20951050.9271911.0375211.3002600.6877770.7451870.920391
83845134.5806725.6672043.2824163.948376

Lines Net Test

Lines Net Test

Ni16 offi32 offi64 offi16 oni32 oni64 on
40.0000020.0000020.0000020.0000020.0000020.000002
80.0000060.0000060.0000070.0000060.0000060.000007
160.0000200.0000200.0000250.0000210.0000200.000025
320.0000910.0000870.0001130.0000920.0000870.000114
640.0003920.0004250.0004860.0004030.0004230.000497
1280.0017170.0017910.0021610.0017160.0018290.002118
2560.0082800.0087330.0103050.0070470.0075100.008971
5120.0376330.0399410.0485150.0305160.0322080.041422
10240.1684660.1814880.2198350.1300990.1451590.181670
20480.7512820.8061230.9912090.5690640.6222110.780686
40963.5577614.4202092.6877783.220613

Spiral Test

Spiral Test

Ni16 offi32 offi64 offi16 oni32 oni64 on
20.0000010.0000010.0000010.0000010.0000010.000001
40.0000020.0000020.0000030.0000020.0000020.000003
80.0000050.0000050.0000070.0000050.0000050.000008
160.0000070.0000100.0000160.0000070.0000100.000016
320.0000150.0000210.0000340.0000150.0000200.000033
640.0000310.0000430.0000710.0000310.0000420.000069
1280.0000860.0000920.0001590.0000760.0001040.000154
2560.0002510.0002980.0003760.0002790.0002450.000380
5120.0006980.0007900.0010180.0007640.0007480.001008
10240.0018180.0020410.0026580.0019620.0019840.002594
20480.0041240.0042070.0057360.0039500.0044830.005705
40960.0052860.0079740.0096870.0043740.0062700.005941
81920.0105660.0127960.0177130.0084460.0094340.010722
163840.0220610.0280010.0379010.0173470.0195260.023228
327680.0455130.0509970.0750600.0331830.0343970.042546
655360.0949610.1133480.1656860.0651670.0742290.091817
1310720.2014150.2236530.3363380.1317890.1460950.192015
2621440.4315970.5415260.7807710.3017770.3509410.449105
5242880.6666601.0341781.5366260.4563910.7445200.922172

Windows Test

Windows Test

Ni16 offi32 offi64 offi16 oni32 oni64 on
80.0000030.0000030.0000030.0000030.0000020.000003
320.0000090.0000080.0000100.0000090.0000090.000010
1280.0000380.0000380.0000430.0000380.0000380.000043
5120.0002050.0001950.0002250.0002040.0001940.000224
20480.0011270.0011330.0013380.0011290.0011380.001340
81920.0031880.0034210.0040130.0026330.0028090.003138
327680.0139170.0155840.0186260.0101630.0108920.012617
1310720.0630980.0699250.0889670.0457370.0498750.061721
5242880.2773220.3122580.3844340.1990350.2248170.267889
20971521.2115611.3824591.7093740.9091311.0079651.175990

Nested Squares Test

Nested Squares Test

Ni16 offi32 offi64 offi16 oni32 oni64 on
40.0000040.0000040.0000050.0000040.0000040.000004
80.0000070.0000070.0000080.0000070.0000080.000009
160.0000150.0000150.0000180.0000150.0000150.000018
320.0000340.0000330.0000400.0000340.0000330.000040
640.0000820.0000790.0000960.0000830.0000800.000097
1280.0002240.0002130.0002500.0002280.0002140.000253
2560.0006510.0006590.0007600.0006980.0006720.000756
5120.0020650.0020600.0028370.0020150.0021090.002833
10240.0053560.0052230.0076130.0052710.0054260.007585
20480.0092380.0116090.0155530.0070700.0077570.009880
40960.0573000.0233090.0312920.0585290.0146830.018457
81920.0818560.1131960.0460140.059750
163840.1814160.2453530.0876460.122264
327680.6673940.9610190.3227070.431346
655361.4010062.0594380.6537410.933473
1310725.4450658.1380392.4109103.822923

Documentation


Filling Rules

Filling rules determine how the interior of a shape is defined. iOverlay supports 4 filling rules:

  • Even-Odd: A point is inside the shape if a ray drawn from the point crosses the shape’s edges an odd number of times.
  • Non-Zero: A point is inside the shape if the total winding number around the point is non-zero.
  • Positive: Only regions with a positive winding number are considered inside.
  • Negative: Only regions with a negative winding number are considered inside.

Overlay Rules

Overlay rules define how two shapes interact during Boolean operations:

  • Union (A ∪ B): Combines the areas of both shapes.
  • Intersection (A ∩ B): Retains only the overlapping area of both shapes.
  • Difference (A - B): Subtracts the area of shape B from shape A.
  • Exclusion (A ⊕ B): Combines the areas of both shapes but excludes the overlapping region.

Contours

Contours represent the boundaries of shapes and are categorized as:

  • Outer Contours: Define the external boundary of a shape, ordered in a counterclockwise direction.
  • Inner Contours (Holes): Define holes within a shape, ordered in a clockwise direction.

Overlay Graph

The overlay graph is a data structure that represents the intersections and overlays of two geometric objects. It is constructed by dividing all segments of the object contours into non-intersecting parts, where segments can only touch at their endpoints. Each segment in the graph contains information about its association with the original shapes, facilitating efficient Boolean operations.


Extract Shapes

After applying Boolean operations, the resulting shapes are extracted through a series of steps:

  1. Build Contour: Starting from the leftmost node, the algorithm traverses connected segments to form contours, marking each segment as visited to prevent duplication.
  2. Define Contour: Determines whether a contour is outer or inner based on its orientation and position.
  3. Matching Contours: Associates inner contours with their corresponding outer contours by analyzing spatial relationships.

Filling Rules

Even-Odd

Even-Odd

Non-Zero

Non-Zero

Positive

Positive

Negative

Negative

Filling Rules:

  • Even-Odd: Only odd numbered sub-regions are filled
  • Non-Zero: Only non-zero sub-regions are filled
  • Positive: Only positive sub-regions are filled
  • Negative: Only negative sub-regions are filled

Overlay Rules

AB

Union, A or B

Union

Intersection, A and B

Intersection

Difference, A - B

Difference

Inverse Difference, B - A

Inverse Difference

Exclusion, A xor B

Exclusion

Contours

Outer and Inner

Contour In the context of the Overlay Graph, contours are used to represent the boundaries of geometric objects. These contours are classified into two types: outer contours and inner contours.

Outer Contour:

  • An outer contour is a sequence of points ordered in a counterclockwise direction.
  • The outer contour defines the external boundary of a shape, enclosing the exterior space.

Inner Contour (Hole or Cave):

  • An inner contour is a sequence of points ordered in a clockwise direction.
  • Inner contours represent enclosed areas within an outer contour, often referred to as “holes” or “caves.”

Both outer and inner contours must be simple, meaning they must not self-intersect and must not share edges with other contours.

Overlay Graph

Example An Overlay Graph is a data structure representing the intersections and overlays of two geometric objects (A and B) defined by closed contours in 2D space.

The graph is constructed by dividing all the segments of the object contours into non-intersecting parts, where segments can only touch at their endpoints. Each segment in the graph contains the following properties:

  • For each side of the segment, it stores information about its membership to object A and object B
  • Segments do not intersect each other, but they may touch at their endpoints.

for more Overlay Graph examples see Shape Editor

Filter Segments

Difference, C = A - B

The resulting segments of C must not be inside body B and must belong to body A on one side.
The side associated solely with body A will represent the inner part of the resulting shape.

Example

Difference, C = B - A

The resulting segments of C must not be inside body A and must belong to body B on one side.
The side associated solely with body B will represent the inner part of the resulting shape. Example

Union, C = A or B

The resulting segments of C must belong to either body A or body B, or to both. The opposite side of each segment must not belong to anybody.
The side associated with one of the bodies will represent the inner part of the resulting shape. Example

Intersection, C = A and B

The resulting segments of C must belong to both bodies A and B. The opposite side of each segment must not belong to both bodies simultaneously.
The side associated with both bodies A and B will represent the inner part of the resulting shape. Example

Exclusion, C = A xor B

The resulting segments of C must belong to either body A or body B, but not to both simultaneously. The opposite side of each segment must either belong to both bodies or to neither.
The side associated with one of the bodies (A or B) will represent the inner part of the resulting shape. Example

Extract Shapes

Once we apply boolean filter to Overlay Graph, we can begin extract contours.

Build Contour

Outer Contour

Extract Contour

Inner Contour

Extract Contour

The algorithm starts by selecting the leftmost node and proceeds by choosing the topmost segment connected to that node. The process continues by traversing to the next node along the selected segment.

At each node, the algorithm selects the next segment by rotating around the current node in a clockwise/counterclockwise direction for outer/inner contours and taking the first nearest segment.

To prevent segments from being visited twice, each segment is marked as visited upon traversal.

This process continues until the contour is complete, forming either an outer or inner contour.

By following this approach, outer contours are extracted in a counter-clockwise direction, while inner contours are extracted in a clockwise direction.

Define Contour

Define Contour

To define a contour, the algorithm begins by identifying the leftmost and topmost segment in the contour. The classification of the contour is determined as follows:

  • If the left-top side of the segment is classified as the outer side, then the contour is an outer contour.
  • If the left-top side of the segment is classified as the inner side, then the contour is an inner contour.

This method ensures each contour is correctly classified based on its orientation in 2D space.

Define Shape

Define Shape

A shape is defined as a group of contours, where the first contour is always an outer contour, and the subsequent contours (if any) are inner contours.

Matching Contours

Matching Contours To match inner contours to their corresponding outer contours:

  1. Draw a line downward from any point on the inner (target) contour.
  2. Identify the first segment encountered along the line that does not belong to the target contour.
  • If the segment belongs to an outer contour, that contour is the container for the target contour.
  • If the segment belongs to another inner contour, the container of that inner contour is also the container for the target contour.

Define Segment under Point

Segment under Point

Segment Under Point

To determine whether a segment AB is below a point P, one may be tempted to compute the value of ym at the point of intersection M, where a vertical line is dropped from P onto AB (i.e., xp = xm):

$$ y_{m} = \frac{y_{a} - y_{b}}{x_{a} - x_{b}}\cdot(x_{m} - x_{a}) + y_{a} $$

However, this approach can introduce precision issues due to the division involved.

A more reliable method involves using the order of traversal around the vertices of the triangle APB. If segment AB is below point P, the vertices A, P, and B will appear in a clockwise order.

This method uses the cross product of vectors PA and PB:

$$ a \times b = a_x b_y - a_y b_x $$

Since this method avoids division, it eliminates precision issues, making it stable for determining whether a segment is below a point.

Selecting the Closest Segment under Point

When multiple segments are positioned below point P, we need to determine which segment is the closest to P. This scenario can be divided into three distinct cases based on the configuration of the segments relative to P.

Left Case

Left Case

When both segments share a common left vertex A, we check the positions of their right endpoints. If the vertices B0, B1, and A form a clockwise pattern, then AB0 is closer to P than AB1.

Right Case

Right Case

When both segments share a common right vertex B, we check the positions of their left endpoints. If the vertices A0, A1, and B form a clockwise pattern, then A1B is closer to P than A0B.

Middle Case

Middle Case

In this case, one of the vertices (e.g., A1 or B0) lies inside the opposite segment. We use the point-segment comparison method to determine which of the segments is closer to P.

iTriangle

Eagle triangulation

Introduction

  • Easy way to get your triangulation!

Features

  • Delaunay triangulation
  • Break into convex polygons
  • Support any kind of polygons
  • Self-Intersection Resolving

Source Code

Demo

This section contains interactive examples that demonstrate how iTriangle performs triangulation and tessellation.

Triangulation

Triangulation

Title

Tessellation

Tessellation

Title

Performance Comparison

Benchmark projects are:

All benchmarks were executed on the following machine:
3 GHz 6-Core Intel Core i5, 40GB 2667 MHz DDR4

All results are presented in microseconds (10⁻⁶ sec).

Each test was repeated multiple times, and the average result is shown.

All input shapes are clean (non-self-intersecting), and the logic was optimized to achieve maximum performance.

Solvers

  • iTriangle (Earcut64, Rust) v0.36.3 — raw triangulation, no holes, limited to ≤64 points, validation disabled
  • iTriangle (Monotone, Rust) v0.36.3 — raw triangulation, validation disabled
  • iTriangle (Delaunay, Rust) v0.36.3 — Delaunay triangulation, validation disabled
  • MapBox (Earcut Rust) v0.5.0 – Rust port – raw triangulation, validation disabled
  • MapBox (Earcut C++) v2.2.4 – C++ official – raw triangulation, validation disabled
  • Triangle (Delaunay C) v1.6 – C official - constrained Delaunay triangulation, validation disabled

Star Test

Raw

CountEarcut64MonotoneEarcut RustEarcut C++
80.30.50.730.42
160.661.61.230.5
321.63.92.61.2
644.68.355.63.3
128-17.812.68.4
256-37.529.122.9
512-79.780.772.7
1024-172259209
2048-388736641
4096-89831582804
8192-18241343511479
16384-38465168844017

Delaunay

CountiTriangleTriangle
80.464.3
161.08.3
322.525
646.65130
12819.7271
25640.5523
51285.91006
10241941704
20484242828
40969874806
819220748581
16384453316384

Spiral Test

Raw

CountEarcut64MonotoneEarcut RustEarcut C++
80.350.70.770.42
161.21.41.660.77
324.03.06.253.4
6415.46.218.619.8
128-12.871.666
256-26.7295306
512-55.512301438
1024-12053017595
2048-2792268250140
4096-68596933376060
8192-14354169433.7kk
16384-3080181214743.4kk

Delaunay

CountiTriangleTriangle
80.513.2
161.548.7
324.721.5
6416.935.6
12815.066.9
25629.7166
51262.2340
1024139728
20483131469
409673582948
819214426609
16384346313863

Star with Hole Test

Raw

CountMonotoneEarcut RustEarcut C++
12812.131.930.2
25622.486.678.8
51242.3227222
102484.4650593
204817420531825
409633371025702
81927552619722390
16384163610287480154

Delaunay

CountiTriangleTriangle
12816.8201
25632.8410
51261.6808
10241211616
20482503055
40965056410
8192140112919
16384409330704

Star with 8 holes Test

Raw

CountMonotoneEarcut RustEarcut C++
25619.311743
51230.3260107
102453.7437270
20481075018576
4096200405961517
81923881562873802
1638479727356712687

Delaunay

CountiTriangleTriangle
25623.7330
51241.6546
102471.4951
20481431777
40962763398
81925676921
16384153913748

Delaunay

Delaunay

Click on the canvas to drag the points

What is the Delaunay Condition?

When creating a triangulation network, the Delaunay condition aims to form triangles such that their circumscribed circles do not contain any other points from the dataset. In simpler terms, it ensures that triangles are “well-shaped” rather than “skinny,” making the network more balanced and useful for various applications.


Delaunay condition


If the condition \(\alpha + \beta < \pi\) holds, it implies that the point \(P\) will lie outside the circumscribed circle. This confirms that a pair of triangles satisfies the Delaunay condition.

$$ \alpha + \beta < \pi \Rightarrow \sin(\alpha + \beta) > 0 $$

$$ \sin(\alpha + \beta) = \sin(\alpha)\cos(\beta) + \cos(\alpha)\sin(\beta) $$

Calculating \(\cos(\alpha)\) and \(\sin(\alpha)\):

$$ \cos(\alpha) = \frac{\vec{a} \cdot \vec{b}}{|a||b|} = \frac{a_{x}b_{x} + a_{y}b_{y}}{|a||b|} $$

$$ \sin(\alpha) = \sqrt{1- \cos^2(\alpha)} = … = \frac{|a_{x}b_{y} - b_{x}a_{y}|}{|a||b|} = \frac{|\vec{a} \times \vec{b}|}{|a||b|} $$

Calculating \(\cos(\beta)\) and \(\sin(\beta)\):

$$ \cos(\beta) = \frac{\vec{c} \cdot \vec{d}}{|c||d|} = \frac{c_{x}d_{x} + c_{y}d_{y}}{|c||d|} $$

$$ \sin(\beta) = \frac{|\vec{c} \times \vec{d}|}{|c||d|} = \frac{|c_{x}d_{y} - d_{x}c_{y}|}{|c||d|} $$

Final Equation:

$$ \sin(\alpha + \beta) = \frac{|a_{x}b_{y} - b_{x}a_{y}|\cdot(c_{x}d_{x} + c_{y}d_{y}) + (a_{x}b_{x} + a_{y}b_{y})\cdot|c_{x}d_{y} - c_{x}d_{y}|}{|a||b||c||d|} > 0 $$

$$ |a_{x}b_{y} - b_{x}a_{y}|\cdot(c_{x}d_{x} + c_{y}d_{y}) + (a_{x}b_{x} + a_{y}b_{y})\cdot|c_{x}d_{y} - d_{x}c_{y}| > 0 $$

Or in vector form:

$$ |\vec{a} \times \vec{b}|(\vec{c} \cdot \vec{d}) + (\vec{a} \cdot \vec{b})|\vec{c} \times \vec{d}| > 0 $$