CataMap¶
Catacombs maps using SVG source map with codes inside it.
The program allows to produce:
2D “readable” maps with symbols changed to larger ones, second level shifted to avoid superimposition of corridors, enlarged zooms, shadowing etc.
3D maps to be used in a 3D visualization program, a webGL server, or the CataZoom app.
Requirements¶
Having inkscape installed on the system and available in the PATH. A recent version of inkscape (1.0 at least) is recommended to avoid units and scaling problems. Inkscape is needed for 2D maps renderings, it is not needed for the 3D mode.
Either (for 2D maps):
the Pillow (PIL) python module (see later)
or ImageMagick “convert” tool to convert PNG to JPEG. If Pillow is present, then convert will not be used.
Warning: https://github.com/ImageMagick/ImageMagick/issues/396 ImageMagick cache (disk limit) size is too small. Edit /etc/ImageMagick-6/policy.xml and change disk resource limit:
<policy domain="resource" name="memory" value="12GiB"/> <policy domain="resource" name="map" value="20GiiB"/> <policy domain="resource" name="width" value="50KP"/> <policy domain="resource" name="height" value="50KP"/> <policy domain="resource" name="area" value="20GiB"/> <policy domain="resource" name="disk" value="80GiB"/>
Python modules:
These can be installed using the command:
python -m pip install numpy scipy Pillow
svg_to_mesh
submodule and its requirements (part of this project)xml ElementTree
numpy
scipy
Pillow (PIL) optionally for PNG/JPEG image conversion. Otherwise ImageMagick “convert” tool will be used (see above)
pyclipper, used in 2D maps and only when zoomed zones are used. You can install it via pip.
The 3D part has additional requirements:
soma.aims (https://github.com/brainvisa/aims-free)
anatomist (https://github.com/brainvisa/anatomist-free and https://github.com/brainvisa/anatomist-gpl)
json
The maps differences tool (diff_svg
) also needs:
yaml (pip module
pyyaml
)
Usage¶
set the
python
subdirectory of the project in yourPYTHONPATH
environment variable. Under Unix sh/bash shells, this would be:export PYTHONPATH="~/fdc_catamaps/python:$PYTHONPATH"
(it can be set in a
.bash_profile
or.bashrc
init file)get or make the source SVG file with codes inside, for instance
plan_14_fdc_2021_04_29.svg
main
* go to the directory containing it
* run the module catamap
as a program:
python -m catamap --2d plan_14_fdc_2021_04_29.svg
It should work using python3 (python2 support has been dropped). The 2D maps options will produce files with suffixes in the current directory: modified .svg files, .pdf and .jpg files.
The 3D maps option will produce meshes in a subdirectory.
Use the commandline with the ‘-h’ option to get all parameters help.
Inkscape SVG files¶
SVG files may (should) contain additional XML properties that can be set in the XML editor in the Inkscape software. They allow to specify how objects should be parsed, grouped, represented etc. For now they are mainly used in the 3D part, but the 2D part also uses level
, label
, and private
information information.
Codes correspond to properties used in the program, and can be set in XML elements in the SVG file.
Bool properties can be written true
, True
, 1
, or false
, False
, 0
.
Properties are inherited from parent (group/layer) to children. Thus if a layer has the property corridor
set to true
, all objects in this layer will be marked as corridor
.
In the program, elements are grouped into meshes: a mesh will be the concatenation of all elements of the same kind, to avoid having dozens of thousands of mesh files to load. An object “kind” (a group making a single mesh) is identified by several of its properties, but not all. Namely the identifier is:
<label>_<level>_<public/private>_<accessible/inaccessible>[_<category>]
Other properties are not discriminative, so in some conditions may not be taken into account. For instance if a layer defines a label, level, public and accessible states, and marks items as corridors, if one element inside adds a property block
, it will be part of the same mesh group anyway, and the block
property will be ignored.
Properties list¶
- alt_colors: JSON dict (2D and 3D maps)
color to be used alternatively in maps. This is a string representing a JSON format dictionary. Keys are colorsets names, values are a second level of dictionary which specifies color properties, a bit like for SVG elements style. The default colorset for 3D maps is
map_3d
. Ex:{"map_3d": "#cccccc4c"}
see also: Colorsets
- arrow: bool (3D maps)
arrows join a text label to a location on map. They are filar meshes. Most of them are just a segment (2 points) but they may contain more points. Points orientation is important as the arrow goes from the text (above the meshes) down to the pointed item below.
- arrow_base_height_shift: float (3D maps)
z shift of the base of an arrow element in the upper layer depth. The arrow head shift is specified using height_shift.
- block: bool (3D maps)
block elements have a ceiling and walls. Meshes are extruded and tesselated to be filled.
- border: bool (3D maps)
not used if I remember…
- camera_light: str (3D maps)
if set to
off
, the camera light (headlamp) is disabled.- category: str (3D maps)
the category string the element will be associated in the 3D views. Categories can be displayed/hidden using buttons or menus in 3D views.
- catflap: bool (3D maps)
In catflaps, paths are replaced with striped tubes.
- ceil_texture: JSON dict (3D maps)
Texture definition for the ceiling part of elements. See Texturing below for details.
- colorsets: JSON dict (2D maps)
used as a property of the
metadata
layer only, it specifies which default colorset is associated with specific map types, for instance:{"private": "black", "igc": "igc"}
see also: Colorsets
- colorset_inheritance: JSON dict (2D and 3D maps)
used as a property of the
metadata
layer only, it specifies colorsets which can inherit the colors defined by another, in order to minimally specialize it.see also: Colorsets
- contrast_floor: str (3D maps)
if true (which is the default), corridor or block top and bottom meshes are contrasted compared to wall meshes: the wall colors (given as the color properties) are lightened or darkened before being assigned to floor or ceilings. If you don’t want this, set this property to false. A third value is allowed:
if_no_tex
, meaning that contrasting colors is enabled only in non-textured mode (if the commandline option--texture
is not set).- corridor: bool (3D maps)
corridors have a floor and walls. Meshes are extruded and tesselated to be filled.
- date: str (2D maps)
the date text will be replaced with the date of the map build.
- default_categories: JSON list (3D maps)
list of categories which are visible by default (checked in the viewer)
- depth_map: bool (3D maps)
the layer is a depth map. It should contain a
level
property to define the level it maps. See Depth maps for details.- floor_texture: JSON dict (3D maps)
Texture definition for the floor part of elements. See Texturing below for details.
- glabel: str (2D maps)
“group label” used to replace elements with ones from the legends layer. The
glabel
is associated to one legends element if the legends elementlabel
property has the value of theglabel
property of the element plus the duffix_proto
. Ex, in the legends:label: colim_proto
in the map elements:
glabel: colim
- gltf_properties: JSON dict (3D maps)
optionally set on texture image elements, they specify how the texture image is mapped and repeaded on the meshes. See Texturing for details.
- height_map: bool (3D maps)
the layer is a height map. This is the same as depth_map except that heights are inverted compared to depths, and that a height map may be relative to another depth map (see the
relative_to
property). All related attributes are the same as for depth_map otherwise.- height_shift: float (3D maps)
z shift of the element (esp. for corridor, block, wall elements, but also wells and arrows). An element with a height shift will not begin on the ground, but above or below as specified.
- hidden: bool (2D and 3D maps)
removed from 3D maps.
- inaccessible: bool (3D maps)
inaccessible elements will be separated from others, and set in the
Inaccessible
display category.- item_height: float (3D maps)
height of the element (esp. for corridor, block, wall elements). WARNING: it is
item_height
, notheight
as height is already an official SVG attribute for some elements (rectangles for instance).- label: str (2D and 3D maps)
name of the element type
- label_alt_colors: JSON dict (2D and 3D maps)
Like alt_colors, except that the dict has an upper-level which keys area object labels. The dict can be applied hierarchically, thus put in a layer. Ex:
{"repetiteur": {"black": {"bg": "#cccccc4c"}}}
see also: Colorsets
- legend: bool (2D maps)
set on a layer, indicates that this layer contains the legend symbols and can be searched for replacement symbols (wells, etc) which will replace those in the map to enlarge them and ease view from a bit further.
- level: str (2D and 3D maps)
depth level name (sup, inf, surf, tech, metro, esc…). Levels are an “open” property, there is no predefined list of levels, apart for 2 exceptions:
items which don’t specify a level are set by default to a level named
sup
(generally superior corridor level).a
surf
level represents the ground surface, and is automatically built. It is flat, altitude 0 by default, but can be associated to an altitude map and geolocalisation information. See Altitude maps later.
Levels are associated to depth maps, so for each level used (except
surf
), adepth_map
layer is supposed to be defined. See Depth maps.- main_clip_rect_id: JSON dict (2D maps)
set in the Inkscape metadata layer, it indicates the clip rectangle ID (in the XML elements IDs) for each map type. A default (fallback) one can be given under the key
default
in the dict. Ex:{"default": "clip_general", "private": "clip_all"}
so that, in this example, the
private
map gets a different field of view from the other ones.- map_transform: SVG transformation spec (2D maps)
additional transformation applied to elements, used for instance to shift lower level parts when they are superimposed under an upper level. Without this shift, they would not be seen because they are hidden by the upper level. The transform is specified in the same way as the standard SVG
transform
property.This propery can be set to paths, groups, and arrows (which will thus point to a shifted location).
- maps_def: JSON dict (2D maps)
In the SVG metadtadata layer. Definition of 2D maps types (to be used with the -m commandline option). See maps types later for details.
- marker: str (3D maps)
set on a layer to specify that this layer is a markers layer. Three types of markers are currently recognized:
sounds
,photos
, andlights
.See Markers for more details.
- markers_base_url: bool (3D maps)
set on a marker layer to specify that marekrs in this layer have URLS which point to the server directory specified here. Individual markers will be appended to this base URL. The URL may be absolute (
https://photos.google.com/xyzsomething
) or relative to the map server (photos/photo_dir
). If not specified, the default base url is the markers type (photos
,sounds
), in relative mode.- markers_map: str (3D maps)
Set on a marker layer: correspondence map file name (CSV file) for markers text. See Markers for more details.
- non_visibility: str (2D maps)
list of maps types (json-like), for which this layer is removed. The inverse of visibility (see below).
- private: bool (2D and 3D maps)
private elements will only be visible if a code is provided
- proto_scale: float (2D maps)
Only in the legend layers elements which are prototypes for symbols replacements, this is the scale to be applied when replacing. The default scale is 0.5 (replaced elements will be half the size they have in the legend).
- radius: float (**3D maps)
used in a “marker” layer to specify the max radius between the user click and the marker position for it to be triggered. It can be set on the marker layer itself, or on any marker item inside.
See Markers for more details.
- relative_to: str (3D maps)
for height maps or depth maps layers, specify to which depth map the height is relative to. The default is surface depth (which means 0 or the ground altitude map).
- replace_children: bool (2D maps)
should be set only in replacement symbols in the legend layer (wells signs, etc) to indicate that children of matching elements should be parsed recursively and their children may be replaced also.
- shadow: bool (2D maps)
marks the element (or layer…) to have a halo / shadow around it
- shadow_scale: float (2D maps)
in the metadata layer, sets a global shadow scale applied to all shadow operations.
- symbol: bool (3D maps)
not sure it is used, after all…
- symbol_scale: float (3D maps)
in the metadata layer, scale of symbol meshes (markers, fontis, etc)
- text: bool (3D maps)
text layers.
- texture: JSON dict (3D maps)
Texture definition for elements. See Texturing below for details.
- title: bool (3D maps)
The title string(s) will be used and displayed in the web site title.
- travel_ref_level: str (3D maps)
depth level used to define the 3D ground level. It is used to adapt the travel speed scale (for 3D controls) depending to the altitude of the camera to this level. Up to now the level is assimilated to its average altitude, but this could be refined to approximate a plane, if needed. The default is the
sup
level (default level for all elements).- travel_speed_base: float (3D maps)
Travel speed factor for 3D controls at the altitude of the
travel_level
altitude, which is the minimum speed. The default is 0.03.- travel_speed_alt_factor: float (3D maps)
Scale factor applied to the distance to the
travel level
to adapt the travel speed: speed increases with this “elevation” according to this factor. The default is: 0.003.- transform_3d: str( 3D maps)
3D transformation, used to rotate an object in space. The spec is similar to SVG transformations specs, except that it has one more dimension, and the “matrix()” spec becomes “matrix4()”, with 12 parameters (columns of the matrix).
- upper_level: str (3D maps)
depth level for the top of elements. Only used for elements joining two levels (wells, arrows)
- use_height_map: str (3D maps)
When set on a corridor, block or wall layer, it replaces the constant item_height when extruding the height with a height map whose level is given by the value of this property.
- visibility: str (2D and 3D maps)
may be either:
private
: alternative toprivate: true
, or a list of maps types (json-like), for which this layer is kept visible. If such a list is specified, then maps types not listed here will drop the layer. Asvisibility
has now a broader meaning, it is better to specifyprivate: true
for private things, to avoid ambiguities.- wall: bool (3D maps)
wall elements have only side walls (no floor or ceiling).
- wall_texture: JSON dict (3D maps)
Texture definition for the walls part of elements. See Texturing below for details.
- well: bool (3D maps)
wells are replaced with custom elements, which type is the element label (PE, PS, PSh, échelle, sans, P ossements, …). Well elements (or groups, or layers) shoud specify the level and upper_level.
- well_read_mode: str (3D maps)
tells if well elements should be read in the XML file as a single “path” element (a circle for instance), or a group (a grop containing a circle, and additional lines). Thus allowed values are
path
orgroup
.- z_scale: float or “auto” (**3D maps)
Can be set in the SVG metadtadata layer. This scale factor applies to depths and heights in order to match x, y scalings which may be arbitraty. The default is 0.5 and is also arbitrary. If it is set to “auto”, then if lambert93 coordinates are provied in the appropriate layer, the scale factor will be processed according to these “true” coordinates to match x and y scales.
- zoom_area_id: str (2D maps)
Identifier for a zoomed area zone layer. Should be present in a layer containing a polygon which defines a source region. The identifier is also present in a target zoom region layer, see
zoom_id
. See also Zoomed regions for details.- zoom_hidden: bool (2D maps)
Layers marked with this will be excluded from zoomed areas. See also Zoomed regions for details.
- zoom_id:* str (2D maps)
Identifier for a zoomed area zone layer. Should be present in a layer containing a rectangle for the target zoomed region. The identifier is also present in a source zoom region polygon layer, see
zoom_area_id
. See also Zoomed regions for details.
Maps types¶
Most common types, such as “public”, “private” are (for now at least) builtin
in the program, but the maps_def
property dict in the metadata layer allows
to define new maps types associated with specific filters. Each map type is a
dictionary which defines the following:
Ex:
{
"igcportail": {
"name": "igcportail",
"filters": ["igc_private"],
"shadows": false,
"do_pdf": false,
"do_jpg": false,
},
}
- name: str
name of the map type, usually the same as the map type key.
- filters: list
list of filters used for this map type. Several filters are available in the program. The filters list is available using the
--list-filters
option of the commandline.- shadows: bool
if true, shadows are applied in layers or objects which define the
shadow
property. If false, shadows are disabled.- do_pdf: bool
if false, PDF output is not processed.
- do_jpg: bool
if false, JPEG or TIFF bitmap output is not processed.
Depth maps¶
Depth maps are layers containing depth information, and nothing else.
Each depth information specifies the depth of a specifi point in the map. They can be specified in several ways:
a text element: the position of the element (its center if the text is centered) will be used as the position. The text should specify a floating point number which is the depth at this position.
a group containing a text element and a segment path: the text is a float number specifying the depth, and the segment (2 points, oriented from the text toward the application point) specifies where the depth applied: the end pont of the segment will be assigned the given depth.
a rectangle: this was originally the way to specify depth, but it proved to be difficult to read and is thus obsolete. Prefer the two above methods. In 2 words, the min of the rectangle is the depth, and the position of the rectangle (its center) is the position. Well, better forget it.
Altitude maps¶
Altitude maps can be built and used to shift all other depth maps, which are supposed to be relative to the surface ground altitude map (for now at least: we may change this later using an upper_level
property in depth maps which could be any other map).
To work we require more information, because we need actual altitude maps, and a geolocalisation of the inkscape SVG file.
Geolocalisation of the SVG file¶
The SVG file should contain a layer named lambert93
which contains, as its name says it, world coordinates in the Lambert 93 coordinates system.
Coordinates can be spacified at any location of the map. At least 3 points are needed to estimate a transformation, but the more points are provided, the more precise the estimation will be. The coordinates transformation between the SVG positions and the Lambert93 coordinates will be estimated as a linear transformation fit to all SVG/Lambert 93 coortinates couples.
A Lambert93 point is specified in this lambert93
layer as a group containing 2 objects:
a text item with text being the 2 cooridinates separated by a coma, ex:
652470.89,6858871.84
a segment line (2 points, oriented) going from the text toward the application point on the map.
Lambert 93 positions can be found using https://www.geoportail.gouv.fr/carte: on the map, select “tools” on the right, and enable “display coordinates”. Then select for “reference system” the “Lambert 93” mode.
Altitude maps¶
Altitude maps can be retreived from BDAlti: https://geoservices.ign.fr/documentation/diffusion/telechargement-donnees-libres.html#bd-alti
Then maps have to be converted using tools in catamap.altitude.bdalti
.
The altitude
directory should be located in the same directory as the SVG map file.
Example
See the map: example map
The result in 2D is (left: original map, right: result):
![_images/example_map.png](_images/example_map.png)
![_images/example_map_imprimable.jpg](_images/example_map_imprimable.jpg)
In 3D: here
See for instance how wells indications are enlarged in the “printable” 2D map, the inferior level is shifted to allow seing it when it is superimposed with the upper level, while they are still superposed in the 3D map.
Colorsets¶
Both 2D and 3D maps, while processed, may assign different colorsets to elements, if specified via the --color
option. A colorset is a defined by a name. Each element, group, layer, or labelled element can be assigned a different color for each colorset. Colorsets are defined dynamically in the map SVG source file. XML elements having a alt_colors
property can both define colorsets and assign colors.
A few “hard-coded” colorsets are expected to exist (even it it is not mandatory) and are used by default:
3D maps use by default the
map_3d
colorset.2D maps using “igc” mode (with ICC maps overlayed) use the
igc
colorset.
The list of colorsets defined in a given SVG map file can be queried using the --list-colorsets
option:
python -m catamap --list-colorsets plan_14_fdc_2023_07_31.svg
A map file may specify which colorset is used by each map type in the colorsets
property in the metadata
layer. See colorsets property.
Colorsets inheritance¶
Some colorsets may be slight variants to other existing ones. To avoid redefining every element color in the SVG file, it is possible to specify some “colorset inheritances”. This is done using the colorset_inheritance
property in the metadata
layer (a hidden layer made for SVG / inkscape). This property is a JSON dictionary, with a {'child': 'parent'}
shape. The meaning is that a child inherits all its parent colors, and then can override some.
Colors specifications¶
An alt_colors
property applies recursively to all its children. It is a JSON dictionary, whith the followin shape:
primary keys are colorset names
primary values are color specs
A color spec is normally also a dict, with the following shape:
keys are like in SVG elements style,
fg
(foreground),bg
(background),stroke-width
values are strings, either containing the RGBA color, or a float value for
stroke-width
.colorsets used only in 3D may shunt the second level and specify directly a single RGBA color string as colorspec value.
Ex:
{"map_3d": "#c0c0c0ff",
"igc": {"bg": "#ff0000ff"},
"black": {"fg": "#ffffffff", "bg": "#c0606060ff", "stroke-width": "0.2"}}
A label_alt_colors
property has an additional upper level whick key is the element label, and the primary value is like the alt_colors
dict:
{"repetiteur": {"black": {"bg": "#c0c0c0ff"}},
"marches": {"black": {"fg": "#c0c0c0ff"}}}
Markers¶
Markers are small marker objects pointing to external links, such as photographs, or sounds. When the user clicks on a marker, or sufficiently close to it in a given radius, it triggers a link to an external resource (an web URL).
Markers are recorded in dedicated layers in the SVG file. Such layer must have a marker
property, which value is the type of markers in the layer. Currently two types of markers are handled: photos
(links to photographs URLS) or sounds
.
Sounds are handled specificly using a media player inside the 3D map, whereas photographs are just web links, and may actually point to any web resource or page (web page, photo file, video, or anything).
A marker layer can have markers_base_url
or radius
properties, which respectively specify the base URL for all markers, and the max distance to the marker for which a user click will trigger the marker.
The layer contents are similar to depth layers: they are text objects, or groups containing a text object and a line object to make an arrow from the text to the marker exact location. The layer may not have other kind of groups, it is not recursive.
Items in the marker layer are thus text at specified locations. The text is the URL of the resource (sound, photo, …) and is appended to the base URL above. If no markers_base_url
is specified, the marker value (type) is used as a relative directory as base URL (sounds/...
or photos/...
).
Each item may get a specific radius
property, which may overload the layer radius. If no radius is specified, a default is used (10., which would correspond to 10 m radisu, depending on the map scale).
If an item text has no file extension, .jpg
will be appended by the server in a photos markers layer. This way the map source, in Inkscape, may display a very short, readable, indication, such as a single number: for instance, 123
will be replaced with photos/123.jpg
.
On the web server side, photos and sounds directory have to be created and contain the referenced files.
Markers text syntax¶
Markers text may be a filename (which will be prefixed with the contents of the markers_base_url
property, and possibly suffixed with .jpg
), or a list of such filenames:
image1.jpg, video2.mp4, image3.jpg
or:
image1, video2.mp4, image3
In addition to the “direct URL” mechanism above, it is also possible to specify, for each markers layer, a “correspondance map” file (using the markers_map
property on the layer). This file will be read as a CSV file (with tab
separators). Then texts in markers text in the SGV file will go through this map to get a “final” file name for the marker element. A given marker text can be found several times in the file, and then several files will be associated with the marker element. For instance if you use numbers for markers texts, 1
, 2
, 3
in the SVG map, a markers_map
can specify final filenames such as:
20220304_201758.jpg 1
20220304_201802.jpg 2
20220304_201804.jpg 1
20220304_201815.jpg 3
20220304_202652.jpg 2
20220304_202810.jpg 1
will assign to marker 1
the files: 20220304_201758.jpg
, 20220304_201804.jpg
, 20220304_202810.jpg
, and so on. Each of the file names will undergo the prefix/suffix transformations using markers_base_url
etc.
Zoomed regions¶
Zoomed regions may be displayed to represent en enlarged duplicated portion of the original map. To do so we need 3 components, in 3 different layers:
a source zoomed region definition. This is done in a layer containing a
zoom_area_id
property, this layer should contain a single closed and connected polygon, which traces the region to be zoomed. The zoom_area_id` identifier will be matched to a target zoom region.a target zoomed region area definition (where the zoomed copy will be drawn). This is done in a layer containing a
zoom_id
property (matching a source region definition identifier). This layer should contain a single rectangle, which marks the bounding box of where the zoomed copy of the map will be drawn.
Other layers can be marked with a zoom_hidden
property, which indicates that these layers should not be part of zoomed regions.
Lights¶
Lights may be inserted in the 3D maps. They are actually handled as a special marker type. Thus they are specified in a dedicated layer, using the marker
property with the value lights
.
Then elements are like markers: either a text element, or a group containing a text and a segment arrow to point at its exact position. The element can contain the property light_props
to specify the light characteristics. This property is a JSON dict, with the following items:
- type: string
light type:
point
,directional
orspot
.- color: list of float
color of the light, as a triplet (RGB) of float values in the range 0.-1.
- intensity: float
intensity of the light source, default: 1.0
- range: float
range of the light. 0 is infinity, otherwise this value drives the decay of the light with distance from the source.
- direction: list of float
for directional lights (directional, spot), direction of the light.
Other properties may be specified (like the spot cone angle) as in https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual/README.md
Texturing¶
In 3D mode, elements are transformed into meshes. By default meshes have a color but no texture (images mapped on the meshes). It is possible to specify texturing, by using images loaded in a hidden layer of the SVG file, and telling which texture image is associated with given elements, and how it is mapped.
Texturing involves 3 parts: texture images, mesh-image mapping, and texturing properties.
Texture images¶
They are images inserted in the Inkscape SVG file, and meant to be used for texturing. They are generally inserted into one or several separate layers, which are hidden in normal display modes.
Texture image elements may optionally contain texture mapping properties, in the gltf_properties
property (see below, texturing properties).
Mesh-image mapping¶
Texture may be associated with an individual polygon element, or to a group or a layer, like most other properties. To be textured, an element shoud have either texture
, ceil_texture
, wall_texture
or floor_texture
properties defined, or several of them. ceil_texture
, wall_texture
or floor_texture
represent texturing properties for (respectively) the ceiling, walls, or floor part of an element. texture
is the default texturing properties used for all of them (walls, ceil, floor) if other parts specifications are not given. Each of those texturing definition properties is a JSON dictionary, structured like the following:
- id: string (mandatory)
SVG ID of the texture image to be mapped. The image element itself is generally in a different SVG layer, as explained above.
- mapping_method: string (optional)
specifies how the image is mapped on the mesh. Available methods are, for now,
geodesic_z
andxy
. These are described below. The defautl value for ceilings and floors isxy
andgeodesic_z
is the default for walls.
Texture mapping modes¶
- xy:
used for horizontal (or semi-horizontal) meshes. Texture coordinates are the x,y projection (2D) of mesh coordinates, with appropriate scaling factors, in order to have the texture image exactly where it is in the SVG file.
- geodesic_z:
used for vertical meshes. Walls are generally not all in the same plane, and can contain bifurcations. To be correctly mapped (as a wallpaper), texture images should follow a geodesic alignment, starting at the first mesh point, in order to follow curves and bifurcations.
Texturing properties¶
They describe how a texture image is colored, and repeated on a mesh.
At the moment, only limited support for properties is implemented, and such properties are only associated with the texture image elements. In the future we could also specify it in the mesh-image mapping. Anyway this is given via the optional gltf_properties
property on the texture image element.
We use gltf_properties
because these properties are based on the GLTF format. See https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-sampler for details. This property is a JSON dictionary, which may contain the following:
- sampler: JSON dict
specified how the image wraps around the mesh texture coordinates. The fll description is fund at: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-sampler, but mainly, the following sub-properties are used:
- wrapS: int
1st texture coord mapping. 10497 means REPEAT; 33071 means CLAMP_TO_EDGE; 33648 means MIRRORED_REPEAT. (I did not invent these funny values…)
- wrapT: int
2nd texture coord mapping. Same values as for
wrapS
.
map_to_meshes module¶
This module is an extension of the svg_to_mesh
module and ist main class, SvgToMesh
for more specific purposes. This means the former is dedicated to generically read Inkscape files and convert elements to meshes, while the specialized classes here are dedicated to building catacombs maps.
CataSvgToMesh
wiil build 3D maps meshes and objects
CataMapTo2DMap
will build “cleaner” 2D maps (with some symbols replaced and enlarged, regions zooms and more, and export PDF and JPG versions.
map_to_meshes module API¶
- class catamap.map_to_meshes.CataMapTo2DMap(concat_mesh='bygroup')[source]¶
Process XML tree to build modified 2D maps
- Parameters:
concat_mesh (str) –
concatenation method between multiple paths in SVG file. ‘merge’: merge all paths in a single mesh ‘time’: use mesh timestep to store each path ‘list’: return a list of meshes ‘bygroup’ (default): return a dict of meshes, one for each main
group, paths are concatenated inside each group
- static box_in_region(box, region, bbox, verbose=False)[source]¶
check if a box is totally inside a region, or totally outside, or intersecting
Warning: if 4 corners are inside, the test says inside, whereas it is not always true for a non-convex clip polygon
- Returns:
1 (inside)
0 (intersecting)
-1 (outside)
- class catamap.map_to_meshes.CataSvgToMesh(concat_mesh='list_bygroup', skull_mesh=None, headless=True)[source]¶
Process XML tree to build 3D meshes
- Parameters:
concat_mesh (str) –
concatenation method between multiple paths in SVG file. ‘merge’: merge all paths in a single mesh ‘time’: use mesh timestep to store each path ‘list’: return a list of meshes ‘bygroup’ (default): return a dict of meshes, one for each main
group, paths are concatenated inside each group
- extrude(mesh, distance, height_map=None)[source]¶
This is an overloaded version of the static SvgToMesh.extrude(mesh, distance)
When height_map is given, use this level height map to shift Z positions
- filter_element(xml_element, style=None)[source]¶
Assign a processing function / method to the given element, a cleaning function to be called after the associated sub-tree is processed, and a bool to tell if children should be skipped. This method can be overloaded and is called for each XML tree element. The default implementation returns None, which means that there is no specific processing and the default behavior should happen.
- Returns:
proc – proc_callable and clean_callable may be None, meaning that normal processing should happen. The processing callable will be called with 3 arguments: (xml_element, transform_matrix, style_dict). The cleaning callable will be called without arguments. if skip_children is True, children are skipped.
- Return type:
(proc_callable, clean_callable, skip_children) or None
- get_alt_colors(props, colorset=None, conv=True)[source]¶
Get backgroud, foreground colors (fill/border)
- load_ground_altitude_bdalti(filename)[source]¶
- filename:
json map, to be used with the API module bdalti.py
- make_ps_well(center, radius, z, height, well_type, props, faces=8, smooth=True, rotate=0.0)[source]¶
PS or PE (blue), P ossements (yellow)
- read_path(xml_path, trans, style=None)[source]¶
Read a path element as mesh, apply coords transformations
- read_paths(xml)[source]¶
Parse XML tree and extract meshes, text and other objects
- Parameters:
xml_et (XML tree) – obtained using xml.etree.cElementTree.parse(svg_filename)
- save_mesh_dict(meshes, dirname, mesh_format='.glb', mesh_wf_format='.glb', json_filename=None, map2d_filename=None)[source]¶
mesh_format may be a valid mesh extension (“.obj”, “.gii”, “.mesh”) or GLTF (“.gltf” or “.glb”), or None (not saved here).
If GLTF is used a scene dict (JSON) is returned in the output summary under the key “gltf_scene”.
- class catamap.map_to_meshes.DefaultItemProperties[source]¶
Defaults and constant values.
This is mainly a remaining of the v1 of the software, where fewer things were indicated in the SVG file, and the program was written originally for a single map (GRS, Paris 14e) with hard-coded labels.
- class catamap.map_to_meshes.ItemProperties[source]¶
XML item properties structure, used by
CataSvgToMesh
. They represent properties read from the XML file elements.Properties match those documented in Inkscape SVG files, except the
height
property which is nameditem_height
in XML file elements (becauseheight
is already used in SVG).
- catamap.map_to_meshes.scale_georef_points_file(in_filename, out_filename, scale_factor_x, scale_factor_y=None)[source]¶
Rescale source positions in a QGis .points file in order to adapt to a different resolution
svg_to_mesh module¶
This modules allows to read an Inkscape SVG file, parse its elements, and convert them to 3D meshes.
svg_to_mesh module API¶
- class catamap.svg_to_mesh.SvgToMesh(concat_mesh='bygroup')[source]¶
Read SVG, transforms things into meshes
- Parameters:
concat_mesh (str) –
concatenation method between multiple paths in SVG file. ‘merge’: merge all paths in a single mesh ‘time’: use mesh timestep to store each path ‘list’: return a list of meshes ‘bygroup’ (default): return a dict of meshes, one for each main
group, paths are concatenated inside each group
- filter_element(style=None)[source]¶
Assign a processing function / method to the given element, a cleaning function to be called after the associated sub-tree is processed, and a bool to tell if children should be skipped. This method can be overloaded and is called for each XML tree element. The default implementation returns None, which means that there is no specific processing and the default behavior should happen.
- Returns:
proc – proc_callable and clean_callable may be None, meaning that normal processing should happen. The processing callable will be called with 3 arguments: (xml_element, transform_matrix, style_dict). The cleaning callable will be called without arguments. if skip_children is True, children are skipped.
- Return type:
(proc_callable, clean_callable, skip_children) or None
- get_transform(trans, previous=None, no_3d=False)[source]¶
- Parameters:
trans (str or XML element) – if str: transform field in the SVG element. if element: XML element itself
previous (np array or None) – parent transform to be composed with
- read_path(xml_path, trans, style=None)[source]¶
Read a path element as mesh, apply coords transformations
- read_paths(xml_et)[source]¶
Parse XML tree and extract meshes, text and other objects
- Parameters:
xml_et (XML tree) – obtained using xml.etree.cElementTree.parse(svg_filename)
- replace_filter_element(xml)[source]¶
Inside replace_elements, this function is called for each xml element, and should return either the element itself (no replacement), or None (element is discarded), or a replaced XML element.
The default method always returns the input element.
- save_mesh_dict(meshes, dirname, mesh_format='.obj', mesh_wf_format='.obj', lights=None)[source]¶
mesh_format may be a valid mesh extension (“.obj”, “.gii”, “.mesh”) or GLTF (“.gltf” or “.glb”), or None (not saved here).
If GLTF is used a scene dict (JSON) is returned in the output summary under the key “gltf_scene”.
diff_svg module¶
Print differences between two SVG maps.
Uses the yaml module (pip install pyyaml
).
The output is a hierarchical dictionary of differences between the two maps. Differences in tags (properties) and children are recorded. Item keys are their “id” property, which should be unique in the files, and are displayed hierarchically.
Used as a program, the output is in YAML format (mostly human readable)
To use it, try:
python -m catamap.diff_svg --h
It will print the command doc and parameters.
diff_svg module API¶
- catamap.diff_svg.diff_element(el1, el2, verbose_depth=0, verbose_depth_max=1)[source]¶
Compare two SVG XML trees, record differences in both properties and children in a readable dictionary.
BDAlti maps module¶
Convertion tools for BDAlti maps (https://geoservices.ign.fr/documentation/diffusion/telechargement-donnees-libres.html#bd-alti) and their use in catamap
.
API¶
- catamap.altitude.bdalti.build_meta_table(ima_fnames)[source]¶
build the metadata table from converted .ima files
ima_fnames: pattern with a “%s”, same as out_fnames in convert_raw_maps()
- catamap.altitude.bdalti.convert_raw_map(fname, out_fname)[source]¶
convert one raw map from bdalti (.asc) to .ima format
- catamap.altitude.bdalti.convert_raw_maps(fnames, out_fnames)[source]¶
convert all raw data files from bdalti (.asc) to .ima format
- fnames:
input files pattern (used with glob.glob())
- out_fnames:
output files pattern, should contain a “%s” pattern