AKTIVE

fill.tcl at trunk
Login

fill.tcl at trunk

File etc/transformer/structure/resample/fill.tcl artifact e7983f01e7 on branch trunk


     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
   100
   101
   102
   103
   104
   105
   106
   107
   108
   109
   110
   111
   112
   113
   114
   115
   116
   117
   118
   119
   120
   121
   122
   123
   124
   125
   126
   127
   128
   129
   130
   131
   132
   133
   134
   135
   136
   137
   138
   139
   140
   141
   142
   143
   144
   145
   146
   147
   148
   149
   150
   151
   152
   153
   154
   155
   156
   157
   158
   159
   160
   161
   162
   163
   164
   165
   166
   167
   168
   169
   170
   171
   172
   173
   174
   175
   176
   177
   178
   179
   180
   181
   182
   183
   184
   185
   186
   187
   188
   189
   190
   191
   192
   193
   194
   195
   196
## -*- mode: tcl ; fill-column: 90 -*-
# # ## ### ##### ######## ############# #####################
## Transformers -- Structural changes (data re-arrangements)

# # ## ### ##### ######## ############# #####################
## Zero-stuff along one of the coordinate axes. No replication.
## Intermediate points are filled with a fixed value.
##
## The stuffing factor S is also the scale factor, i.e.
##
##   result width = input width * S
##
## and S-1 pixel gaps to be set to the chosen fill value.

operator op::sample::fill::xy {

    section transform structure

    example {
	aktive op sdf 2image smooth [aktive op sdf ring [aktive image sdf triangle width 128 height 128 a {10 10} b {50 80} c {80 30}] thickness 4]
	@1 by 4 fill 0.5
    }

    note Returns image where the input is \"zero-stuffed\" \
	along both x and y axes according to the stuffing \
	factor S (>= 1). The S-1 gaps in the result are set to \
	the given fill value, with zero, i.e. 0, used by default.

    input

    uint? 2 by Stuff factor, range 2...
    double? 0 fill  Pixel fill value

    body {
	set src [x $src by $by fill $fill]
	set src [y $src by $by fill $fill]
    }
}

