svghmi/geometry.ysl2
author Edouard Tisserant
Thu, 09 Dec 2021 10:21:45 +0100
branchRuntimeLists
changeset 3395 93ad018fb602
parent 3199 1582753e409b
child 3625 bb1eff4091ab
permissions -rw-r--r--
RUNTIME: Variable forcing now uses limited list and buffer instead of systematical instance tree traversal and in-tree "fvalue" to keep track of forced value for pointed variables (external, located). Pointer swapping is performed when forcing externals and located, with backup being restored when forcing is reset. Retain still uses tree traversal.
// 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 ))]""";
}