svghmi/geometry.ysl2
author etisserant <edouard.tisserant@gmail.com>
Tue, 25 Jan 2022 16:37:16 +0100
changeset 3415 c270b6c8162b
parent 3199 1582753e409b
child 3625 bb1eff4091ab
permissions -rw-r--r--
Create README.md in tests
// geometry.ysl2
//
// Geometry (bounding box intersection) definitions

// This retrieves geometry obtained through "inkscape -S"
// already parsed by python and presented as a list of
// <bbox x="0" y="0" w="42" h="42">
const "all_geometry", "ns:GetSVGGeometry()";
const "defs", "//svg:defs/descendant-or-self::svg:*";
const "geometry", "$all_geometry[not(@Id = $defs/@id)]";

// Debug data
emit "debug:geometry" {
    | ID, x, y, w, h
    foreach "$geometry"
        |  «@Id» «@x» «@y» «@w» «@h»
}

// Rates 1D intersection of 2 segments A and B
// described respectively with a0,a1 and b0,b1
def "func:intersect_1d" {
    // it is assumed that a1 > a0 and b1 > b0
    param "a0";
    param "a1";
    param "b0";
    param "b1";

    const "d0", "$a0 >= $b0";
    const "d1", "$a1 >= $b1";
    choose {
        when "not($d0) and $d1"
            // b contained in a
            //   a0<b0 b1<a1
            // a +--------+
            // b    +--+
            result "3";
        when "$d0 and not($d1)"
            // a contained in b
            //   b0<a0 a1<b1
            // a    +--+
            // b +--------+
            result "2";
        when "$d0 and $d1 and $a0 < $b1"
            // a and b are overlapped 
            //   b0<a0<b1<a1
            // a    +-----+
            // b +-----+
            result "1";
        when "not($d0) and not($d1) and $b0 < $a1"
            // a and b are overlapped
            //   a0<b0<a1<b1
            // a +-----+
            // b    +-----+
            result "1";
            // since orientation doesn't matter,
            // rated same as previous symetrical overlapping
        otherwise
            result "0"; /* no intersection*/
    }
}


// Rates intersection A and B areas described with x,y,w and h 
// attributes passed as $a and $b parameters.
// 
// returns :
// 0 - no intersection
//            .-----.
//    .-----. |    b|
//    |     | |     |
//    |     | '-----'
//    |a    |
//    '-----'
//
// 1 - overlapping
//        .-----.
//    .---|--. b|
//    |   |  |  |
//    |   '-----'
//    |a     |
//    '------'
//
// 2 - overlapping
//        .-----.
//        |  a  |
//    .---|-----|---.
//    |   '-----'   |
//    | b           |
//    '-------------'
//
// 3 - overlapping
//        .-----.
//        |  b  |
//    .---|-----|---.
//    |   '-----'   |
//    | a           |
//    '-------------'
//
// 4 - a contained in b
//    .-------------.
//    |   .-----.   |
//    |   |  a  |   |
//    |b  '-----'   |
//    '-------------'
//
// 6 - overlapping
//        .----.
//        |   b|
//    .---|----|---.
//    |a  |    |   |
//    '---|----|---'
//        '----'
//
// 9 - b contained in a
//    .-------------.
//    |   .-----.   |
//    |   |  b  |   |
//    |a  '-----'   |
//    '-------------'
//
def "func:intersect" {
    param "a";
    param "b";

    const "x_intersect", "func:intersect_1d($a/@x, $a/@x+$a/@w, $b/@x, $b/@x+$b/@w)";

    choose{
        when "$x_intersect != 0"{
            const "y_intersect", "func:intersect_1d($a/@y, $a/@y+$a/@h, $b/@y, $b/@y+$b/@h)";
            result "$x_intersect * $y_intersect";
        }
        otherwise result "0";
    }
}

const "groups", "/svg:svg | //svg:g";

// return overlapping geometry for a given element
// all intersercting element are returned
// except groups, that must be contained to be counted in
def "func:overlapping_geometry" {
    param "elt";
    const "g", "$geometry[@Id = $elt/@id]"; 
    const "candidates", "$geometry[@Id != $elt/@id]";
    result """$candidates[(@Id = $groups/@id and (func:intersect($g, .) = 9)) or 
                          (not(@Id = $groups/@id) and (func:intersect($g, .) > 0 ))]""";
}