#include "contour_test.h"
#include "canvas.h"

using namespace contour;

std::string to_string(const std::pair<Tri, Tri>& p) {
    return to_string(p.first) + std::string(";") + to_string(p.second);
}

using std::to_string;

template <typename TT, typename = void>
struct has_to_string : std::false_type {};
template<typename TT>
struct has_to_string<TT, std::void_t<decltype(to_string(std::declval<TT>()))>> : std::true_type {};

template <typename TT, typename = void>
struct has_Dump_member : std::false_type {};
template<typename TT>
struct has_Dump_member<TT, std::void_t<decltype(std::declval<TT>().Dump())>> : std::true_type {};

constexpr auto equal = [](auto& a, auto& b) {return a==b; };

template <typename T, typename pred=decltype(equal)>
void TAssert(std::vector<std::pair<std::string, bool>>& ret,
             const T& value, const T& should_be, std::string_view text,
             pred pass = equal) {
    if (!shall_draw()) return;
    if (pass(value, should_be)) ret.emplace_back(std::string(text)+" - PASS", true);
    else if constexpr (has_to_string<T>::value)
        ret.emplace_back(std::string(text)+" "+to_string(value)+"!="+to_string(should_be), false);
    else if constexpr (has_Dump_member<T>::value)
        ret.emplace_back(std::string(text)+" "+value.Dump()+"!="+should_be.Dump(), false);
    else if constexpr (std::is_convertible_v<T, std::string>)
        ret.emplace_back(std::string(text)+" "+(std::string)value+"!="+(std::string)should_be, false);
    else
        ret.emplace_back(std::string(text)+" FAIL values mismatch", false);
}

void BAssert(std::vector<std::pair<std::string, bool>>& ret, bool pass, std::string_view text) {
    if (!shall_draw()) return;
    if (pass) ret.emplace_back(std::string(text)+" - PASS", true);
    else ret.emplace_back(std::string(text)+" FAIL", false);
}

void DAssert(std::vector<std::pair<std::string, bool>>& ret, double A, double B, std::string_view text) {
    TAssert(ret, A, B, text, &test_equal<double, double>);
}

std::string to_string(const std::vector<CPData>& cps) {
    std::string ret;
    for (auto& cp : cps)
        ret.append(cp.Dump(false)).append("; ");
    if (ret.size())
        ret.pop_back();
    return ret;
}

//Asserts that 'c' holds a simple contour with no holes and returns it.
const SimpleContour& GetSC(std::vector<std::pair<std::string, bool>>& ret, const Contour& c, std::string_view txt) {
    BAssert(ret, c.size()==1, std::string(txt)+": is a single simplecontour 1");
    BAssert(ret, !c[0].HasHoles(), std::string(txt)+": is a single simplecontour 2");
    return c[0].Outline();
}

void AssertContainment(std::vector<std::pair<std::string, bool>>& R, const Contour& c, const Contour& d,
                       contour::EContourRelationType rel, std::string_view txt) {
    using namespace contour;
    EContourRelationType irel = switch_side(rel);
    const SimpleContour& sc = GetSC(R, c, std::string(txt)+" 1");
    const SimpleContour& dc = GetSC(R, d, std::string(txt)+" 2");
    BAssert(R, sc.CheckContainment(dc)==rel, std::string(txt)+" res 1");
    BAssert(R, dc.CheckContainment(sc)==irel, std::string(txt)+" res 2");
    BAssert(R, dc.CheckContainment(sc.CreateInvert())==irel, std::string(txt)+" res 3");
    BAssert(R, sc.CheckContainment(dc.CreateInvert())==rel, std::string(txt)+" res 3");
    BAssert(R, sc.CreateInvert().CheckContainment(dc.CreateInvert())==rel, std::string(txt)+" res 4");
    BAssert(R, dc.CreateInvert().CheckContainment(sc.CreateInvert())==irel, std::string(txt)+" res 5");
    BAssert(R, sc.RelationTo(dc)==rel, std::string(txt)+" rel 1");
    BAssert(R, dc.RelationTo(sc)==irel, std::string(txt)+" rel 2");
    BAssert(R, dc.RelationTo(sc.CreateInvert())==irel, std::string(txt)+" rel 3");
    BAssert(R, sc.RelationTo(dc.CreateInvert())==rel, std::string(txt)+" rel 3");
    BAssert(R, sc.CreateInvert().RelationTo(dc.CreateInvert())==rel, std::string(txt)+" rel 4");
    BAssert(R, dc.CreateInvert().RelationTo(sc.CreateInvert())==irel, std::string(txt)+" rel 5");
}

void UnionAssert(std::vector<std::pair<std::string, bool>>& R, const Contour& c, const Contour& d, std::string_view text) {
    const Block est_bb = c.GetBoundingBox()+d.GetBoundingBox();
    _SUPPRESS_ASSERT_PRINT;
    const Contour U = c+d;
    const Block bb = U.GetBoundingBox();
    BAssert(R, fabs(est_bb.x.from-bb.x.from)+fabs(est_bb.y.from-bb.y.from)+fabs(est_bb.x.till-bb.x.till)+fabs(est_bb.y.till-bb.y.till)<1,
            std::string(text)+": Not equal BB after positive union."+ bb.Dump(false)+" instead of "+est_bb.Dump(false));
}

//This assumes the intersect is not empty. If it should be that is easy to assert as such without this fn.
void IntersectAssert(std::vector<std::pair<std::string, bool>>& R, const Contour& c, const Contour& d, std::string_view text) {
    const Block est_bb = c.GetBoundingBox()*d.GetBoundingBox();
    _SUPPRESS_ASSERT_PRINT;
    const Contour U = c*d;
    const Block bb = U.GetBoundingBox();
    BAssert(R, std::max(0., est_bb.x.from-bb.x.from)+std::max(0., est_bb.y.from-bb.y.from)+std::max(0., bb.x.till-est_bb.x.till)+std::max(0., bb.y.till-est_bb.y.till)<1,
            std::string(text)+": Not smaller BB after positive intersect."+ bb.Dump(false)+" instead of "+est_bb.Dump(false));
    BAssert(R, !U.IsEmpty(), std::string(text)+": Empty intersect.");
}

