Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Olena
pylene
Commits
6fd35d58
Commit
6fd35d58
authored
Jan 22, 2019
by
Edwin Carlinet
Browse files
Merge branch 'development/zip_view' into 'development/ranges'
zip view (PR4) See merge request
!39
parents
e9730905
ecb47cac
Pipeline
#12871
passed with stages
in 12 minutes and 1 second
Changes
13
Pipelines
3
Hide whitespace changes
Inline
Side-by-side
.gitignore
View file @
6fd35d58
...
...
@@ -8,4 +8,6 @@
.vs
.idea
*.pyc
/venv_*/
\ No newline at end of file
compile_commands.json
/venv_*/
/**/.DS_Store
\ No newline at end of file
.vscode/settings.json
View file @
6fd35d58
...
...
@@ -60,6 +60,7 @@
"queue"
:
"cpp"
,
"stack"
:
"cpp"
},
"python.pythonPath"
:
"/usr/bin/python3"
,
"C_Cpp.configurationWarnings"
:
"Disabled"
"python.pythonPath"
:
"venv_python37/bin/python"
,
"C_Cpp.configurationWarnings"
:
"Disabled"
,
"git.ignoreLimitWarning"
:
true
}
\ No newline at end of file
pylene/include/mln/core/image/private/image_operators.hpp
View file @
6fd35d58
...
...
@@ -2,6 +2,7 @@
#include <functional>
#include <mln/core/image/view/transform.hpp>
#include <mln/core/image/view/zip.hpp>
#include <mln/core/rangev3/foreach.hpp>
namespace
mln
::
experimental
...
...
@@ -97,14 +98,13 @@ namespace mln::experimental
template
<
class
ICond
,
class
ITrue
,
class
IFalse
>
struct
where_fn
<
ICond
,
ITrue
,
IFalse
,
std
::
enable_if_t
<
is_a
<
ITrue
,
Image
>::
value
&&
is_a
<
IFalse
,
Image
>::
value
>>
{
auto
operator
()(
const
ICond
&
/*
cond
*/
,
ITrue
/*
iftrue
*/
,
IFalse
/*
iffalse
*/
)
const
auto
operator
()(
const
ICond
&
cond
,
ITrue
iftrue
,
IFalse
iffalse
)
const
{
auto
g
=
[](
bool
vcond
,
auto
&&
vtrue
,
auto
&&
vfalse
)
->
decltype
(
auto
)
{
return
(
vcond
)
?
std
::
forward
<
decltype
(
vtrue
)
>
(
vtrue
)
:
std
::
forward
<
decltype
(
vfalse
)
>
(
vfalse
);
auto
g
=
[](
auto
tuple_ternary_expr
)
->
decltype
(
auto
)
{
return
(
std
::
get
<
0
>
(
tuple_ternary_expr
))
?
std
::
get
<
1
>
(
tuple_ternary_expr
)
:
std
::
get
<
2
>
(
tuple_ternary_expr
);
};
// FIXME: to be implemented with imzip
return
;
return
view
::
transform
(
view
::
zip
(
cond
,
iftrue
,
iffalse
),
g
);
}
};
...
...
@@ -144,42 +144,42 @@ namespace mln::experimental
return
view
::
transform
(
cond
,
g
);
}
};
}
// namespace details
}
// namespace details
template
<
class
ICond
,
class
ITrue
,
class
IFalse
>
auto
where
(
const
Image
<
ICond
>&
cond
,
ITrue
iftrue
,
IFalse
iffalse
)
{
return
details
::
where_fn
<
ICond
,
ITrue
,
IFalse
>
()(
static_cast
<
const
ICond
&>
(
cond
),
std
::
move
(
iftrue
),
std
::
move
(
iffalse
));
}
template
<
class
ICond
,
class
ITrue
,
class
IFalse
>
auto
where
(
const
Image
<
ICond
>&
cond
,
ITrue
iftrue
,
IFalse
iffalse
)
{
return
details
::
where_fn
<
ICond
,
ITrue
,
IFalse
>
()(
static_cast
<
const
ICond
&>
(
cond
),
std
::
move
(
iftrue
),
std
::
move
(
iffalse
));
}
// FIXME: deprecated => replace with algorithm all_of
template
<
class
I
>
[[
deprecated
]]
bool
all
(
I
ima
)
{
static_assert
(
mln
::
is_a
<
I
,
Image
>
());
static_assert
(
std
::
is_convertible
<
typename
I
::
reference
,
bool
>
());
// FIXME: deprecated => replace with algorithm all_of
template
<
class
I
>
[[
deprecated
]]
bool
all
(
I
ima
)
{
static_assert
(
mln
::
is_a
<
I
,
Image
>
());
static_assert
(
std
::
is_convertible
<
typename
I
::
reference
,
bool
>
());
mln_foreach_new
(
auto
&&
val
,
ima
.
new_values
())
if
(
!
val
)
return
false
;
mln_foreach_new
(
auto
&&
val
,
ima
.
new_values
())
if
(
!
val
)
return
false
;
return
true
;
}
return
true
;
}
template
<
class
I
>
[[
deprecated
]]
bool
any
(
I
ima
)
{
static_assert
(
mln
::
is_a
<
I
,
Image
>
());
static_assert
(
std
::
is_convertible
<
typename
I
::
reference
,
bool
>
());
template
<
class
I
>
[[
deprecated
]]
bool
any
(
I
ima
)
{
static_assert
(
mln
::
is_a
<
I
,
Image
>
());
static_assert
(
std
::
is_convertible
<
typename
I
::
reference
,
bool
>
());
mln_foreach_new
(
auto
&&
val
,
ima
.
new_values
())
if
(
val
)
return
true
;
mln_foreach_new
(
auto
&&
val
,
ima
.
new_values
())
if
(
val
)
return
true
;
return
false
;
}
return
false
;
}
#undef MLN_PRIVATE_DEFINE_UNARY_OPERATOR
...
...
pylene/include/mln/core/image/view/adaptor.hpp
View file @
6fd35d58
...
...
@@ -208,8 +208,8 @@ namespace mln
return
m_ima
.
index_of_point
(
p
);
}
template
<
typename
dummy
=
I
,
typename
=
std
::
enable_if_t
<
(
indexable
::
value
&&
accessible
::
value
)>
>
point_type
point_at_index
(
image_index_t
<
dummy
>
i
)
const
template
<
typename
dummy
=
I
>
point_type
point_at_index
(
std
::
enable_if_t
<
(
indexable
::
value
&&
accessible
::
value
),
image_index_t
<
dummy
>
>
i
)
const
{
return
m_ima
.
point_at_index
(
i
);
}
...
...
pylene/include/mln/core/image/view/transform.hpp
View file @
6fd35d58
...
...
@@ -27,12 +27,6 @@ namespace mln
static_assert
(
!
(
std
::
is_rvalue_reference_v
<
reference
>
&&
!
std
::
is_reference_v
<
image_reference_t
<
I
>>
),
"The transformed image returns a temporary and the mapping function is a projection.
\n
"
"This is building a dangling reference."
);
using
concrete_type
=
image_ch_value_t
<
I
,
value_type
>
;
template
<
typename
V
>
using
ch_value_type
=
image_ch_value_t
<
I
,
V
>
;
/// \}
...
...
@@ -45,13 +39,15 @@ namespace mln
// Transform doesn't preserve contiguity, so it decays from raw_image_tag
using
category_type
=
std
::
conditional_t
<
std
::
is_base_of_v
<
raw_image_tag
,
image_category_t
<
I
>>
,
bidirectional_image_tag
,
image_category_t
<
I
>>
;
/// \}
using
concrete_type
=
image_ch_value_t
<
I
,
value_type
>
;
private:
// FIXME may be a simpler way ?
// note that pixels() can return a proxy convertible to the pixel_type ? Or does it?
// using pixel_range_base_type = decltype(std::declval<I&>.pixels());
// using pixel_proxy_base_type = ::ranges::range_value_t<pixel_proxy_base_type>;
#ifdef PYLENE_CONCEPT_TS_ENABLED
template
<
concepts
::
Value
V
>
#else
template
<
typename
V
>
#endif
using
ch_value_type
=
image_ch_value_t
<
I
,
V
>
;
/// \}
public:
/// Pixel type definitions
...
...
@@ -182,7 +178,8 @@ namespace mln
template
<
class
I1
,
class
I2
,
class
F
>
class
transform2_view
:
public
experimental
::
Image
<
transform2_view
<
I1
,
I2
,
F
>>
{
using
fun_t
=
F
;
using
fun_t
=
F
;
using
common_category
=
std
::
common_type_t
<
image_category_t
<
I1
>
,
image_category_t
<
I2
>>
;
I1
m_ima1
;
I2
m_ima2
;
fun_t
fun_
;
...
...
@@ -191,28 +188,34 @@ namespace mln
/// Type definitions
/// \{
using
reference
=
std
::
invoke_result_t
<
F
&
,
typename
I1
::
reference
,
typename
I2
::
reference
>
;
using
value_type
=
std
::
decay
_t
<
reference
>
;
using
point_type
=
typename
I1
::
point_t
ype
;
using
domain_type
=
typename
I1
::
domain_t
ype
;
using
value_type
=
std
::
remove_cv_t
<
std
::
remove_reference
_t
<
reference
>
>
;
using
point_type
=
std
::
common_type_t
<
image_point_t
<
I1
>
,
image_
point_t
<
I2
>>
;
using
domain_type
=
std
::
common_type_t
<
image_domain_t
<
I1
>
,
image_
domain_t
<
I2
>>
;
/// \}
/// Traits & Image Properties
/// \{
using
accessible
=
std
::
bool_constant
<
I1
::
accessible
::
value
&&
I2
::
accessible
::
value
>
;
using
indexable
=
std
::
false_type
;
// Preservative behavior
using
indexable
=
std
::
false_type
;
// Preservative behavior
using
view
=
std
::
true_type
;
using
extension_category
=
mln
::
extension
::
none_extension_tag
;
// Preservative behavior (may be too preservative)
// Transform doesn't preserve contiguity, so it decays from raw_image_tag
using
category_type
=
std
::
conditional_t
<
std
::
is_base_of_v
<
raw_image_tag
,
common_category
>
,
bidirectional_image_tag
,
common_category
>
;
using
concrete_type
=
std
::
common_type_t
<
image_ch_value_t
<
I1
,
value_type
>
,
image_ch_value_t
<
I2
,
value_type
>>
;
using
concrete_type
=
image_ch_value_t
<
I1
,
value_type
>
;
template
<
class
V
>
using
ch_value_type
=
image_ch_value_t
<
I1
,
V
>
;
#ifdef PYLENE_CONCEPT_TS_ENABLED
template
<
concepts
::
Value
V
>
#else
template
<
typename
V
>
#endif
using
ch_value_type
=
std
::
common_type_t
<
image_ch_value_t
<
I1
,
V
>
,
image_ch_value_t
<
I2
,
V
>>
;
/// \}
public:
/// Pixel type definitions
/// \{
struct
new_pixel_type
:
pixel_adaptor
<
image_pixel_t
<
I1
>>
,
Pixel
<
new_pixel_type
>
struct
new_pixel_type
:
Pixel
<
new_pixel_type
>
{
public:
using
point_type
=
transform2_view
::
point_type
;
...
...
@@ -222,36 +225,27 @@ namespace mln
new_pixel_type
(
fun_t
fun
,
image_pixel_t
<
I1
>
px1
,
image_pixel_t
<
I2
>
px2
)
:
new
_pix
el_type
::
pixel_adaptor
{
std
::
move
(
px1
)}
:
m
_pix
1
{
std
::
move
(
px1
)}
,
m_pix2
{
std
::
move
(
px2
)}
,
fun_
{
std
::
move
(
fun
)}
{
}
new_pixel_type
(
const
new_pixel_type
&
other
)
:
new_pixel_type
::
pixel_adaptor
{
other
}
,
m_pix2
{
other
.
m_pix2
}
,
fun_
(
other
.
fun_
)
{
}
new_pixel_type
(
new_pixel_type
&&
other
)
:
new_pixel_type
::
pixel_adaptor
{
std
::
move
(
other
)}
,
m_pix2
{
std
::
move
(
other
.
m_pix2
)}
,
fun_
(
std
::
move
(
other
.
fun_
))
{
}
new_pixel_type
(
const
new_pixel_type
&
other
)
=
default
;
new_pixel_type
(
new_pixel_type
&&
other
)
=
default
;
reference
val
()
const
{
return
std
::
invoke
(
fun_
,
new
_pix
el_type
::
pixel_adaptor
::
val
(),
m_pix2
.
val
());
}
auto
point
()
const
{
return
new
_pix
el_type
::
pixel_adaptor
::
point
();
}
reference
val
()
const
{
return
std
::
invoke
(
fun_
,
m
_pix
1
.
val
(),
m_pix2
.
val
());
}
auto
point
()
const
{
return
m
_pix
1
.
point
();
}
void
advance
(
point_type
p
)
{
new
_pix
el_type
::
pixel_adaptor
::
advance
(
p
);
m
_pix
1
.
advance
(
p
);
m_pix2
.
advance
(
p
);
}
private:
fun_t
fun_
;
image_pixel_t
<
I1
>
m_pix1
;
image_pixel_t
<
I2
>
m_pix2
;
fun_t
fun_
;
};
/// \}
...
...
@@ -262,69 +256,72 @@ namespace mln
{
}
transform2_view
(
const
transform2_view
&
other
)
:
m_ima1
(
other
.
m_ima1
)
,
m_ima2
(
other
.
m_ima2
)
/*transform_view::image_adaptor{other}*/
,
fun_
(
other
.
fun_
)
{
}
transform2_view
(
transform2_view
&&
other
)
:
m_ima1
(
std
::
move
(
other
.
m_ima1
))
,
m_ima2
(
std
::
move
(
other
.
m_ima2
))
/*transform_view::image_adaptor{std::move(other)}*/
,
fun_
(
std
::
move
(
other
.
fun_
))
{
}
transform2_view
(
const
transform2_view
&
other
)
=
default
;
transform2_view
(
transform2_view
&&
other
)
=
default
;
decltype
(
auto
)
concretize
()
const
{
return
i
mchvalue
<
value_type
>
(
this
->
base
()
);
}
decltype
(
auto
)
concretize
()
const
{
return
m
_ima1
.
template
ch
_
value
<
value_type
>();
}
;
template
<
class
U
>
template
<
class
V
>
decltype
(
auto
)
ch_value
()
const
{
return
i
mchvalue
<
U
>
(
this
->
base
()
);
return
m
_ima1
.
template
ch
_
value
<
V
>(
);
}
auto
domain
()
const
{
return
m_ima1
.
domain
();
}
auto
new_values
()
{
return
mln
::
ranges
::
view
::
transform
(
m_ima1
.
new_values
(),
m_ima2
.
new_values
(),
fun_
);
}
auto
new_values
()
{
static_assert
(
::
ranges
::
ForwardRange
<
decltype
(
m_ima1
.
new_values
())
>
());
static_assert
(
::
ranges
::
ForwardRange
<
decltype
(
m_ima2
.
new_values
())
>
());
return
mln
::
ranges
::
view
::
transform
(
m_ima1
.
new_values
(),
m_ima2
.
new_values
(),
fun_
);
}
auto
new_pixels
()
{
using
R1
=
decltype
(
m_ima1
.
new_pixels
());
using
R2
=
decltype
(
m_ima2
.
new_pixels
());
using
R1
=
decltype
(
m_ima1
.
new_pixels
());
using
R2
=
decltype
(
m_ima2
.
new_pixels
());
static_assert
(
::
ranges
::
ForwardRange
<
R1
>
());
static_assert
(
::
ranges
::
ForwardRange
<
R2
>
());
auto
pxwrapper
=
[
fun
=
this
->
fun_
](
::
ranges
::
range_reference_t
<
R1
>
px1
,
::
ranges
::
range_reference_t
<
R2
>
px2
)
{
return
new_pixel_type
{
fun
,
std
::
move
(
px1
),
std
::
move
(
px2
)};
};
return
mln
::
ranges
::
view
::
transform
(
m_ima1
.
new_pixels
(),
m_ima2
.
new_pixels
(),
pxwrapper
);
}
template
<
typename
dummy
=
reference
>
std
::
enable_if_t
<
accessible
::
value
,
dummy
>
operator
()(
point_type
p
)
/// Accessible-image related methods
/// \{
template
<
typename
Ret
=
reference
>
std
::
enable_if_t
<
accessible
::
value
,
Ret
>
operator
()(
point_type
p
)
{
mln_precondition
(
m_ima1
.
domain
().
has
(
p
));
mln_precondition
(
m_ima2
.
domain
().
has
(
p
));
return
std
::
invoke
(
fun_
,
m_ima1
.
at
(
p
),
m_ima2
.
at
(
p
));
}
template
<
typename
dummy
=
reference
>
std
::
enable_if_t
<
accessible
::
value
,
dummy
>
at
(
point_type
p
)
template
<
typename
Ret
=
reference
>
std
::
enable_if_t
<
accessible
::
value
,
Ret
>
at
(
point_type
p
)
{
return
std
::
invoke
(
fun_
,
m_ima1
.
at
(
p
),
m_ima2
.
at
(
p
));
}
template
<
typename
dummy
=
new_pixel_type
>
std
::
enable_if_t
<
accessible
::
value
,
dummy
>
new_pixel
(
point_type
p
)
template
<
typename
Ret
=
new_pixel_type
>
std
::
enable_if_t
<
accessible
::
value
,
Ret
>
new_pixel
(
point_type
p
)
{
mln_precondition
(
m_ima1
.
domain
().
has
(
p
));
mln_precondition
(
m_ima2
.
domain
().
has
(
p
));
return
{
fun_
,
m_ima1
.
new_pixel
(
p
),
m_ima2
.
new_pixel
(
p
)};
}
template
<
typename
dummy
=
new_pixel_type
>
std
::
enable_if_t
<
accessible
::
value
,
dummy
>
new_pixel_at
(
point_type
p
)
template
<
typename
Ret
=
new_pixel_type
>
std
::
enable_if_t
<
accessible
::
value
,
Ret
>
new_pixel_at
(
point_type
p
)
{
return
{
fun_
,
m_ima1
.
new_pixel_at
(
p
),
m_ima2
.
new_pixel_at
(
p
)};
}
/// \}
};
...
...
@@ -345,6 +342,11 @@ namespace mln
static_assert
(
mln
::
is_a
<
I1
,
experimental
::
Image
>
());
static_assert
(
mln
::
is_a
<
I2
,
experimental
::
Image
>
());
#ifdef PYLENE_CONCEPT_TS_ENABLED
static_assert
(
mln
::
concepts
::
InputImage
<
I1
>
);
static_assert
(
mln
::
concepts
::
InputImage
<
I2
>
);
#endif
return
{
std
::
move
(
ima1
),
std
::
move
(
ima2
),
std
::
move
(
fun
)};
}
}
// namespace view
...
...
pylene/include/mln/core/image/view/zip.hpp
0 → 100644
View file @
6fd35d58
#pragma once
#include <mln/core/image/image.hpp>
#include <mln/core/image/view/adaptor.hpp>
#include <mln/core/rangev3/view/zip.hpp>
#include <tuple>
#include <type_traits>
namespace
mln
{
template
<
class
...
Images
>
class
zip_view
:
public
experimental
::
Image
<
zip_view
<
Images
...
>>
{
using
tuple_t
=
std
::
tuple
<
Images
...
>
;
using
I0
=
typename
std
::
tuple_element
<
0
,
tuple_t
>::
type
;
using
common_category
=
std
::
common_type_t
<
image_category_t
<
Images
>
...
>
;
tuple_t
m_images
;
public:
/// Type definitions
/// \{
using
reference
=
std
::
tuple
<
image_reference_t
<
Images
>
...
>
;
using
value_type
=
std
::
tuple
<
image_value_t
<
Images
>
...
>
;
using
point_type
=
std
::
common_type_t
<
image_point_t
<
Images
>
...
>
;
using
domain_type
=
std
::
common_type_t
<
image_domain_t
<
Images
>
...
>
;
/// \}
/// Traits & Image Properties
/// \{
using
accessible
=
std
::
conjunction
<
typename
Images
::
accessible
...
>
;
using
indexable
=
std
::
false_type
;
// Preservative behavior
using
view
=
std
::
true_type
;
using
extension_category
=
mln
::
extension
::
none_extension_tag
;
// Preservative behavior
// Zip doesn't preserve contiguity, so it decays from raw_image_tag
using
category_type
=
std
::
conditional_t
<
std
::
is_base_of_v
<
raw_image_tag
,
common_category
>
,
bidirectional_image_tag
,
common_category
>
;
using
concrete_type
=
image_ch_value_t
<
I0
,
typename
I0
::
value_type
>
;
#ifdef PYLENE_CONCEPT_TS_ENABLED
template
<
concepts
::
Value
V
>
#else
template
<
typename
V
>
#endif
using
ch_value_type
=
image_ch_value_t
<
I0
,
V
>
;
/// \}
static_assert
(
std
::
conjunction_v
<
std
::
is_same
<
image_point_t
<
Images
>
,
point_type
>
...
>
,
"The point type of all images to be zipped must be the same."
);
public:
/// Pixel type definitions
/// \{
struct
new_pixel_type
:
Pixel
<
new_pixel_type
>
{
using
reference
=
zip_view
::
reference
;
using
value_type
=
zip_view
::
value_type
;
using
site_type
[[
deprecated
]]
=
zip_view
::
point_type
;
using
point_type
=
zip_view
::
point_type
;
new_pixel_type
(
image_pixel_t
<
Images
>
...
pixels
)
:
m_pixels
{
std
::
move
(
pixels
)...}
{
}
new_pixel_type
(
const
new_pixel_type
&
)
=
default
;
new_pixel_type
(
new_pixel_type
&&
)
=
default
;
new_pixel_type
&
operator
=
(
const
new_pixel_type
&
)
=
delete
;
new_pixel_type
&
operator
=
(
new_pixel_type
&&
)
=
delete
;
point_type
point
()
const
{
return
std
::
get
<
0
>
(
m_pixels
).
point
();
}
reference
val
()
const
{
auto
build_value
=
[](
auto
&&
...
pixels
)
->
reference
{
return
{
pixels
.
val
()...};
};
return
std
::
apply
(
build_value
,
m_pixels
);
}
void
advance
(
point_type
q
)
{
auto
g
=
[
q
](
auto
&&
...
pixels
)
{
(
pixels
.
advance
(
q
),
...);
};
std
::
apply
(
g
,
m_pixels
);
}
private:
std
::
tuple
<
image_pixel_t
<
Images
>
...
>
m_pixels
;
};
/// \}
zip_view
(
Images
...
images
)
:
m_images
{
std
::
move
(
images
)...}
{
}
zip_view
(
const
zip_view
<
Images
...
>&
)
=
default
;
zip_view
(
zip_view
<
Images
...
>&&
)
=
default
;
zip_view
<
Images
...
>&
operator
=
(
const
zip_view
<
Images
...
>&
)
=
delete
;
zip_view
<
Images
...
>&
operator
=
(
zip_view
<
Images
...
>&&
)
=
delete
;
auto
domain
()
const
{
return
std
::
get
<
0
>
(
m_images
).
domain
();
}
decltype
(
auto
)
concretize
()
const
{
return
std
::
get
<
0
>
(
m_images
).
concretize
();
}
#ifdef PYLENE_CONCEPT_TS_ENABLED
template
<
concepts
::
Value
V
>
#else
template
<
typename
V
>
#endif
decltype
(
auto
)
ch_value
()
const
{
return
std
::
get
<
0
>
(
m_images
).
template
ch_value
<
V
>();
}
auto
new_values
()
{
auto
g_new_values
=
[](
auto
&&
...
images
)
{
return
ranges
::
view
::
zip
(
images
.
new_values
()...);
};
return
std
::
apply
(
g_new_values
,
m_images
);
}
auto
new_pixels
()
{
auto
g_new_pixels
=
[](
auto
&&
...
images
)
{
return
ranges
::
view
::
zip_with
([](
auto
&&
...
pixels
)
{
return
new_pixel_type
(
pixels
...);
},
images
.
new_pixels
()...);
};
return
std
::
apply
(
g_new_pixels
,
m_images
);
}
/// Accessible-image related methods
/// \{
template
<
typename
Ret
=
reference
>
std
::
enable_if_t
<
accessible
::
value
,
Ret
>
operator
()(
point_type
p
)
{
mln_precondition
(
all_domain_has
(
p
));
return
this
->
at
(
p
);
}
template
<
typename
Ret
=
reference
>
std
::
enable_if_t
<
accessible
::
value
,
Ret
>
at
(
point_type
p
)
{
auto
g
=
[
p
](
auto
&&
...
images
)
{
return
std
::
forward_as_tuple
(
images
.
at
(
p
)...);
};
return
std
::
apply
(
g
,
m_images
);
}
template
<
typename
Ret
=
new_pixel_type
>
std
::
enable_if_t
<
accessible
::
value
,
Ret
>
new_pixel
(
point_type
p
)
{
mln_precondition
(
all_domain_has
(
p
));
return
this
->
new_pixel_at
(
p
);
}
template
<
typename
Ret
=
new_pixel_type
>
std
::
enable_if_t
<
accessible
::
value
,
Ret
>
new_pixel_at
(
point_type
p
)
{
auto
g
=
[
p
](
auto
&&
...
images
)
{
return
new_pixel_type
(
images
.
new_pixel_at
(
p
)...);
};
return
std
::
apply
(
g
,
m_images
);
}
/// \}
private:
template
<
typename
dummy
=
bool
>
std
::
enable_if_t
<
accessible
::
value
,
dummy
>
all_domain_has
(
point_type
p
)
{
auto
g_has
=
[
p
](
auto
&&
...
images
)
{
return
(
images
.
domain
().
has
(
p
)
&&
...);
};
return
std
::
apply
(
g_has
,
m_images
);
}
};
namespace
view
{
template
<
class
...
Images
>
zip_view
<
Images
...
>
zip
(
Images
...
images
)
{
static_assert
(
std
::
conjunction_v
<
is_a
<
Images
,
experimental
::
Image
>
...
>
,
"All zip arguments must be images."
);
return
zip_view
<
Images
...
>
(
std
::
move
(
images
)...);
}
}
// namespace view
}
// namespace mln
pylene/include/mln/core/rangev3/view/transform.hpp
View file @
6fd35d58
...
...
@@ -33,13 +33,21 @@ namespace mln::ranges
{
private:
// Very bad way to access the private member
auto
fun
()
const
{
return
reinterpret_cast
<
const
detail
::
iter_transform_view_public
<
Rng
,
Fun
>*>
(
this
)
->
fun_
;
}
auto
cfun
()
const
{
return
reinterpret_cast
<
const
detail
::
iter_transform_view_public
<
Rng
,
Fun
>*>
(
this
)
->
fun_
;
}
auto
fun
()
{
return
reinterpret_cast
<
detail
::
iter_transform_view_public
<
Rng
,
Fun
>*>
(
this
)
->
fun_
;
}
public:
using
::
ranges
::
iter_transform_view
<
Rng
,
Fun
>::
iter_transform_view
;
template
<
typename
U
=
void
,
typename
=
std
::
enable_if_t
<
is_segmented_range_v
<
Rng
>,
U
>>
auto
rows
()
const
{
return
::
ranges
::
view
::
transform
(
this
->
base
().
rows
(),
[
fun_
=
cfun
()](
auto
row
)
{
return
::
ranges
::
view
::
iter_transform
(
row
,
fun_
);
});
}