operator {coordinate dimension} {
    op::sample::fill::x  x width
    op::sample::fill::y  y height
    op::sample::fill::z  z depth
} {
    section transform structure

    if {$coordinate in {x y}} {
	example {
	    aktive op sdf 2image smooth [aktive op sdf ring [aktive image sdf triangle width 128 height 128 a {10 10} b {50 80} c {80 30}] thickness 4]
	    @1 by 4 fill 0.5
	}
    }

    note Returns image where the input is \"zero-stuffed\" \
	along the ${coordinate}-axis according to the stuffing \
	factor S (>= 1). The S-1 gaps in the result are set to \
	the given fill value, with zero, i.e. 0, used by default.

    # Factor 0 - Undefined. Rejected.
    #        1 - No gaps -> Identity, no operation
    #        2 - Gap 1, fill every other value
    #        3 - Gap 2.

    input

    uint      by    Stuff factor, range 2...
    double? 0 fill  Pixel fill value

    # Factor 1 stuffing is no stuffing at all
    simplify for \
	if {$by == 1} \
	returns src

    # Chains: stuff factors multiply, however if and only if the fill values match
    simplify for  src/type @self \
	src/value fill __fill \
	if {$__fill == $fill} \
	src/value by __by \
	calc __by {$__by * $by} \
	src/pop \
	returns op sample fill $coordinate : by __by fill __fill

    # Chains: stuffing a sampling is __not__ identity.
    #         The stuffing cannot recover the information lost in the sampling.

    state -setup {
	// could be moved into the cons wrapper created for simplification
	if (param->by == 0) aktive_fail ("Rejecting undefined stuffing by factor 0");

	aktive_geometry_copy (domain, aktive_image_get_geometry (srcs->v[0]));
	// Modify dimension according to parameter
	domain->@@dimension@@ *= param->by;
    }

    #
    # SRC 0     1     2     3     4     5     6		(gradient    7 1 1 0 6)
    # DST 0 . . 1 . . 2 . . 3 . . 4 . . 5 . . 6 . .	(sample fill x 3 .)
    #     = = = = = = = = = = = = = = = = = = = = =
    #     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
    #                         1                   2
    #               |=========|
    #               . 2 . . 3 .				(select x 5 10)
    #               0 1 2 3 4 5
    #
    # select      request: 5..10 = 5,6
    # sample fill request: 5..10 = 5,6
    # gradient    request: 2..3  = 2,1 (grid to 6 (+1 = (-5 % 3) [1] = ((5 - (5 % 3)) % 3) [2])
    # note: different %-semantics for Tcl [1] and C [2].
    #
    # The actual dst x is shifted to align to the stretched grid in the destination.
    #
    # X % 5 | Correction -x  % 5 == (5 - x%5) % 5
    # ----- + ------------------ -- -------------
    # 0     | 0           0  0
    # 1     | 4          -1  4
    # 2     | 3          -2  3
    # 3     | 2          -3  2
    # 4     | 1          -4  1
    # ----- + -------------------

    if 0 {
	foreach x {0 1 2 3 4 5 6 7 8 9} z {0 4 3 2 1 0 4 3 2 1} {
	    puts $x\t$z\t[expr {(-$x) % 5}]\t[expr {(5 - (($x) % 5)) % 5}]
	}
    }

    blit filler [dict get {
	y {
	    {SH {y grid n up} {y 0 1 up}}
	    {DW {x 0    1 up} {x 0 1 up}}
	    {DD {z 0    1 up} {z 0 1 up}}
	}
	x {
	    {DH {y 0    1 up} {y 0 1 up}}
	    {SW {x grid n up} {x 0 1 up}}
	    {DD {z 0    1 up} {z 0 1 up}}
	}
	z {
	    {DH {y 0 1 up} {y 0 1 up}}
	    {DW {x 0 1 up} {x 0 1 up}}
	    {SD {z 0 n up} {z 0 1 up}}
	}
    } $coordinate] copy

    def shrinkcore {
	// Note: C-semantics for `%`. Tcl semantics yield `(-i)%n`.
	#define CORRECTION(i,n)  (((n) - ((i) % (n))) % (n))
	// Shift correction to snap request into the sample grid
	int grid = CORRECTION (subrequest.@@coordinate@@, n);
	#undef CORRECTION
	TRACE ("Correction: %d (%d in %d)", grid, subrequest.@@coordinate@@, n);

	// Rewrite request to the input coordinates and dimensions
	subrequest.@@coordinate@@ = (subrequest.@@coordinate@@ + grid) / n;
	if (subrequest.@@dimension@@ < n) {
	    // The correction puts the input block outside of the requested range
	    // This means that the caller asked for gap data. This data is already
	    // in the result, as `aktive_blit_fill` was called above.
	    if (grid >= subrequest.@@dimension@@) {
		TRACE_RETURN_VOID;
	    }
	    subrequest.@@dimension@@ = 1;
	} else {
	    subrequest.@@dimension@@ /= n;
	}

	TRACE_RECTANGLE_M ("rewritten", request);

	// Note: grid is the starting point in the destination area (rooted at 0).
    }

    def shrink [dict get {
	x { @@shrinkcore@@ }
	y { @@shrinkcore@@ }
	z { // Nothing to rewrite for z, depth }
    } $coordinate]

    pixels {
	// Blank the region with the fill value first. This way the coming blitter
	// does not have to concern itself with the gaps, just the values to set.
	aktive_blit_fill (block, dst, param->fill);

	aktive_uint n = param->by;
	aktive_rectangle_def_as (subrequest, request);
	@@shrink@@
	aktive_block* src = aktive_region_fetch_area (0, &subrequest);

	// The destination @@coordinate@@ axis is scanned N times faster than the source.
	// The destination location is snapped forward to the grid.
	@@filler@@
    }
}

##
# # ## ### ##### ######## ############# #####################
::return