/** Here we test simple stuff in code.*/
void contour_unit_tests(bool do_image) {
    if (shouldnt_do(0)) return;

    using namespace std::literals;
    std::vector<std::pair<std::string, bool>> R;

    //Test MovePos and LinearExtend on flattened beziers.
    Edge e(XY(176, 83), XY(92, 84), XY(176, 83), XY(126, 84)), f(e);
    const double pos = e.MovePos2(0, 10);
    f.Chop(0, pos);
    DAssert(R, f.GetLength(), 10, "Chop length");
    e.Chop(pos, 1);
    auto [b, e2] = e.LinearExtend(10, false, true);
    XY xy = b ? e2.GetStart() : e.GetStart(); //shall be close to (176,83)
    TAssert(R, xy, XY(176, 83), "LinearExtend", [](const XY& a, const XY& b) {return a.test_equal(b, 0.01); });

    Contour c, d;
    Path p, l;
    Edge ee, ff;
    std::vector<CPData> cps;
    bool r;
    CPData cp;

    //Test Crosspoints
    c = Contour(0, 10, 0, 10);
    p = {XY{0,0}, XY(0,10), XY(10,10)};
    TAssert(R, to_string(c.CrossPoints(p, true, nullptr, CalcRelation)),
            "XY(10,10)[(2:0),(1:1),overlap:opp:p2_ends]; XY(0,0)[(3:1),(0:0),overlap:opp:p2_ends];"s,
            "CrossPoint: along box"sv);
    p = {XY{0,0}, XY(10,0), XY(10,10)};
    TAssert(R, to_string(c.CrossPoints(p, true, nullptr, CalcRelation)),
            "XY(10,10)[(2:0),(1:1),overlap:p2_ends]; XY(0,0)[(3:1),(0:0),overlap:p2_ends];"s,
            "CrossPoint: along box opposite dir"sv);

    l = {XY{0,0}, XY{100,0}};
    p = {XY{0,0}, XY{50,0}, XY{100, -10}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(0,0)[(0:0),(0:0),overlap:both_end]; XY(50,0)[(0:0.5),(1:0),fork:bw:bw:l:r];"s,
            "CrossPoint: Along and leave left"sv);
    p = {XY{0,0}, XY{50,0}, XY{100, +10}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(0,0)[(0:0),(0:0),overlap:both_end]; XY(50,0)[(0:0.5),(1:0),fork:bw:bw:r:l];"s,
            "CrossPoint: Along and leave right"sv);
    p = {XY{100, -10}, XY{50,0}, XY{0,0}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(0,0)[(0:0),(1:1),overlap:opp:both_end]; XY(50,0)[(0:0.5),(1:0),fork:bw:fw:l:l:opp];"s,
            "CrossPoint: Along and leave right opposite"sv);
    p = {XY{100, +10}, XY{50,0}, XY{0,0}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(0,0)[(0:0),(1:1),overlap:opp:both_end]; XY(50,0)[(0:0.5),(1:0),fork:bw:fw:r:r:opp];"s,
            "CrossPoint: Along and leave left opposite"sv);
    p = {XY{0, +10}, XY{50,0}, XY{100,+10}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(50,0)[(0:0.5),(1:0),touch:r:l];"s,
            "CrossPoint: touch from right"sv);
    p = {XY{0, -10}, XY{50,0}, XY{100,-10}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(50,0)[(0:0.5),(1:0),touch:l:r];"s,
            "CrossPoint: touch from left"sv);
    p = {XY{0,0}, XY{50,0}, XY{40,-10}, XY{60,-10}, XY{50,0}, XY{100,0}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(0,0)[(0:0),(0:0),overlap:both_end]; XY(50,0)[(0:0.5),(1:0),fork:bw:bw:l:r]; XY(50,0)[(0:0.5),(4:0),fork:fw:fw:l:r]; XY(100,0)[(0:1),(4:1),overlap:both_end];"s,
            "CrossPoint: Along, leave to left, join back at same point"sv);
    p = {XY{0,0}, XY{50,0}, XY{40,+10}, XY{60,+10}, XY{50,0}, XY{100,0}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(0,0)[(0:0),(0:0),overlap:both_end]; XY(50,0)[(0:0.5),(1:0),fork:bw:bw:r:l]; XY(50,0)[(0:0.5),(4:0),fork:fw:fw:r:l]; XY(100,0)[(0:1),(4:1),overlap:both_end];"s,
            "CrossPoint: Along, leave to right, join back at same point"sv);

    l = {XY{100,0}, XY{0,0}};
    p = {XY{0,0}, XY{50,0}, XY{100, -10}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(50,0)[(0:0.5),(1:0),fork:fw:bw:r:r:opp]; XY(0,0)[(0:1),(0:0),overlap:opp:both_end];"s,
            "CrossPoint: Join from right opposite"sv);
    p = {XY{0,0}, XY{50,0}, XY{100, +10}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(50,0)[(0:0.5),(1:0),fork:fw:bw:l:l:opp]; XY(0,0)[(0:1),(0:0),overlap:opp:both_end];"s,
            "CrossPoint: Join from left opposite"sv);
    p = {XY{100, -10}, XY{50,0}, XY{0,0}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(50,0)[(0:0.5),(1:0),fork:fw:fw:r:l]; XY(0,0)[(0:1),(1:1),overlap:both_end];"s,
            "CrossPoint: Join from right"sv);
    p = {XY{100, +10}, XY{50,0}, XY{0,0}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(50,0)[(0:0.5),(1:0),fork:fw:fw:l:r]; XY(0,0)[(0:1),(1:1),overlap:both_end];"s,
            "CrossPoint: Join from left"sv);
    p = {XY{0, +10}, XY{50,0}, XY{100,+10}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(50,0)[(0:0.5),(1:0),touch:l:l:opp];"s,
            "CrossPoint: touch from left opposite"sv);
    p = {XY{0, -10}, XY{50,0}, XY{100,-10}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(50,0)[(0:0.5),(1:0),touch:r:r:opp];"s,
            "CrossPoint: touch from right opposite"sv);
    p = {XY{0,0}, XY{50,0}, XY{40,-10}, XY{60,-10}, XY{50,0}, XY{100,0}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(100,0)[(0:0),(4:1),overlap:opp:both_end]; XY(50,0)[(0:0.5),(1:0),fork:fw:bw:r:r:opp]; XY(50,0)[(0:0.5),(4:0),fork:bw:fw:r:r:opp]; XY(0,0)[(0:1),(0:0),overlap:opp:both_end];"s,
            "CrossPoint: Along, leave to right, join back at same point opposite"sv);
    p = {XY{0,0}, XY{50,0}, XY{40,+10}, XY{60,+10}, XY{50,0}, XY{100,0}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(100,0)[(0:0),(4:1),overlap:opp:both_end]; XY(50,0)[(0:0.5),(1:0),fork:fw:bw:l:l:opp]; XY(50,0)[(0:0.5),(4:0),fork:bw:fw:l:l:opp]; XY(0,0)[(0:1),(0:0),overlap:opp:both_end];"s,
            "CrossPoint: Along, leave to left, join back at same point opposite"sv);

    l = {XY{0,0}, XY{50,0}, XY{40,-10}, XY{60,-10}, XY{50,0}, XY{100,0}};
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation)),
            "XY(0,0)[(0:0),(0:0),overlap:both_end]; XY(50,0)[(1:0),(1:0),fork:bw:bw:r:l]; XY(50,0)[(1:0),(4:0),touch:r:l]; XY(50,0)[(4:0),(1:0),touch:r:l]; XY(50,0)[(4:0),(4:0),fork:fw:fw:r:l]; XY(100,0)[(4:1),(4:1),overlap:both_end];"s,
            "CrossPoint: Along, leave to left & right, join back at same point"sv);
    TAssert(R, to_string(l.CrossPoints(true, nullptr, p, false, nullptr, CalcRelation+OverlapOnly)),
            "XY(0,0)[(0:0),(0:0),overlap:both_end]; XY(50,0)[(0:1),(0:1),fork:bw:bw:r:l]; XY(50,0)[(4:0),(4:0),fork:fw:fw:r:l]; XY(100,0)[(4:1),(4:1),overlap:both_end];"s,
            "CrossPoint: Along, leave to left & right, join back at same point overlap_only"sv);

    //Test degenerate cases
    l = Path{XY(0,0), XY(1,1), XY(2,2)};
    p = Path{XY(0,0), XY(1,1), XY(0,0)};
    TAssert(R, to_string(l.CrossPoints(false, nullptr, p, false, nullptr, CalcRelation)),
            "XY(0,0)[(0:0),(0:0),overlap:both_end]; XY(0,0)[(0:0),(1:1),overlap:opp:both_end]; XY(1,1)[(1:0),(1:0),fork:bw:fw:-:-];"s,
            "CrossPoint: Degenerate overlap"sv);
    l = Path{XY(2,2), XY(1,1), XY(2,2)};
    p = Path{XY(0,0), XY(1,1), XY(0,0)};
    TAssert(R, to_string(l.CrossPoints(false, nullptr, p, false, nullptr, CalcRelation)),
            "XY(1,1)[(1:0),(1:0),cross:?->?:?->?];"s,
            "CrossPoint: Degenerate touch"sv);

    //Test circular paths. Good behaviour on the start/endpoint, good bool returns
    l = {XY(30,0), XY(30, 30), XY(0, 30), XY(0,0), XY(30,0)};
    p = {XY(0,0), XY(30,0), XY(30, 30), XY(0, 30), XY(0,0)};
    cps.clear();
    r = l.CrossPoints(cps, true, nullptr, p, true, nullptr, CalcRelation);
    BAssert(R, r, "Crosspoint: same box, cycled - retval");
    BAssert(R, std::ranges::all_of(cps, [](const CPData& cp) { return cp.type.rel==CPRel::Overlap; }),
            "Crosspoint: same box, cycled - all overlap");
    TAssert(R, cps.size(), size_t(4),
            "Crosspoint: same box, cycled - #crosspoints");

    l = {XY(0,0), XY(10, 0), XY(30,0), XY(30, 30), XY(0, 30), XY(0,0)};
    p = {XY(0,0), XY(20, 0), XY(30,0), XY(30, 30), XY(0, 30), XY(0,0)};
    cps.clear();
    r = l.CrossPoints(cps, true, nullptr, p, true, nullptr, CalcRelation);
    BAssert(R, r, "Crosspoint: same box, cut differently - retval");
    BAssert(R, std::ranges::all_of(cps, [](const CPData& cp) { return cp.type.rel==CPRel::Overlap; }),
            "Crosspoint: same box, cut differently - all overlap");
    TAssert(R, cps.size(), size_t(6),
            "Crosspoint: same box, cut differently - #crosspoints");

    l = {XY(10, 0), XY(30,0), XY(30, 30), XY(0, 30), XY(0,0), XY(10, 0)};
    p = {XY(0,0), XY(20, 0), XY(30,0), XY(30, 30), XY(0, 30), XY(0,0)};
    cps.clear();
    r = l.CrossPoints(cps, true, nullptr, p, true, nullptr, CalcRelation);
    BAssert(R, r, "Crosspoint: same box, cut differently & cycled - retval");
    BAssert(R, std::ranges::all_of(cps, [](const CPData& cp) { return cp.type.rel==CPRel::Overlap; }),
            "Crosspoint: same box, cut differently & cycled - all overlap");
    TAssert(R, cps.size(), size_t(6),
            "Crosspoint: same box, cut differently & cycled - #crosspoints");

    l = p = SimpleContour(0, 30, 0, 30).GetEdges();
    p.back().Split(0.333333333333333333333333333333333, ee, ff);
    _ASSERT(ee.IsStraight());
    _ASSERT(ff.IsStraight());
    l.back() = ee;
    l.push_back(ff);
    p.back().Split(0.666666666666666666666666666666, ee, ff);
    _ASSERT(ee.IsStraight());
    _ASSERT(ff.IsStraight());
    p.back() = ee;
    p.push_back(ff);
    cps.clear();
    r = l.CrossPoints(cps, true, nullptr, p, true, nullptr, CalcRelation);
    BAssert(R, r, "Crosspoint: same box2, cut differently - retval");
    BAssert(R, std::ranges::all_of(cps, [](const CPData& cp) { return cp.type.rel==CPRel::Overlap; }),
            "Crosspoint: same box2, cut differently & cycled - all overlap");
    TAssert(R, cps.size(), size_t(6),
            "Crosspoint: same box2, cut differently & cycled - #crosspoints");

    l = p = SimpleContour(XY(0, 0), 10).GetEdges();
    p.back().Split(0.333333333333333333333333333333333, ee, ff);
    l.back() = ee;
    l.push_back(ff);
    p.back().Split(0.666666666666666666666666666666, ee, ff);
    p.back() = ee;
    p.push_back(ff);
    cps.clear();
    r = l.CrossPoints(cps, true, nullptr, p, true, nullptr, CalcRelation);
    BAssert(R, r, "Crosspoint: same circle, cut differently - retval");
    BAssert(R, std::ranges::all_of(cps, [](const CPData& cp) { return cp.type.rel==CPRel::Overlap; }),
            "Crosspoint: same same circle, cut differently - all overlap");
    TAssert(R, cps.size(), size_t(6),
            "Crosspoint: same same circle, cut differently - #crosspoints");

    //Actual crossing/touching
    c = Block(10, 30, 0, 20);
    TAssert(R, to_string(c.CrossPoints(Path{XY(20,10), XY(40,10)}, false, nullptr, CalcRelation)),
            "XY(30,10)[(1:0.5),(0:0.5),cross:r->l:l->r];"s,
            "CrossPoint: Cross out of box"sv);
    TAssert(R, to_string(c.CrossPoints(Path{XY(0,10), XY(20,10)}, false, nullptr, CalcRelation)),
            "XY(10,10)[(3:0.5),(0:0.5),cross:l->r:r->l];"s,
            "CrossPoint: Cross into box"sv);
    TAssert(R, to_string(c.CrossPoints(Path{XY(10,10), XY(20,10)}, false, nullptr, CalcRelation)),
            "XY(10,10)[(3:0.5),(0:0),touch:r:-:p2_ends];"s,
            "CrossPoint: Touch into box"sv);
    TAssert(R, to_string(c.CrossPoints(Path{XY(30,10), XY(40,10)}, false, nullptr, CalcRelation)),
            "XY(30,10)[(1:0.5),(0:0),touch:l:-:p2_ends];"s,
            "CrossPoint: Touch out of box"sv);
    TAssert(R, to_string(c.CrossPoints(Path{XY(20,-10), XY(40,10)}, false, nullptr, CalcRelation)),
            "XY(30,0)[(1:0),(0:0.5),touch:l:r];"s,
            "CrossPoint: Touch outside of box"sv);

    //Test Leave/Enter
    c = Block(-30, 0, -15, +15);
    cp = c.CrossPoints(SimpleContour(XY(10, 0), 10), CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::True, Tri::True),
            "CrossPoint: Leave/Enter: touch outside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: touch outside 2"sv);
    cp = c.CrossPoints(SimpleContour(XY(-10, 0), 10), CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: touch inside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::True, Tri::True),
            "CrossPoint: Leave/Enter: touch inside 2"sv);
    cp = c.CrossPoints(Edge(XY(-5, 0), XY(0, 0)), CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: end inside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::False, Tri::True),
            "CrossPoint: Leave/Enter: end inside 2"sv);
    cp = c.CrossPoints(Edge(XY(0, 0), XY(-5, 0)), CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: start inside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::True, Tri::False),
            "CrossPoint: Leave/Enter: start inside 2"sv);
    cp = c.CrossPoints(Edge(XY(+5, 0), XY(0, 0)), CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::True, Tri::False),
            "CrossPoint: Leave/Enter: end outside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: end outside 2"sv);
    cp = c.CrossPoints(Edge(XY(0, 0), XY(+5, 0)), CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::False, Tri::True),
            "CrossPoint: Leave/Enter: start outside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: start outside 2"sv);
    cp = c.CrossPoints(Edge(XY(-5, 0), XY(+5, 0)), CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::False, Tri::True),
            "CrossPoint: Leave/Enter: crosses out 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::False, Tri::True),
            "CrossPoint: Leave/Enter: crosses out 1"sv);
    cp = c.CrossPoints(Edge(XY(+5, 0), XY(-5, 0)), CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::True, Tri::False),
            "CrossPoint: Leave/Enter: crosses in 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::True, Tri::False),
            "CrossPoint: Leave/Enter: crosses in 2"sv);

    cp = c.CrossPoints(Path{XY(+5, -5), XY(0,0), XY(0, +5)}, false, nullptr, CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::True, Tri::False),
            "CrossPoint: Leave/Enter: joins from outside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: joins from outside 2"sv);
    cp = c.CrossPoints(Path{XY(-5, -5), XY(0,0), XY(0, +5)}, false, nullptr, CalcRelation).front();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: joins from inside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::False, Tri::True),
            "CrossPoint: Leave/Enter: joins from inside 2"sv);
    cp = c.CrossPoints(Path{XY(0, -5), XY(0,0), XY(+5, +5)}, false, nullptr, CalcRelation).back();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::False, Tri::True),
            "CrossPoint: Leave/Enter: leaves on the outside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: leaves on the outside 2"sv);
    cp = c.CrossPoints(Path{XY(0, -5), XY(0,0), XY(-5, +5)}, false, nullptr, CalcRelation).back();
    TAssert(R, std::pair(cp.enters(true), cp.leaves(true)), std::pair(Tri::False, Tri::False),
            "CrossPoint: Leave/Enter: leaves on the inside 1"sv);
    TAssert(R, std::pair(cp.enters(), cp.leaves()), std::pair(Tri::True, Tri::False),
            "CrossPoint: Leave/Enter: leaves on the inside 2"sv);

    //Check containment
    c.assign(Path{XY(0,0), XY(10,0), XY(10,10), XY(0,10), XY(0,0)});
    d.assign(Path{XY(0,10), XY(0,0), XY(10,0), XY(10,10), XY(0,10)});
    AssertContainment(R, c, d, contour::EContourRelationType::REL_SAME, "Containment: rectangle");

    d.assign(Path{XY(0,0), XY(5,0), XY(5,5), XY(10, 5), XY(10,10), XY(0,10), XY(0,0)}); //rectangle missing its upper-left corner
    AssertContainment(R, c, d, contour::EContourRelationType::REL_B_INSIDE_A, "Containment: rect vs L-shape");

    AssertContainment(R, c.CreateShifted(XY(10, 0)), d, contour::EContourRelationType::REL_APART, "Containment: rect beside L-shape");

    p = Path{XY(10,0), XY(20,0), XY(20,10), XY(10,10), XY(10,0)}; //rectangle shifted left by 10 pixels
    for (int i = 0; i<4; i++) {
        std::rotate(p.begin(), p.begin()+3, p.end());
        d.assign(p);
        AssertContainment(R, c, d, contour::EContourRelationType::REL_APART, "Containment: 2 rects side-by-side "+std::to_string(i+1));
    }

    {
        Contour A(Path{
            Edge(XY(0x1.e3eb851eb852p+6,0x1.28p+4), XY(0x1.e3eb851eb852p+6,0x1.bp+3)),
            Edge(XY(0x1.e3eb851eb852p+6,0x1.bp+3), XY(0x1.04f5c28f5c29p+7,0x1.38p+4)),
            Edge(XY(0x1.04f5c28f5c29p+7,0x1.38p+4), XY(0x1.e3eb851eb852p+6,0x1.98p+4)),
            Edge(XY(0x1.e3eb851eb852p+6,0x1.98p+4), XY(0x1.e3eb851eb852p+6,0x1.48p+4)),
            Edge(XY(0x1.e3eb851eb852p+6,0x1.48p+4), XY(0x1.2ap+6,0x1.48p+4)),
            Edge(XY(0x1.2ap+6,0x1.48p+4), XY(0x1.2ap+6,0x1.28p+4)),
            Edge(XY(0x1.2ap+6,0x1.28p+4), XY(0x1.e3eb851eb852p+6,0x1.28p+4)),
        }, ECloseType::IGNORE_OPEN_PATH, EForceClockwise::DONT);
        Contour B(Path{
            Edge(XY(0x1.32p+6,0x1p+1), XY(0x1.e3eb851eb851fp+6,0x1p+1)),
            Edge(XY(0x1.e3eb851eb851fp+6,0x1p+1), XY(0x1.e3eb851eb851fp+6,0x1.2p+4)),
            Edge(XY(0x1.e3eb851eb851fp+6,0x1.2p+4), XY(0x1.32p+6,0x1.2p+4)),
            Edge(XY(0x1.32p+6,0x1.2p+4), XY(0x1.32p+6,0x1p+1)),
        }, ECloseType::IGNORE_OPEN_PATH, EForceClockwise::DONT);
        TAssert(R, GetSC(R, A, "Relation 1A").RelationTo(GetSC(R, B, "Relation 1B")), REL_APART,
                "Relation 1C");
    }
    {
        constexpr double ratio = 3/7.;
        XY A(50, 90), B(40, 20), M = Mid(A, B, ratio);
        XY p; double pos;
        const double d = SectionPointDistance(A, B, M, &p, &pos);
        DAssert(R, d, 0, "SectionPointDistance 1");
        DAssert(R, pos, ratio, "SectionPointDistance 2");
        DAssert(R, M.x, p.x, "SectionPointDistance 3a");
        DAssert(R, M.y, p.y, "SectionPointDistance 3b");
    }
    {
        Contour A(Path{
            Edge(XY(0x1.58p+6,0x1.c6p+8), XY(0x1.2e46c20c80876p+8,0x1.9c1e16bcfe62p+8)),
            Edge(XY(0x1.2e46c20c80876p+8,0x1.9c1e16bcfe62p+8), XY(0x1.2b02887b796bfp+8,0x1.99p+8)),
            Edge(XY(0x1.2b02887b796bfp+8,0x1.99p+8), XY(0x1.3e6p+8,0x1.99p+8)),
            Edge(XY(0x1.3e6p+8,0x1.99p+8), XY(0x1.384898d2a6a12p+9,0x1.c68cd8241f1p+8)),
            Edge(XY(0x1.384898d2a6a12p+9,0x1.c68cd8241f1p+8), XY(0x1.43p+9,0x1.d6p+8), XY(0x1.3e74f7f7abc53p+9,0x1.c862ef133d1bdp+8), XY(0x1.43p+9,0x1.ce9b98a76f47fp+8)),
            Edge(XY(0x1.43p+9,0x1.d6p+8), XY(0x1.348p+9,0x1.e6p+8), XY(0x1.43p+9,0x1.ded62888a7876p+8), XY(0x1.3c8214bbd7d2ap+9,0x1.e6p+8)),
            Edge(XY(0x1.348p+9,0x1.e6p+8), XY(0x1.58p+6,0x1.e6p+8)),
            Edge(XY(0x1.58p+6,0x1.e6p+8), XY(0x1.58p+6,0x1.c6p+8)),
        }, ECloseType::IGNORE_OPEN_PATH, EForceClockwise::DONT);
        Contour B(Path{
            Edge(XY(0x1.58p+6,0x1.c6p+8), XY(0x1.384898d2a6a12p+9,0x1.c68cd8241f1p+8)),
            Edge(XY(0x1.384898d2a6a12p+9,0x1.c68cd8241f1p+8), XY(0x1.348p+9,0x1.c6p+8), XY(0x1.3713cf5692d75p+9,0x1.c630fe784c0fdp+8), XY(0x1.35cf171394abdp+9,0x1.c6p+8)),
            Edge(XY(0x1.348p+9,0x1.c6p+8), XY(0x1.58p+6,0x1.c6p+8)),
        }, ECloseType::IGNORE_OPEN_PATH, EForceClockwise::DONT);
        TAssert(R, GetSC(R, A, "Relation 2A").RelationTo(GetSC(R, B, "Relation 2B")), REL_B_INSIDE_A,
                "Relation 2C");
    }
    {
        const Edge A(XY(0x1.639e7c047bcbap+8, 0x1.b57a8202546c8p+6), XY(0x1.6524633c747f4p+8, 0x1.ac4809cbfd4d8p+6), XY(0x1.63bbda5f317e7p+8, 0x1.b49d349976358p+6), XY(0x1.64f2ff1a318a7p+8, 0x1.ad3c029dd380ap+6));
        const Edge B(XY(0x1.68f1032a5a050p+8, 0x1.ffc1c736bee31p+6), XY(0x1.5a1d40cfb49e9p+8, 0x1.8369e12d52b37p+6), XY(0x1.68f1032a5a050p+8, 0x1.cdaee185b439bp+6), XY(0x1.6330d853c9c0bp+8, 0x1.a0fb5b2b88230p+6), true, 1);
        auto cps = A.Crossing(B, false);
        TAssert(R, cps.num, 1U, "Spec crossing 1");
        for (unsigned u = 0; u<cps.num; u++) {
            BAssert(R, A.Match(cps.xy[u], cps.pos_my[u]),    "Spec crossing 2 CP"+std::to_string(u));
            BAssert(R, B.Match(cps.xy[u], cps.pos_other[u]), "Spec crossing 3 CP"+std::to_string(u));
        }
    }
    {
        Contour A(Path{
            Edge(XY(0x1.352ff274d2f9ep+8,0x1.2ed56cde59f94p+9), XY(0x1.358p+8,0x1.2fcp+9), XY(0x1.3563ca8b4a63ap+8,0x1.2f1ecc4e97622p+9), XY(0x1.358p+8,0x1.2f6dc07cf75c4p+9)),
            Edge(XY(0x1.358p+8,0x1.2fcp+9), XY(0x1.3p+8,0x1.328p+9), XY(0x1.358p+8,0x1.3144cef77ccb4p+9), XY(0x1.33099deef9968p+8,0x1.328p+9)),
            Edge(XY(0x1.3p+8,0x1.328p+9), XY(0x1.2a8p+8,0x1.2fcp+9), XY(0x1.2cf6621106698p+8,0x1.328p+9), XY(0x1.2a8p+8,0x1.3144cef77ccb4p+9)),
            Edge(XY(0x1.2a8p+8,0x1.2fcp+9), XY(0x1.2acd039bd1adep+8,0x1.2ed9c581fe1c4p+9), XY(0x1.2a8p+8,0x1.2f6f5f9bf56bep+9), XY(0x1.2a9b1b834d8d9p+8,0x1.2f21e99f9ba0dp+9)),
            Edge(XY(0x1.2acd039bd1adep+8,0x1.2ed9c581fe1c4p+9), XY(0x1.352ff274d2f9ep+8,0x1.2ed56cde59f94p+9)),
        }, ECloseType::IGNORE_OPEN_PATH, EForceClockwise::DONT);
        Contour B(Path{
            Edge(XY(0x1.358p+8,0x1.2f4p+9), XY(0x1.358p+8,0x1.304p+9)),
            Edge(XY(0x1.358p+8,0x1.304p+9), XY(0x1.b9p+8,0x1.304p+9)),
            Edge(XY(0x1.b9p+8,0x1.304p+9), XY(0x1.b9p+8,0x1.32cp+9)),
            Edge(XY(0x1.b9p+8,0x1.32cp+9), XY(0x1.c28p+8,0x1.2fcp+9)),
            Edge(XY(0x1.c28p+8,0x1.2fcp+9), XY(0x1.b9p+8,0x1.2ccp+9)),
            Edge(XY(0x1.b9p+8,0x1.2ccp+9), XY(0x1.b9p+8,0x1.2f4p+9)),
            Edge(XY(0x1.b9p+8,0x1.2f4p+9), XY(0x1.358p+8,0x1.2f4p+9)),
        }, ECloseType::IGNORE_OPEN_PATH, EForceClockwise::DONT);
        TAssert(R, GetSC(R, A, "Relation 3A").RelationTo(GetSC(R, B, "Relation 3B")), REL_APART,
                "Relation 3C");
    }
    {
        Edge A(XY(0x1.1d39031f9a38ep+5, 0x1.123de9f852ebdp+6), XY(0x1.34c9b4d6c0d26p+5, 0x1.ddc3d7679bap+5), XY(0x1.27454f572e4fp+5, 0x1.069081a9ff1b9p+6), XY(0x1.2f0df5b9b6d3cp+5, 0x1.f5b9279ab051p+5));
        Edge B(XY(0x1.1d39031f9a38ep+5, 0x1.123de9f852ebcp+6), XY(0x1.238bcb1451b89p+5, 0x1.0ae4a3e3449p+6), true, 1);
        double posA[Edge::MAX_CP], posB[Edge::MAX_CP];
        XY xy[Edge::MAX_CP];
        int num = B.Crossing(A, false, xy, posB, posA);
        TAssert(R, num, 1, "Strange edge case");
    }

    {
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
           Edge(XY(0x1.5fc1cp+9,0x1.f8f7p+9), XY(0x1.5d8b5ca689c6ep+9,0x1.f8f7p+9)),
           Edge(XY(0x1.5d8b5ca689c6ep+9,0x1.f8f7p+9), XY(0x1.48dacp+9,0x1.f622a52b45bf7p+9)),
           Edge(XY(0x1.48dacp+9,0x1.f622a52b45bf7p+9), XY(0x1.48dacp+9,0x1.f097p+9)),
           Edge(XY(0x1.48dacp+9,0x1.f097p+9), XY(0x1.204e0ce9ef1p+9,0x1.f097p+9)),
           Edge(XY(0x1.204e0ce9ef1p+9,0x1.f097p+9), XY(0x1.ae5dbec13afc6p+8,0x1.e697p+9)),
           Edge(XY(0x1.ae5dbec13afc6p+8,0x1.e697p+9), XY(0x1.34fcc0bf1294p+9,0x1.e697p+9)),
           Edge(XY(0x1.34fcc0bf1294p+9,0x1.e697p+9), XY(0x1.52dacp+9,0x1.ed510d72b615fp+9)),
           Edge(XY(0x1.52dacp+9,0x1.ed510d72b615fp+9), XY(0x1.52dacp+9,0x1.eef7p+9)),
           Edge(XY(0x1.52dacp+9,0x1.eef7p+9), XY(0x1.5a2c37a1366ap+9,0x1.eef7p+9)),
           Edge(XY(0x1.5a2c37a1366ap+9,0x1.eef7p+9), XY(0x1.5fc1e9b925593p+9,0x1.f039p+9)),
           Edge(XY(0x1.5fc1e9b925593p+9,0x1.f039p+9), XY(0x1.5fc1cp+9,0x1.f039p+9)),
           Edge(XY(0x1.5fc1cp+9,0x1.f039p+9), XY(0x1.5fc1cp+9,0x1.f8f7p+9)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.c6p+9,0x1.03cp+10), XY(0x1.ae5dbec13afc6p+8,0x1.e697p+9)),
            Edge(XY(0x1.ae5dbec13afc6p+8,0x1.e697p+9), XY(0x1.5fc1e9b925593p+9,0x1.f039p+9)),
            Edge(XY(0x1.5fc1e9b925593p+9,0x1.f039p+9), XY(0x1.c6p+9,0x1.03cp+10)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        UnionAssert(R, A, B, "Union 1");
    }

    {
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.22ee0ae381322p+6,0x1.01fec06ddb9aap+6), XY(0x1.2d353b8a6e8cdp+6,0x1.f763640a54269p+5)),
            Edge(XY(0x1.2d353b8a6e8cdp+6,0x1.f763640a54269p+5), XY(0x1.33da4a2c31058p+6,0x1.ee698e8f07a8dp+5)),
            Edge(XY(0x1.33da4a2c31058p+6,0x1.ee698e8f07a8dp+5), XY(0x1.3a61260f98bc6p+6,0x1.e4bf1565a52b9p+5)),
            Edge(XY(0x1.3a61260f98bc6p+6,0x1.e4bf1565a52b9p+5), XY(0x1.481f256d49ddbp+6,0x1.ce7bb53e0b99dp+5)),
            Edge(XY(0x1.481f256d49ddbp+6,0x1.ce7bb53e0b99dp+5), XY(0x1.4757ffcb052ffp+6,0x1.e1292af52b278p+5), true, 1),
            Edge(XY(0x1.4757ffcb052ffp+6,0x1.e1292af52b278p+5), XY(0x1.3dcca64de4ec5p+6,0x1.206fda5d75ae0p+6), XY(0x1.4602431cfd732p+6,0x1.009b15ebb6bfap+6), XY(0x1.42cbd9ab95717p+6,0x1.10c293fa8efd9p+6)),
            Edge(XY(0x1.3dcca64de4ec5p+6,0x1.206fda5d75ae0p+6), XY(0x1.3b2e70a25bb76p+6,0x1.28a685a34c17cp+6), true, 1),
            Edge(XY(0x1.3b2e70a25bb76p+6,0x1.28a685a34c17cp+6), XY(0x1.22ee0ae381322p+6,0x1.01fec06ddb9aap+6)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.1664c0abe5eadp+6,0x1.2988cb930b96dp+6), XY(0x1.21d9baad6453ep+6,0x1.258940b569cf7p+6)),
            Edge(XY(0x1.21d9baad6453ep+6,0x1.258940b569cf7p+6), XY(0x1.295b12bfc33dap+6,0x1.229255ca4b578p+6)),
            Edge(XY(0x1.295b12bfc33dap+6,0x1.229255ca4b578p+6), XY(0x1.30cb219e45d52p+6,0x1.1f48a23b994b8p+6)),
            Edge(XY(0x1.30cb219e45d52p+6,0x1.1f48a23b994b8p+6), XY(0x1.40a68bbb80c5bp+6,0x1.177df04fcc858p+6)),
            Edge(XY(0x1.40a68bbb80c5bp+6,0x1.177df04fcc858p+6), XY(0x1.3dcc9ffd77810p+6,0x1.206fee2cb6c85p+6), true, 1),
            Edge(XY(0x1.3dcc9ffd77810p+6,0x1.206fee2cb6c85p+6), XY(0x1.2a32111a1d67ep+6,0x1.4d102132281a3p+6), XY(0x1.38fc686435803p+6,0x1.2f89c8a43b94ep+6), XY(0x1.3264ecb619452p+6,0x1.3e96a46262737p+6)),
            Edge(XY(0x1.2a32111a1d67ep+6,0x1.4d102132281a3p+6), XY(0x1.25e69771b1c85p+6,0x1.54a53aa5dd183p+6), true, 1),
            Edge(XY(0x1.25e69771b1c85p+6,0x1.54a53aa5dd183p+6), XY(0x1.1664c0abe5eadp+6,0x1.2988cb930b96dp+6)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        UnionAssert(R, A, B, "Union 2");
    }

    {
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.ff8e4p+7,0x1.0ae9f3c689ff4p+9), XY(0x1.ff8e4p+7,0x1.1352p+9)),
            Edge(XY(0x1.ff8e4p+7,0x1.1352p+9), XY(0x1.67512f785ef0cp+7,0x1.1352p+9)),
            Edge(XY(0x1.67512f785ef0cp+7,0x1.1352p+9), XY(0x1.763dcf519ea34p+7,0x1.0952p+9)),
            Edge(XY(0x1.763dcf519ea34p+7,0x1.0952p+9), XY(0x1.fabba6a14d42ap+7,0x1.0952p+9)),
            Edge(XY(0x1.fabba6a14d42ap+7,0x1.0952p+9), XY(0x1.ff8e4p+7,0x1.0ae9f3c689ff4p+9)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.6fp+8,0x1.b8p+8), XY(0x1.75p+8,0x1.d8p+8), XY(0x1.72504f333ed2cp+8,0x1.b8p+8), XY(0x1.75p+8,0x1.c653aeeeb0f15p+8)),
            Edge(XY(0x1.75p+8,0x1.d8p+8), XY(0x1.6fp+8,0x1.f8p+8), XY(0x1.75p+8,0x1.e9ac51114f0ebp+8), XY(0x1.72504f333ed2cp+8,0x1.f8p+8)),
            Edge(XY(0x1.6fp+8,0x1.f8p+8), XY(0x1.98p+5,0x1.f8p+8)),
            Edge(XY(0x1.98p+5,0x1.f8p+8), XY(0x1.68p+5,0x1.d8p+8), XY(0x1.7d7d8666096ap+5,0x1.f8p+8), XY(0x1.68p+5,0x1.e9ac51114f0ebp+8)),
            Edge(XY(0x1.68p+5,0x1.d8p+8), XY(0x1.98p+5,0x1.b8p+8), XY(0x1.68p+5,0x1.c653aeeeb0f15p+8), XY(0x1.7d7d8666096ap+5,0x1.b8p+8)),
            Edge(XY(0x1.98p+5,0x1.b8p+8), XY(0x1.6fp+8,0x1.b8p+8)),
        }),ContourList::UnsafeMake({})),}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.67512f785ef0cp+7,0x1.1352p+9), XY(0x1.94b29daf964cp+5,0x1.f7eceab497278p+8)),
            Edge(XY(0x1.94b29daf964cp+5,0x1.f7eceab497278p+8), XY(0x1.6f79880902465p+8,0x1.f7e6bbc9d8cc8p+8)),
            Edge(XY(0x1.6f79880902465p+8,0x1.f7e6bbc9d8cc8p+8), XY(0x1.67512f785ef0cp+7,0x1.1352p+9)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        UnionAssert(R, A, B, "Union 3");
    }

    {
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.8509619343574p+6,0x1.7f2ep+9), XY(0x1.a90fd2a2067ep+6,0x1.7bd2p+9)),
            Edge(XY(0x1.a90fd2a2067ep+6,0x1.7bd2p+9), XY(0x1.6471cp+7,0x1.7bd2p+9)),
            Edge(XY(0x1.6471cp+7,0x1.7bd2p+9), XY(0x1.6471cp+7,0x1.7f2ep+9)),
            Edge(XY(0x1.6471cp+7,0x1.7f2ep+9), XY(0x1.8509619343574p+6,0x1.7f2ep+9)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.6fp+8,0x1.3c8p+9), XY(0x1.75p+8,0x1.558p+9), XY(0x1.72504f333ed2cp+8,0x1.3c8p+9), XY(0x1.75p+8,0x1.47b160aa7a3c8p+9)),
            Edge(XY(0x1.75p+8,0x1.558p+9), XY(0x1.6fp+8,0x1.6e8p+9), XY(0x1.75p+8,0x1.634e9f5585c38p+9), XY(0x1.72504f333ed2cp+8,0x1.6e8p+9)),
            Edge(XY(0x1.6fp+8,0x1.6e8p+9), XY(0x1.98p+5,0x1.6e8p+9)),
            Edge(XY(0x1.98p+5,0x1.6e8p+9), XY(0x1.68p+5,0x1.558p+9), XY(0x1.7d7d8666096ap+5,0x1.6e8p+9), XY(0x1.68p+5,0x1.634e9f5585c38p+9)),
            Edge(XY(0x1.68p+5,0x1.558p+9), XY(0x1.98p+5,0x1.3c8p+9), XY(0x1.68p+5,0x1.47b160aa7a3c8p+9), XY(0x1.7d7d8666096ap+5,0x1.3c8p+9)),
            Edge(XY(0x1.98p+5,0x1.3c8p+9), XY(0x1.6fp+8,0x1.3c8p+9)),
        }),ContourList::UnsafeMake({})),}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.8509619343574p+6,0x1.7f2ep+9), XY(0x1.93d26741cd0d2p+5,0x1.6e68172dbf4c3p+9)),
            Edge(XY(0x1.93d26741cd0d2p+5,0x1.6e68172dbf4c3p+9), XY(0x1.6f212842083a6p+8,0x1.6e7e89d23e10dp+9)),
            Edge(XY(0x1.6f212842083a6p+8,0x1.6e7e89d23e10dp+9), XY(0x1.8509619343574p+6,0x1.7f2ep+9)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        UnionAssert(R, A, B, "Union 4");
    }

    {
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.6071cp+7,0x1.0952p+9), XY(0x1.763dcf519ea34p+7,0x1.0952p+9)),
            Edge(XY(0x1.763dcf519ea34p+7,0x1.0952p+9), XY(0x1.67512f785ef0cp+7,0x1.1352p+9)),
            Edge(XY(0x1.67512f785ef0cp+7,0x1.1352p+9), XY(0x1.6071cp+7,0x1.1352p+9)),
            Edge(XY(0x1.6071cp+7,0x1.1352p+9), XY(0x1.6071cp+7,0x1.0952p+9)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.6fp+8,0x1.b8p+8), XY(0x1.75p+8,0x1.d8p+8), XY(0x1.72504f333ed2cp+8,0x1.b8p+8), XY(0x1.75p+8,0x1.c653aeeeb0f15p+8)),
            Edge(XY(0x1.75p+8,0x1.d8p+8), XY(0x1.6fp+8,0x1.f8p+8), XY(0x1.75p+8,0x1.e9ac51114f0ebp+8), XY(0x1.72504f333ed2cp+8,0x1.f8p+8)),
            Edge(XY(0x1.6fp+8,0x1.f8p+8), XY(0x1.98p+5,0x1.f8p+8)),
            Edge(XY(0x1.98p+5,0x1.f8p+8), XY(0x1.68p+5,0x1.d8p+8), XY(0x1.7d7d8666096ap+5,0x1.f8p+8), XY(0x1.68p+5,0x1.e9ac51114f0ebp+8)),
            Edge(XY(0x1.68p+5,0x1.d8p+8), XY(0x1.98p+5,0x1.b8p+8), XY(0x1.68p+5,0x1.c653aeeeb0f15p+8), XY(0x1.7d7d8666096ap+5,0x1.b8p+8)),
            Edge(XY(0x1.98p+5,0x1.b8p+8), XY(0x1.6fp+8,0x1.b8p+8)),
        }),ContourList::UnsafeMake({})),}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.6071cp+7,0x1.1352p+9), XY(0x1.949f13258bacp+5,0x1.f7ec0573dbc54p+8)),
            Edge(XY(0x1.949f13258bacp+5,0x1.f7ec0573dbc54p+8), XY(0x1.6f48989ea0878p+8,0x1.f7f7030322c15p+8)),
            Edge(XY(0x1.6f48989ea0878p+8,0x1.f7f7030322c15p+8), XY(0x1.6071cp+7,0x1.1352p+9)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        UnionAssert(R, A, B, "Union 5");
    }
    {
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.cf7b81db65819p+7,0x1.4ep+7), XY(0x1.9dfef9db22d0ep+7,0x1.f4b45c22e65dap+6)),
            Edge(XY(0x1.9dfef9db22d0ep+7,0x1.f4b45c22e65dap+6), XY(0x1.e4cda703188b1p+7,0x1.4ep+7)),
            Edge(XY(0x1.e4cda703188b1p+7,0x1.4ep+7), XY(0x1.084a3d70a3d71p+8,0x1.4ep+7)),
            Edge(XY(0x1.084a3d70a3d71p+8,0x1.4ep+7), XY(0x1.084a3d70a3d71p+8,0x1.82p+7)),
            Edge(XY(0x1.084a3d70a3d71p+8,0x1.82p+7), XY(0x1.c76b851eb851fp+7,0x1.82p+7)),
            Edge(XY(0x1.c76b851eb851fp+7,0x1.82p+7), XY(0x1.c76b851eb851fp+7,0x1.4ep+7)),
            Edge(XY(0x1.c76b851eb851fp+7,0x1.4ep+7), XY(0x1.cf7b81db65819p+7,0x1.4ep+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.9ep+7,0x1.03p+7), XY(0x1.9ep+7,0x1.f2p+6)),
            Edge(XY(0x1.9ep+7,0x1.f2p+6), XY(0x1.b1p+7,0x1.05p+7)),
            Edge(XY(0x1.b1p+7,0x1.05p+7), XY(0x1.9ep+7,0x1.11p+7)),
            Edge(XY(0x1.9ep+7,0x1.11p+7), XY(0x1.9ep+7,0x1.07p+7)),
            Edge(XY(0x1.9ep+7,0x1.07p+7), XY(0x1.62p+6,0x1.07p+7)),
            Edge(XY(0x1.62p+6,0x1.07p+7), XY(0x1.62p+6,0x1.03p+7)),
            Edge(XY(0x1.62p+6,0x1.03p+7), XY(0x1.9ep+7,0x1.03p+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.6a020c49ba5e3p+6,0x1.c4p+6), XY(0x1.9dfef9db22d0ep+7,0x1.c4p+6)),
            Edge(XY(0x1.9dfef9db22d0ep+7,0x1.c4p+6), XY(0x1.9dfef9db22d0ep+7,0x1.02p+7)),
            Edge(XY(0x1.9dfef9db22d0ep+7,0x1.02p+7), XY(0x1.6a020c49ba5e3p+6,0x1.02p+7)),
            Edge(XY(0x1.6a020c49ba5e3p+6,0x1.02p+7), XY(0x1.6a020c49ba5e3p+6,0x1.c4p+6)),
        }),ContourList::UnsafeMake({})),}));
        IntersectAssert(R, A, B, "Intersect 1");
    }

    {
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.634e2c108178ap+10,0x1.4cf5273ef513ap+7), XY(0x1.59p+10,0x1.1e8p+7)),
            Edge(XY(0x1.59p+10,0x1.1e8p+7), XY(0x1.687388e4d3c3fp+10,0x1.4cf5273ef513ap+7)),
            Edge(XY(0x1.687388e4d3c3fp+10,0x1.4cf5273ef513ap+7), XY(0x1.73f16991cfedap+10,0x1.4cf5273ef513ap+7)),
            Edge(XY(0x1.73f16991cfedap+10,0x1.4cf5273ef513ap+7), XY(0x1.75316991cfedap+10,0x1.56f5273ef513ap+7), XY(0x1.74a224bc7d043p+10,0x1.4cf5273ef513ap+7), XY(0x1.75316991cfedap+10,0x1.516f4de98c5f1p+7)),
            Edge(XY(0x1.75316991cfedap+10,0x1.56f5273ef513ap+7), XY(0x1.75316991cfedap+10,0x1.643d273ef513ap+7)),
            Edge(XY(0x1.75316991cfedap+10,0x1.643d273ef513ap+7), XY(0x1.73f16991cfedap+10,0x1.6e3d273ef513ap+7), XY(0x1.75316991cfedap+10,0x1.69c300945dc83p+7), XY(0x1.74a224bc7d043p+10,0x1.6e3d273ef513ap+7)),
            Edge(XY(0x1.73f16991cfedap+10,0x1.6e3d273ef513ap+7), XY(0x1.5fe2b991cfedap+10,0x1.6e3d273ef513ap+7)),
            Edge(XY(0x1.5fe2b991cfedap+10,0x1.6e3d273ef513ap+7), XY(0x1.5ea2b991cfedap+10,0x1.643d273ef513ap+7), XY(0x1.5f31fe6722d71p+10,0x1.6e3d273ef513ap+7), XY(0x1.5ea2b991cfedap+10,0x1.69c300945dc83p+7)),
            Edge(XY(0x1.5ea2b991cfedap+10,0x1.643d273ef513ap+7), XY(0x1.5ea2b991cfedap+10,0x1.56f5273ef513ap+7)),
            Edge(XY(0x1.5ea2b991cfedap+10,0x1.56f5273ef513ap+7), XY(0x1.5fe2b991cfedap+10,0x1.4cf5273ef513ap+7), XY(0x1.5ea2b991cfedap+10,0x1.516f4de98c5f1p+7), XY(0x1.5f31fe6722d71p+10,0x1.4cf5273ef513ap+7)),
            Edge(XY(0x1.5fe2b991cfedap+10,0x1.4cf5273ef513ap+7), XY(0x1.634e2c108178ap+10,0x1.4cf5273ef513ap+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.a2c08p+10,0x1.acp+7), XY(0x1.d6bf8p+10,0x1.acp+7)),
            Edge(XY(0x1.d6bf8p+10,0x1.acp+7), XY(0x1.d6bf8p+10,0x1.06p+8)),
            Edge(XY(0x1.d6bf8p+10,0x1.06p+8), XY(0x1.a2c08p+10,0x1.06p+8)),
            Edge(XY(0x1.a2c08p+10,0x1.06p+8), XY(0x1.a2c08p+10,0x1.acp+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.b91p+10,0x1.9p+7), XY(0x1.b91p+10,0x1.85p+7)),
            Edge(XY(0x1.b91p+10,0x1.85p+7), XY(0x1.bc8p+10,0x1.96p+7)),
            Edge(XY(0x1.bc8p+10,0x1.96p+7), XY(0x1.b91p+10,0x1.a7p+7)),
            Edge(XY(0x1.b91p+10,0x1.a7p+7), XY(0x1.b91p+10,0x1.9cp+7)),
            Edge(XY(0x1.b91p+10,0x1.9cp+7), XY(0x1.03p+9,0x1.9cp+7)),
            Edge(XY(0x1.03p+9,0x1.9cp+7), XY(0x1.03p+9,0x1.9p+7)),
            Edge(XY(0x1.03p+9,0x1.9p+7), XY(0x1.b91p+10,0x1.9p+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.0f72p+10,0x1.68p+7), XY(0x1.2b9ep+10,0x1.68p+7)),
            Edge(XY(0x1.2b9ep+10,0x1.68p+7), XY(0x1.2b9ep+10,0x1.8d4p+7)),
            Edge(XY(0x1.2b9ep+10,0x1.8d4p+7), XY(0x1.0f72p+10,0x1.8d4p+7)),
            Edge(XY(0x1.0f72p+10,0x1.8d4p+7), XY(0x1.0f72p+10,0x1.68p+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.17a908p+10,0x1.9d4p+7), XY(0x1.2366f8p+10,0x1.9d4p+7)),
            Edge(XY(0x1.2366f8p+10,0x1.9d4p+7), XY(0x1.2366f8p+10,0x1.b488p+7)),
            Edge(XY(0x1.2366f8p+10,0x1.b488p+7), XY(0x1.17a908p+10,0x1.b488p+7)),
            Edge(XY(0x1.17a908p+10,0x1.b488p+7), XY(0x1.17a908p+10,0x1.9d4p+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.fa8p+8,0x1.88p+7), XY(0x1.fa8p+8,0x1.7ep+7)),
            Edge(XY(0x1.fa8p+8,0x1.7ep+7), XY(0x1.02p+9,0x1.8ap+7)),
            Edge(XY(0x1.02p+9,0x1.8ap+7), XY(0x1.fa8p+8,0x1.96p+7)),
            Edge(XY(0x1.fa8p+8,0x1.96p+7), XY(0x1.fa8p+8,0x1.8cp+7)),
            Edge(XY(0x1.fa8p+8,0x1.8cp+7), XY(0x1.ap+3,0x1.8cp+7)),
            Edge(XY(0x1.ap+3,0x1.8cp+7), XY(0x1.ap+3,0x1.88p+7)),
            Edge(XY(0x1.ap+3,0x1.88p+7), XY(0x1.fa8p+8,0x1.88p+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.6ceap+7,0x1.6p+7), XY(0x1.540bp+8,0x1.6p+7)),
            Edge(XY(0x1.540bp+8,0x1.6p+7), XY(0x1.540bp+8,0x1.854p+7)),
            Edge(XY(0x1.540bp+8,0x1.854p+7), XY(0x1.6ceap+7,0x1.854p+7)),
            Edge(XY(0x1.6ceap+7,0x1.854p+7), XY(0x1.6ceap+7,0x1.6p+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.db884p+7,0x1.8d4p+7), XY(0x1.1cbbep+8,0x1.8d4p+7)),
            Edge(XY(0x1.1cbbep+8,0x1.8d4p+7), XY(0x1.1cbbep+8,0x1.a488p+7)),
            Edge(XY(0x1.1cbbep+8,0x1.a488p+7), XY(0x1.db884p+7,0x1.a488p+7)),
            Edge(XY(0x1.db884p+7,0x1.a488p+7), XY(0x1.db884p+7,0x1.8d4p+7)),
        }),ContourList::UnsafeMake({})),}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.5afp+10,0x1.4bp+7), XY(0x1.59p+10,0x1.5a8p+7), XY(0x1.5afp+10,0x1.538f7744624b2p+7), XY(0x1.5a11eee88c496p+10,0x1.5a8p+7)),
            Edge(XY(0x1.59p+10,0x1.5a8p+7), XY(0x1.571p+10,0x1.4bp+7), XY(0x1.57ee111773b6ap+10,0x1.5a8p+7), XY(0x1.571p+10,0x1.538f7744624b2p+7)),
            Edge(XY(0x1.571p+10,0x1.4bp+7), XY(0x1.59p+10,0x1.3b8p+7), XY(0x1.571p+10,0x1.427088bb9db4ep+7), XY(0x1.57ee111773b6ap+10,0x1.3b8p+7)),
            Edge(XY(0x1.59p+10,0x1.3b8p+7), XY(0x1.5afp+10,0x1.4bp+7), XY(0x1.5a11eee88c496p+10,0x1.3b8p+7), XY(0x1.5afp+10,0x1.427088bb9db4ep+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.5afp+10,0x1.49p+7), XY(0x1.e1dp+10,0x1.49p+7)),
            Edge(XY(0x1.e1dp+10,0x1.49p+7), XY(0x1.e1dp+10,0x1.3ap+7)),
            Edge(XY(0x1.e1dp+10,0x1.3ap+7), XY(0x1.e54p+10,0x1.4bp+7)),
            Edge(XY(0x1.e54p+10,0x1.4bp+7), XY(0x1.e1dp+10,0x1.5cp+7)),
            Edge(XY(0x1.e1dp+10,0x1.5cp+7), XY(0x1.e1dp+10,0x1.4dp+7)),
            Edge(XY(0x1.e1dp+10,0x1.4dp+7), XY(0x1.5afp+10,0x1.4dp+7)),
            Edge(XY(0x1.5afp+10,0x1.4dp+7), XY(0x1.5afp+10,0x1.49p+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.1fcp+8,0x1.4bp+7), XY(0x1.18p+8,0x1.5a8p+7), XY(0x1.1fcp+8,0x1.538f7744624b2p+7), XY(0x1.1c47bba231259p+8,0x1.5a8p+7)),
            Edge(XY(0x1.18p+8,0x1.5a8p+7), XY(0x1.104p+8,0x1.4bp+7), XY(0x1.13b8445dceda7p+8,0x1.5a8p+7), XY(0x1.104p+8,0x1.538f7744624b2p+7)),
            Edge(XY(0x1.104p+8,0x1.4bp+7), XY(0x1.18p+8,0x1.3b8p+7), XY(0x1.104p+8,0x1.427088bb9db4ep+7), XY(0x1.13b8445dceda7p+8,0x1.3b8p+7)),
            Edge(XY(0x1.18p+8,0x1.3b8p+7), XY(0x1.1fcp+8,0x1.4bp+7), XY(0x1.1c47bba231259p+8,0x1.3b8p+7), XY(0x1.1fcp+8,0x1.427088bb9db4ep+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.1fcp+8,0x1.45p+7), XY(0x1.571p+10,0x1.45p+7)),
            Edge(XY(0x1.571p+10,0x1.45p+7), XY(0x1.571p+10,0x1.51p+7)),
            Edge(XY(0x1.571p+10,0x1.51p+7), XY(0x1.1fcp+8,0x1.51p+7)),
            Edge(XY(0x1.1fcp+8,0x1.51p+7), XY(0x1.1fcp+8,0x1.45p+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.cd0dp+9,0x1.1ap+7), XY(0x1.07098p+10,0x1.1ap+7)),
            Edge(XY(0x1.07098p+10,0x1.1ap+7), XY(0x1.07098p+10,0x1.3f4p+7)),
            Edge(XY(0x1.07098p+10,0x1.3f4p+7), XY(0x1.cd0dp+9,0x1.3f4p+7)),
            Edge(XY(0x1.cd0dp+9,0x1.3f4p+7), XY(0x1.cd0dp+9,0x1.1ap+7)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.6cp+5,0x1.41p+7), XY(0x1.104p+8,0x1.41p+7)),
            Edge(XY(0x1.104p+8,0x1.41p+7), XY(0x1.104p+8,0x1.55p+7)),
            Edge(XY(0x1.104p+8,0x1.55p+7), XY(0x1.6cp+5,0x1.55p+7)),
            Edge(XY(0x1.6cp+5,0x1.55p+7), XY(0x1.6cp+5,0x1.41p+7)),
        }),ContourList::UnsafeMake({})),}));
        UnionAssert(R, A, B, "Union 6");
    }
    {
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.2c48139908494p+8,0x1.12p+9), XY(0x1.43e1d1dca3ca9p+8,0x1.04cp+9)),
            Edge(XY(0x1.43e1d1dca3ca9p+8,0x1.04cp+9), XY(0x1.350147ae147aep+8,0x1.124f79ee24e66p+9)),
            Edge(XY(0x1.350147ae147aep+8,0x1.124f79ee24e66p+9), XY(0x1.350147ae147aep+8,0x1.1fp+9)),
            Edge(XY(0x1.350147ae147aep+8,0x1.1fp+9), XY(0x1.1afeb851eb852p+8,0x1.1fp+9)),
            Edge(XY(0x1.1afeb851eb852p+8,0x1.1fp+9), XY(0x1.1afeb851eb852p+8,0x1.12p+9)),
            Edge(XY(0x1.1afeb851eb852p+8,0x1.12p+9), XY(0x1.2c48139908494p+8,0x1.12p+9)),
                                                                                                 }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.348p+8,0x1.adp+8), XY(0x1.1ee0f1266407p+8,0x1.adp+8)),
            Edge(XY(0x1.1ee0f1266407p+8,0x1.adp+8), XY(0x1.0bp+8,0x1.991f0ed99bf9p+8)),
            Edge(XY(0x1.0bp+8,0x1.991f0ed99bf9p+8), XY(0x1.0bp+8,0x1.94e0f1266407p+8)),
            Edge(XY(0x1.0bp+8,0x1.94e0f1266407p+8), XY(0x1.1ee0f1266407p+8,0x1.81p+8)),
            Edge(XY(0x1.1ee0f1266407p+8,0x1.81p+8), XY(0x1.330f876ccdfc8p+9,0x1.81p+8)),
            Edge(XY(0x1.330f876ccdfc8p+9,0x1.81p+8), XY(0x1.3dp+9,0x1.94e0f1266407p+8)),
            Edge(XY(0x1.3dp+9,0x1.94e0f1266407p+8), XY(0x1.3dp+9,0x1.991f0ed99bf9p+8)),
            Edge(XY(0x1.3dp+9,0x1.991f0ed99bf9p+8), XY(0x1.330f876ccdfc8p+9,0x1.adp+8)),
            Edge(XY(0x1.330f876ccdfc8p+9,0x1.adp+8), XY(0x1.284p+9,0x1.adp+8)),
            Edge(XY(0x1.284p+9,0x1.adp+8), XY(0x1.3856309cdd6d1p+9,0x1.ba539ec64525ep+8), XY(0x1.2e68408ac85e6p+9,0x1.adp+8), XY(0x1.345231f7cd16ap+9,0x1.b24ba17c24791p+8)),
            Edge(XY(0x1.3856309cdd6d1p+9,0x1.ba539ec64525ep+8), XY(0x1.3fp+9,0x1.da8p+8), XY(0x1.3c5a2f41edc38p+9,0x1.c25b9c1065d2dp+8), XY(0x1.3fp+9,0x1.ce2f7eea6f431p+8)),
            Edge(XY(0x1.3fp+9,0x1.da8p+8), XY(0x1.3fp+9,0x1.ed8p+8)),
            Edge(XY(0x1.3fp+9,0x1.ed8p+8), XY(0x1.3856309cdd6d1p+9,0x1.06d6309cdd6d1p+9), XY(0x1.3fp+9,0x1.f9d0811590bcfp+8), XY(0x1.3c5a2f41edc38p+9,0x1.02d231f7cd16ap+9)),
            Edge(XY(0x1.3856309cdd6d1p+9,0x1.06d6309cdd6d1p+9), XY(0x1.284p+9,0x1.0d8p+9), XY(0x1.345231f7cd16ap+9,0x1.0ada2f41edc38p+9), XY(0x1.2e68408ac85e7p+9,0x1.0d8p+9)),
            Edge(XY(0x1.284p+9,0x1.0d8p+9), XY(0x1.330f876ccdfc8p+9,0x1.0d8p+9)),
            Edge(XY(0x1.330f876ccdfc8p+9,0x1.0d8p+9), XY(0x1.3dp+9,0x1.1770789332038p+9)),
            Edge(XY(0x1.3dp+9,0x1.1770789332038p+9), XY(0x1.3dp+9,0x1.238p+9)),
            Edge(XY(0x1.3dp+9,0x1.238p+9), XY(0x1.0bp+8,0x1.238p+9)),
            Edge(XY(0x1.0bp+8,0x1.238p+9), XY(0x1.0bp+8,0x1.0d8p+9)),
            Edge(XY(0x1.0bp+8,0x1.0d8p+9), XY(0x1.348p+8,0x1.0d8p+9)),
            Edge(XY(0x1.348p+8,0x1.0d8p+9), XY(0x1.14539ec64525ep+8,0x1.06d6309cdd6d1p+9), XY(0x1.282f7eea6f432p+8,0x1.0d8p+9), XY(0x1.1c5b9c1065d2cp+8,0x1.0ada2f41edc38p+9)),
            Edge(XY(0x1.14539ec64525ep+8,0x1.06d6309cdd6d1p+9), XY(0x1.11p+8,0x1.04f77bb143fep+9), XY(0x1.1328386c2d0b6p+8,0x1.06407d6fd15fdp+9), XY(0x1.120bac27a77c7p+8,0x1.05a07c28f6034p+9)),
            Edge(XY(0x1.11p+8,0x1.04f77bb143fep+9), XY(0x1.11p+8,0x1.0cp+9)),
            Edge(XY(0x1.11p+8,0x1.0cp+9), XY(0x1.1p+7,0x1.0cp+9)),
            Edge(XY(0x1.1p+7,0x1.0cp+9), XY(0x1.1p+7,0x1.fap+8)),
            Edge(XY(0x1.1p+7,0x1.fap+8), XY(0x1.041f0ed99bf9p+8,0x1.fap+8)),
            Edge(XY(0x1.041f0ed99bf9p+8,0x1.fap+8), XY(0x1.0bc7879981c02p+8,0x1.00d43c5ff2e3bp+9)),
            Edge(XY(0x1.0bc7879981c02p+8,0x1.00d43c5ff2e3bp+9), XY(0x1.07p+8,0x1.ed8p+8), XY(0x1.08c18e3166ff3p+8,0x1.fb85827a7d1b1p+8), XY(0x1.07p+8,0x1.f4976af645fcep+8)),
            Edge(XY(0x1.07p+8,0x1.ed8p+8), XY(0x1.07p+8,0x1.da8p+8)),
            Edge(XY(0x1.07p+8,0x1.da8p+8), XY(0x1.14539ec64525ep+8,0x1.ba539ec64525ep+8), XY(0x1.07p+8,0x1.ce2f7eea6f433p+8), XY(0x1.0c4ba17c24791p+8,0x1.c25b9c1065d2bp+8)),
            Edge(XY(0x1.14539ec64525ep+8,0x1.ba539ec64525ep+8), XY(0x1.348p+8,0x1.adp+8), XY(0x1.1c5b9c1065d2cp+8,0x1.b24ba17c2479p+8), XY(0x1.282f7eea6f432p+8,0x1.adp+8)),
        }), ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.0bp+8,0x1.da8p+8), XY(0x1.0bp+8,0x1.ed8p+8)),
            Edge(XY(0x1.0bp+8,0x1.ed8p+8), XY(0x1.348p+8,0x1.0b8p+9), XY(0x1.0bp+8,0x1.0235bc9139438p+9), XY(0x1.1d9486dd8d78fp+8,0x1.0b8p+9)),
            Edge(XY(0x1.348p+8,0x1.0b8p+9), XY(0x1.284p+9,0x1.0b8p+9)),
            Edge(XY(0x1.284p+9,0x1.0b8p+9), XY(0x1.3dp+9,0x1.ed8p+8), XY(0x1.33b5bc9139438p+9,0x1.0b8p+9), XY(0x1.3dp+9,0x1.0235bc9139438p+9)),
            Edge(XY(0x1.3dp+9,0x1.ed8p+8), XY(0x1.3dp+9,0x1.da8p+8)),
            Edge(XY(0x1.3dp+9,0x1.da8p+8), XY(0x1.284p+9,0x1.b1p+8), XY(0x1.3dp+9,0x1.c39486dd8d78fp+8), XY(0x1.33b5bc9139438p+9,0x1.b1p+8)),
            Edge(XY(0x1.284p+9,0x1.b1p+8), XY(0x1.348p+8,0x1.b1p+8)),
            Edge(XY(0x1.348p+8,0x1.b1p+8), XY(0x1.0bp+8,0x1.da8p+8), XY(0x1.1d9486dd8d78fp+8,0x1.b1p+8), XY(0x1.0bp+8,0x1.c39486dd8d78fp+8)),
        }),ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.169533c17d985p+9,0x1.cf8p+8), XY(0x1.153f5c28f5c29p+9,0x1.cf8p+8)),
            Edge(XY(0x1.153f5c28f5c29p+9,0x1.cf8p+8), XY(0x1.153f5c28f5c29p+9,0x1.b68p+8)),
            Edge(XY(0x1.153f5c28f5c29p+9,0x1.b68p+8), XY(0x1.21c0a3d70a3d7p+9,0x1.b68p+8)),
            Edge(XY(0x1.21c0a3d70a3d7p+9,0x1.b68p+8), XY(0x1.21c0a3d70a3d7p+9,0x1.cf8p+8)),
            Edge(XY(0x1.21c0a3d70a3d7p+9,0x1.cf8p+8), XY(0x1.1ab69e0595552p+9,0x1.cf8p+8)),
            Edge(XY(0x1.1ab69e0595552p+9,0x1.cf8p+8), XY(0x1.121a17fb0c74bp+9,0x1.ea8p+8)),
            Edge(XY(0x1.121a17fb0c74bp+9,0x1.ea8p+8), XY(0x1.169533c17d985p+9,0x1.cf8p+8)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.268cc34ae392ap+8,0x1.b6p+8), XY(0x1.f94f52a70c886p+8,0x1.b6p+8)),
            Edge(XY(0x1.f94f52a70c886p+8,0x1.b6p+8), XY(0x1.f94f52a70c886p+8,0x1.d8p+8)),
            Edge(XY(0x1.f94f52a70c886p+8,0x1.d8p+8), XY(0x1.268cc34ae392ap+8,0x1.d8p+8)),
            Edge(XY(0x1.268cc34ae392ap+8,0x1.d8p+8), XY(0x1.268cc34ae392ap+8,0x1.b6p+8)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.25p+9,0x1.ea8p+8), XY(0x1.25p+9,0x1.e58p+8)),
            Edge(XY(0x1.25p+9,0x1.e58p+8), XY(0x1.29cp+9,0x1.eb8p+8)),
            Edge(XY(0x1.29cp+9,0x1.eb8p+8), XY(0x1.25p+9,0x1.f18p+8)),
            Edge(XY(0x1.25p+9,0x1.f18p+8), XY(0x1.25p+9,0x1.ec8p+8)),
            Edge(XY(0x1.25p+9,0x1.ec8p+8), XY(0x1.318p+8,0x1.ec8p+8)),
            Edge(XY(0x1.318p+8,0x1.ec8p+8), XY(0x1.318p+8,0x1.ea8p+8)),
            Edge(XY(0x1.318p+8,0x1.ea8p+8), XY(0x1.25p+9,0x1.ea8p+8)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.acf53f7ced916p+8,0x1.dap+8), XY(0x1.d08ac083126e9p+8,0x1.dap+8)),
            Edge(XY(0x1.d08ac083126e9p+8,0x1.dap+8), XY(0x1.d08ac083126e9p+8,0x1.eap+8)),
            Edge(XY(0x1.d08ac083126e9p+8,0x1.eap+8), XY(0x1.acf53f7ced916p+8,0x1.eap+8)),
            Edge(XY(0x1.acf53f7ced916p+8,0x1.eap+8), XY(0x1.acf53f7ced916p+8,0x1.dap+8)),
        }),ContourList::UnsafeMake({})),})),})), ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.3672b30f13257p+9,0x1.a639a8bb75ae3p+8), XY(0x1.4481da23a5561p+9,0x1.bc8p+8)),
            Edge(XY(0x1.4481da23a5561p+9,0x1.bc8p+8), XY(0x1.4e40a3d70a3d7p+9,0x1.bc8p+8)),
            Edge(XY(0x1.4e40a3d70a3d7p+9,0x1.bc8p+8), XY(0x1.4e40a3d70a3d7p+9,0x1.d58p+8)),
            Edge(XY(0x1.4e40a3d70a3d7p+9,0x1.d58p+8), XY(0x1.41bf5c28f5c29p+9,0x1.d58p+8)),
            Edge(XY(0x1.41bf5c28f5c29p+9,0x1.d58p+8), XY(0x1.41bf5c28f5c29p+9,0x1.c23506acfe39cp+8)),
            Edge(XY(0x1.41bf5c28f5c29p+9,0x1.c23506acfe39cp+8), XY(0x1.3672b30f13257p+9,0x1.a639a8bb75ae3p+8)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.297eb851eb852p+8,0x1.418p+9), XY(0x1.1df6e73ffc0bbp+8,0x1.418p+9)),
            Edge(XY(0x1.1df6e73ffc0bbp+8,0x1.418p+9), XY(0x1.09p+8,0x1.37048c6001fa3p+9)),
            Edge(XY(0x1.09p+8,0x1.37048c6001fa3p+9), XY(0x1.09p+8,0x1.337b739ffe05dp+9)),
            Edge(XY(0x1.09p+8,0x1.337b739ffe05dp+9), XY(0x1.1df6e73ffc0bbp+8,0x1.29p+9)),
            Edge(XY(0x1.1df6e73ffc0bbp+8,0x1.29p+9), XY(0x1.33848c6001fa3p+9,0x1.29p+9)),
            Edge(XY(0x1.33848c6001fa3p+9,0x1.29p+9), XY(0x1.3ep+9,0x1.337b739ffe05dp+9)),
            Edge(XY(0x1.3ep+9,0x1.337b739ffe05dp+9), XY(0x1.3ep+9,0x1.37048c6001fa3p+9)),
            Edge(XY(0x1.3ep+9,0x1.37048c6001fa3p+9), XY(0x1.33848c6001fa3p+9,0x1.418p+9)),
            Edge(XY(0x1.33848c6001fa3p+9,0x1.418p+9), XY(0x1.428147ae147aep+8,0x1.418p+9)),
            Edge(XY(0x1.428147ae147aep+8,0x1.418p+9), XY(0x1.428147ae147aep+8,0x1.4c4p+9)),
            Edge(XY(0x1.428147ae147aep+8,0x1.4c4p+9), XY(0x1.297eb851eb852p+8,0x1.4c4p+9)),
            Edge(XY(0x1.297eb851eb852p+8,0x1.4c4p+9), XY(0x1.297eb851eb852p+8,0x1.47a24688a009fp+9)),
            Edge(XY(0x1.297eb851eb852p+8,0x1.47a24688a009fp+9), XY(0x1.13p+8,0x1.45cp+9)),
            Edge(XY(0x1.13p+8,0x1.45cp+9), XY(0x1.297eb851eb852p+8,0x1.4431ea0565098p+9)),
            Edge(XY(0x1.297eb851eb852p+8,0x1.4431ea0565098p+9), XY(0x1.297eb851eb852p+8,0x1.418p+9)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.41bf8e6172d02p+9,0x1.938p+8), XY(0x1.3bf1df14a81afp+9,0x1.7dp+8)),
            Edge(XY(0x1.3bf1df14a81afp+9,0x1.7dp+8), XY(0x1.4604233b31ee3p+9,0x1.938p+8)),
            Edge(XY(0x1.4604233b31ee3p+9,0x1.938p+8), XY(0x1.4e40a3d70a3d7p+9,0x1.938p+8)),
            Edge(XY(0x1.4e40a3d70a3d7p+9,0x1.938p+8), XY(0x1.4e40a3d70a3d7p+9,0x1.ac8p+8)),
            Edge(XY(0x1.4e40a3d70a3d7p+9,0x1.ac8p+8), XY(0x1.41bf5c28f5c29p+9,0x1.ac8p+8)),
            Edge(XY(0x1.41bf5c28f5c29p+9,0x1.ac8p+8), XY(0x1.41bf5c28f5c29p+9,0x1.938p+8)),
            Edge(XY(0x1.41bf5c28f5c29p+9,0x1.938p+8), XY(0x1.41bf8e6172d02p+9,0x1.938p+8)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.91d7626799994p+7,0x1.13cp+9), XY(0x1.97449b3e96b9cp+7,0x1.0cp+9)),
            Edge(XY(0x1.97449b3e96b9cp+7,0x1.0cp+9), XY(0x1.9d88ad7354331p+7,0x1.13cp+9)),
            Edge(XY(0x1.9d88ad7354331p+7,0x1.13cp+9), XY(0x1.b1028f5c28f5cp+7,0x1.13cp+9)),
            Edge(XY(0x1.b1028f5c28f5cp+7,0x1.13cp+9), XY(0x1.b1028f5c28f5cp+7,0x1.204p+9)),
            Edge(XY(0x1.b1028f5c28f5cp+7,0x1.204p+9), XY(0x1.7efd70a3d70a4p+7,0x1.204p+9)),
            Edge(XY(0x1.7efd70a3d70a4p+7,0x1.204p+9), XY(0x1.7efd70a3d70a4p+7,0x1.13cp+9)),
            Edge(XY(0x1.7efd70a3d70a4p+7,0x1.13cp+9), XY(0x1.91d7626799994p+7,0x1.13cp+9)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.aedc8acebad06p+7,0x1.d38p+8), XY(0x1.b53dd576f1091p+7,0x1.bd00000000001p+8)),
            Edge(XY(0x1.b53dd576f1091p+7,0x1.bd00000000001p+8), XY(0x1.bc9e99c77f432p+7,0x1.d38p+8)),
            Edge(XY(0x1.bc9e99c77f432p+7,0x1.d38p+8), XY(0x1.cf028f5c28f5cp+7,0x1.d38p+8)),
            Edge(XY(0x1.cf028f5c28f5cp+7,0x1.d38p+8), XY(0x1.cf028f5c28f5cp+7,0x1.ec8p+8)),
            Edge(XY(0x1.cf028f5c28f5cp+7,0x1.ec8p+8), XY(0x1.9cfd70a3d70a4p+7,0x1.ec8p+8)),
            Edge(XY(0x1.9cfd70a3d70a4p+7,0x1.ec8p+8), XY(0x1.9cfd70a3d70a4p+7,0x1.d38p+8)),
            Edge(XY(0x1.9cfd70a3d70a4p+7,0x1.d38p+8), XY(0x1.aedc8acebad06p+7,0x1.d38p+8)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.0cp+7,0x1.448p+9), XY(0x1.2ap+7,0x1.3dp+9), XY(0x1.0cp+7,0x1.405b9cfff1789p+9), XY(0x1.196e73ffc5e24p+7,0x1.3dp+9)),
            Edge(XY(0x1.2ap+7,0x1.3dp+9), XY(0x1.04p+8,0x1.3dp+9)),
            Edge(XY(0x1.04p+8,0x1.3dp+9), XY(0x1.13p+8,0x1.448p+9), XY(0x1.0c48c6001d0eep+8,0x1.3dp+9), XY(0x1.13p+8,0x1.405b9cfff1789p+9)),
            Edge(XY(0x1.13p+8,0x1.448p+9), XY(0x1.13p+8,0x1.47p+9)),
            Edge(XY(0x1.13p+8,0x1.47p+9), XY(0x1.04p+8,0x1.4e8p+9), XY(0x1.13p+8,0x1.4b2463000e877p+9), XY(0x1.0c48c6001d0eep+8,0x1.4e8p+9)),
            Edge(XY(0x1.04p+8,0x1.4e8p+9), XY(0x1.2ap+7,0x1.4e8p+9)),
            Edge(XY(0x1.2ap+7,0x1.4e8p+9), XY(0x1.0cp+7,0x1.47p+9), XY(0x1.196e73ffc5e24p+7,0x1.4e8p+9), XY(0x1.0cp+7,0x1.4b2463000e877p+9)),
            Edge(XY(0x1.0cp+7,0x1.47p+9), XY(0x1.0cp+7,0x1.448p+9)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.0cp+7,0x1.297b739ffe05dp+9), XY(0x1.27edce7ff8176p+7,0x1.228p+9)),
            Edge(XY(0x1.27edce7ff8176p+7,0x1.228p+9), XY(0x1.050918c003f45p+8,0x1.228p+9)),
            Edge(XY(0x1.050918c003f45p+8,0x1.228p+9), XY(0x1.13p+8,0x1.297b739ffe05dp+9)),
            Edge(XY(0x1.13p+8,0x1.297b739ffe05dp+9), XY(0x1.13p+8,0x1.2d048c6001fa3p+9)),
            Edge(XY(0x1.13p+8,0x1.2d048c6001fa3p+9), XY(0x1.050918c003f45p+8,0x1.34p+9)),
            Edge(XY(0x1.050918c003f45p+8,0x1.34p+9), XY(0x1.27edce7ff8176p+7,0x1.34p+9)),
            Edge(XY(0x1.27edce7ff8176p+7,0x1.34p+9), XY(0x1.0cp+7,0x1.2d048c6001fa3p+9)),
            Edge(XY(0x1.0cp+7,0x1.2d048c6001fa3p+9), XY(0x1.0cp+7,0x1.297b739ffe05dp+9)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.1p+7,0x1.ac8p+8), XY(0x1.2bp+7,0x1.9fp+8), XY(0x1.1p+7,0x1.a50b4dccb2a5dp+8), XY(0x1.1c169b99654bap+7,0x1.9fp+8)),
            Edge(XY(0x1.2bp+7,0x1.9fp+8), XY(0x1.038p+8,0x1.9fp+8)),
            Edge(XY(0x1.038p+8,0x1.9fp+8), XY(0x1.11p+8,0x1.ac8p+8), XY(0x1.0af4b2334d5a3p+8,0x1.9fp+8), XY(0x1.11p+8,0x1.a50b4dccb2a5dp+8)),
            Edge(XY(0x1.11p+8,0x1.ac8p+8), XY(0x1.11p+8,0x1.af8p+8)),
            Edge(XY(0x1.11p+8,0x1.af8p+8), XY(0x1.038p+8,0x1.bdp+8), XY(0x1.11p+8,0x1.b6f4b2334d5a3p+8), XY(0x1.0af4b2334d5a3p+8,0x1.bdp+8)),
            Edge(XY(0x1.038p+8,0x1.bdp+8), XY(0x1.2bp+7,0x1.bdp+8)),
            Edge(XY(0x1.2bp+7,0x1.bdp+8), XY(0x1.1p+7,0x1.af8p+8), XY(0x1.1c169b99654bap+7,0x1.bdp+8), XY(0x1.1p+7,0x1.b6f4b2334d5a3p+8)),
            Edge(XY(0x1.1p+7,0x1.af8p+8), XY(0x1.1p+7,0x1.ac8p+8)),
        }),ContourList::UnsafeMake({})),HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.1p+7,0x1.84e0f1266407p+8), XY(0x1.29c1e24cc80ep+7,0x1.78p+8)),
            Edge(XY(0x1.29c1e24cc80ep+7,0x1.78p+8), XY(0x1.041f0ed99bf9p+8,0x1.78p+8)),
            Edge(XY(0x1.041f0ed99bf9p+8,0x1.78p+8), XY(0x1.11p+8,0x1.84e0f1266407p+8)),
            Edge(XY(0x1.11p+8,0x1.84e0f1266407p+8), XY(0x1.11p+8,0x1.891f0ed99bf9p+8)),
            Edge(XY(0x1.11p+8,0x1.891f0ed99bf9p+8), XY(0x1.041f0ed99bf9p+8,0x1.96p+8)),
            Edge(XY(0x1.041f0ed99bf9p+8,0x1.96p+8), XY(0x1.29c1e24cc80ep+7,0x1.96p+8)),
            Edge(XY(0x1.29c1e24cc80ep+7,0x1.96p+8), XY(0x1.1p+7,0x1.891f0ed99bf9p+8)),
            Edge(XY(0x1.1p+7,0x1.891f0ed99bf9p+8), XY(0x1.1p+7,0x1.84e0f1266407p+8)),
        }),ContourList::UnsafeMake({})),}));
        Contour x = A*B; //This used to trigger an ASSERT PRINT when setting startpos
        //This was because we have an edge crossing a sharp spike in two CPs. Then these two CPs are
        //merged, and we snap to the end of the spike. This takes the CP far away from the original edge.
        //We have made ASSERT tolerance adaptive in this case to avoid triggering the assert.
    }

    //This tests an Untangle case, when the rightmost point of the path is a CP and has only incoming edges on the outside.
    {
        //   1--------2            In this untangle operation
        //   |         \           the input path goes by numbered vertices.
        //   |          \          The edge 3->4 overlaps with 6->7 and likewise
        //   |     7,4===3,6       4->5 overlaps with 7->8. In this case the rightmost
        //   |      ||  /          point of the path is in vertex 3 (=6). The first ray
        //   |      || /           of this CP is the 5->6 (closest to, but after the X axis).
        //   |      ||/            Here both 2->3 and 5->6 are incoming.
        //   9-----8,5
        Path p = {XY(10,0), XY(20,10), XY(15,10), XY(15, 15), XY(20,10), XY(15,10), XY(15, 15), XY(5, 25), XY(10,0)};
        Contour c(p);
        Contour ref(XY(5, 25), XY(10, 0), XY(20, 10));
        BAssert(R, c == ref, "Untangle with rightmost CP having 2 incoming edges - 1");
    }

    {
        //Same situation as the above
        Path p = {
            Edge(XY(0x1.9000000000000p+5,0x1.a800000000000p+4), XY(0x1.97cf7bffeb4e3p+5,0x1.59e52800cef25p+4)),
            Edge(XY(0x1.97cf7bffeb4e3p+5,0x1.59e52800cef25p+4), XY(0x1.9958a9f992361p+5,0x1.4e7d16aefd7f2p+4)),
            Edge(XY(0x1.9958a9f992361p+5,0x1.4e7d16aefd7f2p+4), XY(0x1.9b0ea10f7da8ep+5,0x1.43630f0dc8b12p+4)),
            Edge(XY(0x1.9b0ea10f7da8ep+5,0x1.43630f0dc8b12p+4), XY(0x1.97cf7bffeb4e3p+5,0x1.59e52800cef25p+4)),
            Edge(XY(0x1.97cf7bffeb4e3p+5,0x1.59e52800cef25p+4), XY(0x1.9958a9f992361p+5,0x1.4e7d16aefd7f2p+4)),
            Edge(XY(0x1.9958a9f992361p+5,0x1.4e7d16aefd7f2p+4), XY(0x1.9b0ea10f7da8ep+5,0x1.43630f0dc8b12p+4)),
            Edge(XY(0x1.9b0ea10f7da8ep+5,0x1.43630f0dc8b12p+4), XY(0x1.c0a2bb64e2390p+5,0x1.966cf3fa8efdep+4), false),
            Edge(XY(0x1.c0a2bb64e2390p+5,0x1.966cf3fa8efdep+4), XY(0x1.bbf953a9ce21bp+5,0x1.972b61b4cfddcp+4)),
            Edge(XY(0x1.bbf953a9ce21bp+5,0x1.972b61b4cfddcp+4), XY(0x1.b70d6bff9886dp+5,0x1.986108002963bp+4)),
            Edge(XY(0x1.b70d6bff9886dp+5,0x1.986108002963bp+4), XY(0x1.c0a2bb64e2390p+5,0x1.966cf3fa8efdep+4)),
            Edge(XY(0x1.c0a2bb64e2390p+5,0x1.966cf3fa8efdep+4), XY(0x1.bbf953a9ce21bp+5,0x1.972b61b4cfddcp+4)),
            Edge(XY(0x1.bbf953a9ce21bp+5,0x1.972b61b4cfddcp+4), XY(0x1.b70d6bff9886dp+5,0x1.986108002963bp+4)),
            Edge(XY(0x1.b70d6bff9886dp+5,0x1.986108002963bp+4), XY(0x1.9000000000000p+5,0x1.a800000000000p+4)),
        };
        Contour c(p);
        BAssert(R, !c.IsEmpty(), "Untangle with rightmost CP having 2 incoming edges - 2");
    }

    {
        //Edge #9 of A and Edge #7 of B almost overlap, but are further than 1e-5, which is the cutoff
        //to merge crosspoints. Their one end (endpoint of A's #9 and startpoint of B's #7) are detected as a
        //crosspoint (because of A's #10 and B's #6), but the other end is not. This sent walking haywire.
        //Then we applied a fix, where we fixed the order of the 2 rays corresponding to these edges in the
        //crosspoint we detected by walking better.
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.14f0d5866936fp+7,0x1.fafaeb6b74637p+5), XY(0x1.1212fcf57c93cp+7,0x1.f241a5bc7c809p+5)),
            Edge(XY(0x1.1212fcf57c93cp+7,0x1.f241a5bc7c809p+5), XY(0x1.0ec7782864c5dp+7,0x1.e9184e502cdbbp+5)),
            Edge(XY(0x1.0ec7782864c5dp+7,0x1.e9184e502cdbbp+5), XY(0x1.0b62fec0aa666p+7,0x1.e083cc742677ap+5)),
            Edge(XY(0x1.0b62fec0aa666p+7,0x1.e083cc742677ap+5), XY(0x1.0ad998ded2ae3p+7,0x1.d4fb9d19ee699p+5), false, true),
            Edge(XY(0x1.0ad998ded2ae3p+7,0x1.d4fb9d19ee699p+5), XY(0x1.0d37f2a76944fp+7,0x1.c83a43971fef4p+5)),
            Edge(XY(0x1.0d37f2a76944fp+7,0x1.c83a43971fef4p+5), XY(0x1.0f76c6a40778fp+7,0x1.baf9af76c5a21p+5)),
            Edge(XY(0x1.0f76c6a40778fp+7,0x1.baf9af76c5a21p+5), XY(0x1.119c0cc5fbc8fp+7,0x1.ad16c4ea9432fp+5)),
            Edge(XY(0x1.119c0cc5fbc8fp+7,0x1.ad16c4ea9432fp+5), XY(0x1.0fec884ed12a5p+7,0x1.98cf865ef6b5fp+5)),
            Edge(XY(0x1.0fec884ed12a5p+7,0x1.98cf865ef6b5fp+5), XY(0x1.1393d84965bffp+7,0x1.9a761b6657dadp+5), true, true),
            Edge(XY(0x1.1393d84965bffp+7,0x1.9a761b6657dadp+5), XY(0x1.1753798d18891p+7,0x1.a00b6faf64428p+5), true, true),
            Edge(XY(0x1.1753798d18891p+7,0x1.a00b6faf64428p+5), XY(0x1.1bc5ed36361edp+7,0x1.fffe9b9b83896p+5), XY(0x1.19b666e1ba0f5p+7,0x1.bf9e2b72e538fp+5), XY(0x1.1b35355a62be7p+7,0x1.e0005c49f9e12p+5)),
            Edge(XY(0x1.1bc5ed36361edp+7,0x1.fffe9b9b83896p+5), XY(0x1.18207d517c4abp+7,0x1.f96a76de524f9p+5), true, true),
            Edge(XY(0x1.18207d517c4abp+7,0x1.f96a76de524f9p+5), XY(0x1.1bf1dc3427ba0p+7,0x1.061c51068c50cp+6)),
            Edge(XY(0x1.1bf1dc3427ba0p+7,0x1.061c51068c50cp+6), XY(0x1.1c09a244c9dccp+7,0x1.0ef06ede65250p+6)),
            Edge(XY(0x1.1c09a244c9dccp+7,0x1.0ef06ede65250p+6), XY(0x1.1aaf4e7ab2d08p+7,0x1.30c3477bf0aebp+6), XY(0x1.1c09b0a40dd3ap+7,0x1.1a38ee2ae9906p+6), XY(0x1.1b9512fb953f6p+7,0x1.259b945299d25p+6)),
            Edge(XY(0x1.1aaf4e7ab2d08p+7,0x1.30c3477bf0aebp+6), XY(0x1.1729ed0701aebp+7,0x1.2cf77fe9cdcd7p+6), true, true),
            Edge(XY(0x1.1729ed0701aebp+7,0x1.2cf77fe9cdcd7p+6), XY(0x1.139bcb61208e4p+7,0x1.2eb04e5f50aabp+6), true, true),
            Edge(XY(0x1.139bcb61208e4p+7,0x1.2eb04e5f50aabp+6), XY(0x1.14987290aa51cp+7,0x1.2bdfb63ab2e24p+6)),
            Edge(XY(0x1.14987290aa51cp+7,0x1.2bdfb63ab2e24p+6), XY(0x1.12011ed6f762ep+7,0x1.259b14adcff32p+6)),
            Edge(XY(0x1.12011ed6f762ep+7,0x1.259b14adcff32p+6), XY(0x1.0f52c963a987cp+7,0x1.1faba5fcd9a03p+6)),
            Edge(XY(0x1.0f52c963a987cp+7,0x1.1faba5fcd9a03p+6), XY(0x1.0c860f32ff914p+7,0x1.1a014f8737db6p+6)),
            Edge(XY(0x1.0c860f32ff914p+7,0x1.1a014f8737db6p+6), XY(0x1.0ca9c02e4c468p+7,0x1.141ff8cf7354dp+6), false, true),
            Edge(XY(0x1.0ca9c02e4c468p+7,0x1.141ff8cf7354dp+6), XY(0x1.0f0af6e696496p+7,0x1.1025017b6766dp+6)),
            Edge(XY(0x1.0f0af6e696496p+7,0x1.1025017b6766dp+6), XY(0x1.1151825a23908p+7,0x1.0c3618c17b9f8p+6)),
            Edge(XY(0x1.1151825a23908p+7,0x1.0c3618c17b9f8p+6), XY(0x1.1580ecc6811dap+7,0x1.03be74de4f6d1p+6)),
            Edge(XY(0x1.1580ecc6811dap+7,0x1.03be74de4f6d1p+6), XY(0x1.15244643262bdp+7,0x1.ff7207c17ad51p+5)),
            Edge(XY(0x1.15244643262bdp+7,0x1.ff7207c17ad51p+5), XY(0x1.14de6ea226627p+7,0x1.ffff1921fdfabp+5), true, true),
            Edge(XY(0x1.14de6ea226627p+7,0x1.ffff1921fdfabp+5), XY(0x1.1514c54340deep+7,0x1.fe198072ebec0p+5)),
            Edge(XY(0x1.1514c54340deep+7,0x1.fe198072ebec0p+5), XY(0x1.14f0d5866936fp+7,0x1.fafaeb6b74637p+5)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.047409b0b24dbp+7,0x1.848fb62b3d7a7p+5), XY(0x1.061452c42fc53p+7,0x1.7609d0194e4dfp+5)),
            Edge(XY(0x1.061452c42fc53p+7,0x1.7609d0194e4dfp+5), XY(0x1.079415fde7ae5p+7,0x1.671e950de53b6p+5)),
            Edge(XY(0x1.079415fde7ae5p+7,0x1.671e950de53b6p+5), XY(0x1.08f6e2a6419a9p+7,0x1.57aa286810e9ap+5)),
            Edge(XY(0x1.08f6e2a6419a9p+7,0x1.57aa286810e9ap+5), XY(0x1.066b7bd7dee23p+7,0x1.42d96ccb42efdp+5)),
            Edge(XY(0x1.066b7bd7dee23p+7,0x1.42d96ccb42efdp+5), XY(0x1.0a14450c9fedap+7,0x1.4189dbc70f2a0p+5), true, true),
            Edge(XY(0x1.0a14450c9fedap+7,0x1.4189dbc70f2a0p+5), XY(0x1.0de883682b048p+7,0x1.462a6a7927613p+5), true, true),
            Edge(XY(0x1.0de883682b048p+7,0x1.462a6a7927613p+5), XY(0x1.175380dd20abbp+7,0x1.a00bd06f09fd1p+5), XY(0x1.11df717fcc256p+7,0x1.63773d21f6f76p+5), XY(0x1.1509ad121b6a0p+7,0x1.81c5100fcc04dp+5)),
            Edge(XY(0x1.175380dd20abbp+7,0x1.a00bd06f09fd1p+5), XY(0x1.1393dfb18b44bp+7,0x1.9a767b22f23bcp+5), true, true),
            Edge(XY(0x1.1393dfb18b44bp+7,0x1.9a767b22f23bcp+5), XY(0x1.10c4e236a1390p+7,0x1.a3bddab262dcbp+5), true, true),
            Edge(XY(0x1.10c4e236a1390p+7,0x1.a3bddab262dcbp+5), XY(0x1.10d1313c12defp+7,0x1.a1f5edeb51a22p+5)),
            Edge(XY(0x1.10d1313c12defp+7,0x1.a1f5edeb51a22p+5), XY(0x1.0d1f919f8532ep+7,0x1.9b249a71dabc0p+5)),
            Edge(XY(0x1.0d1f919f8532ep+7,0x1.9b249a71dabc0p+5), XY(0x1.096427a9f5344p+7,0x1.94f3f829faf3dp+5)),
            Edge(XY(0x1.096427a9f5344p+7,0x1.94f3f829faf3dp+5), XY(0x1.059610985165bp+7,0x1.8f5630fc4cfaap+5)),
            Edge(XY(0x1.059610985165bp+7,0x1.8f5630fc4cfaap+5), XY(0x1.047409b0b24dbp+7,0x1.848fb62b3d7a7p+5), false, true),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));

        A.Scale(30);
        B.Scale(30);

        UnionAssert(R, A, B, "Union of two contours with missing crosspoint");
    }

    {
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.9407cb4936012p+5,0x1.9f013bb268577p+5), XY(0x1.a3780b24a4a0ap+5,-0x1.6p+3)),
            Edge(XY(0x1.a3780b24a4a0ap+5,-0x1.6p+3), XY(0x1.94147ae147ae2p+5,-0x1.6p+3)),
            Edge(XY(0x1.94147ae147ae2p+5,-0x1.6p+3), XY(0x1.94147ae147ae2p+5,-0x1.ap+3)),
            Edge(XY(0x1.94147ae147ae2p+5,-0x1.ap+3), XY(0x1.a3f5c28f5c28fp+5,-0x1.9fffffffffffcp+3)),
            Edge(XY(0x1.a3f5c28f5c28fp+5,-0x1.9fffffffffffcp+3), XY(0x1.b3fe0a3ba27ccp+5,0x1.9f801036523aep+5)),
            Edge(XY(0x1.b3fe0a3ba27ccp+5,0x1.9f801036523aep+5), XY(0x1.b4p+5,0x1.ap+5), XY(0x1.b3ff56f1d0ffdp+5,0x1.9faa4c8d83f7p+5), XY(0x1.b4p+5,0x1.9fd51288ad535p+5)),
            Edge(XY(0x1.b4p+5,0x1.ap+5), XY(0x1.a4p+5,0x1.bp+5), XY(0x1.b4p+5,0x1.a8d62888a7876p+5), XY(0x1.acd62888a7875p+5,0x1.bp+5)),
            Edge(XY(0x1.a4p+5,0x1.bp+5), XY(0x1.94p+5,0x1.ap+5), XY(0x1.9b29d7775878bp+5,0x1.bp+5), XY(0x1.94p+5,0x1.a8d62888a7876p+5)),
            Edge(XY(0x1.94p+5,0x1.ap+5), XY(0x1.9407cb4936012p+5,0x1.9f013bb268577p+5)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.940000055f56ap+5,0x1.9fff2bed74781p+5), XY(0x1.94147ae147ae2p+5,-0x1.ap+3)),
            Edge(XY(0x1.94147ae147ae2p+5,-0x1.ap+3), XY(0x1.a3f5c28f5c28fp+5,-0x1.ap+3)),
            Edge(XY(0x1.a3f5c28f5c28fp+5,-0x1.ap+3), XY(0x1.940000055f56ap+5,0x1.9fff2bed74781p+5)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));

        UnionAssert(R, A, B, "Union of two contours dunno what's wrong");
    }

    {
        Contour Res = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.830dcb553d5d6p+9,0x1.94ec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.aaec1d5734babp+7)),
            Edge(XY(0x1.830dcb553d5d6p+9,0x1.aaec1d5734babp+7), XY(0x1.804dcb553d5d6p+9,0x1.aaec1d5734babp+7)),
            Edge(XY(0x1.804dcb553d5d6p+9,0x1.aaec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.9fec1d5734babp+7), XY(0x1.81d29a4cba28ap+9,0x1.aaec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.a5ff593527e7cp+7)),
            Edge(XY(0x1.830dcb553d5d6p+9,0x1.9fec1d5734babp+7), XY(0x1.804dcb553d5d6p+9,0x1.94ec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.99d8e179418dap+7), XY(0x1.81d29a4cba28ap+9,0x1.94ec1d5734babp+7)),
            Edge(XY(0x1.804dcb553d5d6p+9,0x1.94ec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.94ec1d5734babp+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.85cdcb553d5d6p+9,0x1.94ec1d5734babp+7), XY(0x1.85cdcb553d5d6p+9,0x1.aaec1d5734babp+7)),
            Edge(XY(0x1.85cdcb553d5d6p+9,0x1.aaec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.aaec1d5734babp+7)),
            Edge(XY(0x1.830dcb553d5d6p+9,0x1.aaec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.94ec1d5734babp+7)),
            Edge(XY(0x1.830dcb553d5d6p+9,0x1.94ec1d5734babp+7), XY(0x1.85cdcb553d5d6p+9,0x1.94ec1d5734babp+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.804dcb553d5d6p+9,0x1.94ec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.94ec1d5734babp+7)),
            Edge(XY(0x1.830dcb553d5d6p+9,0x1.94ec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.aaec1d5734babp+7)),
            Edge(XY(0x1.830dcb553d5d6p+9,0x1.aaec1d5734babp+7), XY(0x1.804dcb553d5d6p+9,0x1.aaec1d5734babp+7)),
            Edge(XY(0x1.804dcb553d5d6p+9,0x1.aaec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.9fec1d5734babp+7), XY(0x1.81d29a4cba28ap+9,0x1.aaec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.a5ff593527e7cp+7)),
            Edge(XY(0x1.830dcb553d5d6p+9,0x1.9fec1d5734babp+7), XY(0x1.804dcb553d5d6p+9,0x1.94ec1d5734babp+7), XY(0x1.830dcb553d5d6p+9,0x1.99d8e179418dap+7), XY(0x1.81d29a4cba28ap+9,0x1.94ec1d5734babp+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        
        UnionAssert(R, A, B, "Union of two contours 2");
    }

    {
        Contour Res = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.837234aac2a34p+9,0x1.8d13e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.a313e2a8cb45dp+7)),
            Edge(XY(0x1.837234aac2a34p+9,0x1.a313e2a8cb45dp+7), XY(0x1.80b234aac2a34p+9,0x1.a313e2a8cb45dp+7)),
            Edge(XY(0x1.80b234aac2a34p+9,0x1.a313e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.9813e2a8cb45dp+7), XY(0x1.823703a23f6e8p+9,0x1.a313e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.9e271e86be72ep+7)),
            Edge(XY(0x1.837234aac2a34p+9,0x1.9813e2a8cb45dp+7), XY(0x1.80b234aac2a34p+9,0x1.8d13e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.9200a6cad818cp+7), XY(0x1.823703a23f6e8p+9,0x1.8d13e2a8cb45dp+7)),
            Edge(XY(0x1.80b234aac2a34p+9,0x1.8d13e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.8d13e2a8cb45dp+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.863234aac2a34p+9,0x1.8d13e2a8cb45dp+7), XY(0x1.863234aac2a34p+9,0x1.a313e2a8cb45dp+7)),
            Edge(XY(0x1.863234aac2a34p+9,0x1.a313e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.a313e2a8cb45dp+7)),
            Edge(XY(0x1.837234aac2a34p+9,0x1.a313e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.8d13e2a8cb45dp+7)),
            Edge(XY(0x1.837234aac2a34p+9,0x1.8d13e2a8cb45dp+7), XY(0x1.863234aac2a34p+9,0x1.8d13e2a8cb45dp+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.80b234aac2a34p+9,0x1.8d13e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.8d13e2a8cb45dp+7)),
            Edge(XY(0x1.837234aac2a34p+9,0x1.8d13e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.a313e2a8cb45dp+7)),
            Edge(XY(0x1.837234aac2a34p+9,0x1.a313e2a8cb45dp+7), XY(0x1.80b234aac2a34p+9,0x1.a313e2a8cb45dp+7)),
            Edge(XY(0x1.80b234aac2a34p+9,0x1.a313e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.9813e2a8cb45dp+7), XY(0x1.823703a23f6e8p+9,0x1.a313e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.9e271e86be72ep+7)),
            Edge(XY(0x1.837234aac2a34p+9,0x1.9813e2a8cb45dp+7), XY(0x1.80b234aac2a34p+9,0x1.8d13e2a8cb45dp+7), XY(0x1.837234aac2a34p+9,0x1.9200a6cad818cp+7), XY(0x1.823703a23f6e8p+9,0x1.8d13e2a8cb45dp+7)),
        }), ContourList::UnsafeMake({})), ContourList::UnsafeMake({}));
        UnionAssert(R, A, B, "Union of two contours 3");
    }

    {
        //Here we have a tricky crosspoint
        //                |(a)
        //                |     The crosspoint at the star is found well. However the edeges marked as (a) and (b) are not connected
        //       ....<....*.+   are very close to each other: in the X dimension they are (a)=37.171875000000000, while (b)=37.171875000000007.
        //  --<-----------+ :   (The other 2edges shown differ in Y b 0.1 pixels.) This small difference means that (a) and (b) are not
        //                  :   crossing as their hull does not cross, but the * crosspoint will be filed to the vertex of the dotted contour.
        //               (b):   This prompts us to make HullOverlap() a bit less conservative.


        Contour A = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.b2c0000000000p+4,0x1.5acccccccccccp+6), XY(0x1.57c6666666667p+5,0x1.5acccccccccccp+6)),
            Edge(XY(0x1.57c6666666667p+5,0x1.5acccccccccccp+6), XY(0x1.57c6666666667p+5,0x1.ce66666666666p+6)),
            Edge(XY(0x1.57c6666666667p+5,0x1.ce66666666666p+6), XY(0x1.8ce2666666666p+6,0x1.ce66666666666p+6)),
            Edge(XY(0x1.8ce2666666666p+6,0x1.ce66666666666p+6), XY(0x1.8ce2666666666p+6,0x1.b000000000000p+6)),
            Edge(XY(0x1.8ce2666666666p+6,0x1.b000000000000p+6), XY(0x1.a41599999999ap+6,0x1.b000000000000p+6), true, true),
            Edge(XY(0x1.a41599999999ap+6,0x1.b000000000000p+6), XY(0x1.a41599999999ap+6,0x1.e59999999999ap+6)),
            Edge(XY(0x1.a41599999999ap+6,0x1.e59999999999ap+6), XY(0x1.2960000000001p+5,0x1.e59999999999ap+6)),
            Edge(XY(0x1.2960000000001p+5,0x1.e59999999999ap+6), XY(0x1.2960000000001p+5,0x1.8b9999999999ap+6)),
            Edge(XY(0x1.2960000000001p+5,0x1.8b9999999999ap+6), XY(0x1.b2c0000000000p+4,0x1.8b9999999999ap+6)),
            Edge(XY(0x1.b2c0000000000p+4,0x1.8b9999999999ap+6), XY(0x1.b2c0000000000p+4,0x1.b200000000000p+6)),
            Edge(XY(0x1.b2c0000000000p+4,0x1.b200000000000p+6), XY(0x1.3000000000000p+3,0x1.b200000000000p+6)),
            Edge(XY(0x1.3000000000000p+3,0x1.b200000000000p+6), XY(0x1.3000000000000p+3,0x1.4e00000000000p+6)),
            Edge(XY(0x1.3000000000000p+3,0x1.4e00000000000p+6), XY(0x1.b2c0000000000p+4,0x1.4e00000000000p+6)),
            Edge(XY(0x1.b2c0000000000p+4,0x1.4e00000000000p+6), XY(0x1.b2c0000000000p+4,0x1.5acccccccccccp+6)),
        }),ContourList::UnsafeMake({HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(0x1.b2c0000000000p+4,0x1.7200000000000p+6), XY(0x1.b2c0000000000p+4,0x1.7466666666666p+6)),
            Edge(XY(0x1.b2c0000000000p+4,0x1.7466666666666p+6), XY(0x1.2960000000001p+5,0x1.7466666666666p+6)),
            Edge(XY(0x1.2960000000001p+5,0x1.7466666666666p+6), XY(0x1.2960000000001p+5,0x1.7200000000000p+6)),
            Edge(XY(0x1.2960000000001p+5,0x1.7200000000000p+6), XY(0x1.b2c0000000000p+4,0x1.7200000000000p+6)),
        }),ContourList::UnsafeMake({})), })), ContourList::UnsafeMake({}));
        Contour B = Contour::UnsafeMake(HoledSimpleContour::UnsafeMake(SimpleContour::UnsafeMake(Path{
            Edge(XY(-0x1.0000000000000p-1,0x1.2600000000000p+6), XY(0x1.2960000000000p+5,0x1.2600000000000p+6)),
            Edge(XY(0x1.2960000000000p+5,0x1.2600000000000p+6), XY(0x1.2960000000000p+5,0x1.da00000000000p+6)),
            Edge(XY(0x1.2960000000000p+5,0x1.da00000000000p+6), XY(-0x1.0000000000000p-1,0x1.da00000000000p+6)),
            Edge(XY(-0x1.0000000000000p-1,0x1.da00000000000p+6), XY(-0x1.0000000000000p-1,0x1.2600000000000p+6)),
        }),ContourList::UnsafeMake({})),ContourList::UnsafeMake({}));
        const Block B1 = A.GetBoundingBox() + B.GetBoundingBox();
        Contour C = A + B;
        const Block B2 = C.GetBoundingBox();
        BAssert(R, B1==B2, "Union with tricky crosspoint at 37.1719, 118.5");
    }

    //Now print results (to stderr)
    const size_t failed = std::ranges::count(R, false, &std::pair<std::string, bool>::second);
    if (do_image) {
        R.emplace(R.begin(), failed ? "The following unit tests failed:" : "All unit tests passed!", failed==0);
        const auto imax = std::ranges::max_element(R, {}, [](auto& p) {return p.second ? 0 : p.first.length(); });
        const size_t m = imax->second ? 0: imax->first.length();
        CairoContext canvas(0, Block(0, std::max(m*1.2, 174.), 0, std::max(20.,double(failed+1)*6)), "Unit tests");
        cairo_set_font_size(canvas.cr, 5);
        double y = 0;
        for (auto& [msg, success] : R)
            if (!success || y==0) {
                cairo_set_source_rgb(canvas.cr, int(!success)/2., int(success)/2., 0.);
                cairo_move_to(canvas.cr, 5, y);
                thread_safe_cairo_show_text(canvas.cr, msg.c_str());
                y += 6;
            }
    } else {
        if (failed) std::cerr << "The following " << failed << " unit tests failed : " << std::endl;
        for (auto& [msg, success] : R)
            if (!success) std::cerr<<msg<<std::endl;
    }
}
