proj/scripts/create_c_api_projections.py

187 строки
8.0 KiB
Python
Исполняемый файл

#!/usr/bin/env python
###############################################################################
# $Id$
#
# Project: PROJ
# Purpose: Parse XML output of Doxygen on coordinateoperation.hpp to creat
# C API for projections.
# Author: Even Rouault <even.rouault at spatialys.com>
#
###############################################################################
# Copyright (c) 2018, Even Rouault <even.rouault at spatialys.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
###############################################################################
from lxml import etree
import os
script_dir_name = os.path.dirname(os.path.realpath(__file__))
# Make sure to run doxygen
if not 'SKIP_DOXYGEN' in os.environ:
os.system("bash " + os.path.join(script_dir_name, "doxygen.sh"))
xmlfilename = os.path.join(os.path.dirname(script_dir_name),
'docs/build/xml/classosgeo_1_1proj_1_1operation_1_1Conversion.xml')
tree = etree.parse(open(xmlfilename, 'rt'))
root = tree.getroot()
compounddef = root.find('compounddef')
header = open('projections.h', 'wt')
cppfile = open('projections.cpp', 'wt')
test_cppfile = open('test_projections.cpp', 'wt')
header.write("/* BEGIN: Generated by scripts/create_c_api_projections.py*/\n")
cppfile.write("/* BEGIN: Generated by scripts/create_c_api_projections.py*/\n")
cppfile.write("\n");
test_cppfile.write("/* BEGIN: Generated by scripts/create_c_api_projections.py*/\n")
def snake_casify(s):
out = ''
lastWasLowerAlpha = False
for c in s:
if c.isupper():
if lastWasLowerAlpha:
out += '_'
out += c.lower()
lastWasLowerAlpha = False
else:
out += c
lastWasLowerAlpha = c.isalpha()
return out
for sectiondef in compounddef.iter('sectiondef'):
if sectiondef.attrib['kind'] == 'public-static-func':
for func in sectiondef.iter('memberdef'):
name = func.find('name').text
assert name.startswith('create')
if name in ('create', 'createChangeVerticalUnit',
'createAxisOrderReversal', 'createGeographicGeocentric'):
continue
params = []
has_angle = False
has_linear = False
for param in func.iter('param'):
type = param.find('type').xpath("normalize-space()")
if type.find('Angle') >= 0:
has_angle = True
if type.find('Length') >= 0:
has_linear = True
paramname = param.find('declname').text
if paramname == 'properties':
continue
params.append((type, snake_casify(paramname)))
shortName = name[len('create'):]
c_shortName = snake_casify(shortName)
decl = "proj_create_conversion_"
decl += c_shortName
decl += "(\n"
decl += " PJ_CONTEXT *ctx,\n"
has_output_params = False
for param in params:
if has_output_params:
decl += ",\n"
if param[0] in ('int', 'bool'):
decl += " int " + param[1]
else:
decl += " double " + param[1]
has_output_params = True
if has_angle:
if has_output_params:
decl += ",\n"
decl += " const char* ang_unit_name, double ang_unit_conv_factor"
has_output_params = True
if has_linear:
if has_output_params:
decl += ",\n"
decl += " const char* linear_unit_name, double linear_unit_conv_factor"
decl += ")"
header.write("PJ PROJ_DLL *" + decl + ";\n\n")
briefdescription = func.find('briefdescription/para').xpath("normalize-space()")
briefdescription = briefdescription.replace("Instanciate ", "Instanciate a ProjectedCRS with ")
cppfile.write("// ---------------------------------------------------------------------------\n\n")
cppfile.write("/** \\brief " + briefdescription + "\n")
cppfile.write(" *\n")
cppfile.write(" * See osgeo::proj::operation::Conversion::create" + shortName + "().\n")
cppfile.write(" *\n")
cppfile.write(" * Linear parameters are expressed in (linear_unit_name, linear_unit_conv_factor).\n")
if has_angle:
cppfile.write(" * Angular parameters are expressed in (ang_unit_name, ang_unit_conv_factor).\n")
cppfile.write(" */\n")
cppfile.write("PJ* " + decl + "{\n");
cppfile.write(" SANITIZE_CTX(ctx);\n");
cppfile.write(" try {\n");
if has_linear:
cppfile.write(" UnitOfMeasure linearUnit(createLinearUnit(linear_unit_name, linear_unit_conv_factor));\n")
if has_angle:
cppfile.write(" UnitOfMeasure angUnit(createAngularUnit(ang_unit_name, ang_unit_conv_factor));\n")
cppfile.write(" auto conv = Conversion::create" + shortName + "(PropertyMap()")
for param in params:
if param[0] in 'int':
cppfile.write(", " + param[1])
elif param[0] in 'bool':
cppfile.write(", " + param[1] + " != 0")
elif param[0].find('Angle') >= 0:
cppfile.write(", Angle(" + param[1] + ", angUnit)")
elif param[0].find('Length') >= 0:
cppfile.write(", Length(" + param[1] + ", linearUnit)")
elif param[0].find('Scale') >= 0:
cppfile.write(", Scale(" + param[1] + ")")
cppfile.write(");\n")
cppfile.write(" return proj_create_conversion(ctx, conv);\n")
cppfile.write(" } catch (const std::exception &e) {\n");
cppfile.write(" proj_log_error(ctx, __FUNCTION__, e.what());\n")
cppfile.write(" }\n")
cppfile.write(" return nullptr;\n")
cppfile.write("}\n")
test_cppfile.write("{\n")
test_cppfile.write(" auto projCRS = proj_create_conversion_" + c_shortName + "(\n")
test_cppfile.write(" m_ctxt")
for param in params:
test_cppfile.write(", 0")
if has_angle:
test_cppfile.write(", \"Degree\", 0.0174532925199433")
if has_linear:
test_cppfile.write(", \"Metre\", 1.0")
test_cppfile.write(");\n")
test_cppfile.write(" ObjectKeeper keeper_projCRS(projCRS);\n")
test_cppfile.write(" ASSERT_NE(projCRS, nullptr);\n")
test_cppfile.write("}\n")
header.write("/* END: Generated by scripts/create_c_api_projections.py*/\n")
cppfile.write("/* END: Generated by scripts/create_c_api_projections.py*/\n")
test_cppfile.write("/* END: Generated by scripts/create_c_api_projections.py*/\n")
print('projections.h and .cpp, and test_projections.cpp have been generated. Manually merge them now')