draw.py use settings instead of direct member methods

This commit is contained in:
Thomas Krijnen
2026-05-09 21:19:55 +02:00
parent da5ebf172e
commit c3a10694ba
3 changed files with 106 additions and 35 deletions
+34
View File
@@ -141,6 +141,12 @@ inline namespace settings {
static constexpr const char* const description = "Draws a horizontal line at the height of building storeys in vertical drawings. Accepted values are none, full, and left."; static constexpr const char* const description = "Draws a horizontal line at the height of building storeys in vertical drawings. Accepted values are none, full, and left.";
}; };
struct SvgProfileThreshold : public SettingBase<SvgProfileThreshold, int> {
static constexpr const char* const name = "profile-threshold";
static constexpr const char* const description = "Limits the number of projected wire profiles for non-wall and non-slab elements in SVG output. A negative value disables the limit.";
static constexpr int defaultvalue = -1;
};
struct SvgStoreyHeightLineLength : public SettingBase<SvgStoreyHeightLineLength, double> { struct SvgStoreyHeightLineLength : public SettingBase<SvgStoreyHeightLineLength, double> {
static constexpr const char* const name = "storey-height-line-length"; static constexpr const char* const name = "storey-height-line-length";
static constexpr const char* const description = "Length of the line when --draw-storey-heights=left."; static constexpr const char* const description = "Length of the line when --draw-storey-heights=left.";
@@ -164,12 +170,23 @@ inline namespace settings {
static constexpr bool defaultvalue = false; static constexpr bool defaultvalue = false;
}; };
struct SvgUnifyInputs : public SettingBase<SvgUnifyInputs, bool> {
static constexpr const char* const name = "svg-unify-inputs";
static constexpr const char* const description = "Unify input shapes before SVG projection.";
static constexpr bool defaultvalue = false;
};
struct SvgSegmentProjection : public SettingBase<SvgSegmentProjection, bool> { struct SvgSegmentProjection : public SettingBase<SvgSegmentProjection, bool> {
static constexpr const char* const name = "svg-segment-projection"; static constexpr const char* const name = "svg-segment-projection";
static constexpr const char* const description = "Segment result of projection with respect to original products."; static constexpr const char* const description = "Segment result of projection with respect to original products.";
static constexpr bool defaultvalue = false; static constexpr bool defaultvalue = false;
}; };
struct SvgSubtractBefore : public SettingBase<SvgSubtractBefore, std::string> {
static constexpr const char* const name = "svg-subtract-before";
static constexpr const char* const description = "Controls which shapes are cut before SVG hidden-line projection. Accepted values are auto, slabs-and-walls, and always.";
};
struct SvgPolygonal : public SettingBase<SvgPolygonal, bool> { struct SvgPolygonal : public SettingBase<SvgPolygonal, bool> {
static constexpr const char* const name = "svg-write-poly"; static constexpr const char* const name = "svg-write-poly";
static constexpr const char* const description = "Approximate every curve as polygonal in SVG output."; static constexpr const char* const description = "Approximate every curve as polygonal in SVG output.";
@@ -194,6 +211,18 @@ inline namespace settings {
static constexpr bool defaultvalue = false; static constexpr bool defaultvalue = false;
}; };
struct SvgMirrorY : public SettingBase<SvgMirrorY, bool> {
static constexpr const char* const name = "svg-mirror-y";
static constexpr const char* const description = "Mirror SVG output along the Y axis.";
static constexpr bool defaultvalue = false;
};
struct SvgMirrorX : public SettingBase<SvgMirrorX, bool> {
static constexpr const char* const name = "svg-mirror-x";
static constexpr const char* const description = "Mirror SVG output along the X axis.";
static constexpr bool defaultvalue = false;
};
struct SvgDoorArcs : public SettingBase<SvgDoorArcs, bool> { struct SvgDoorArcs : public SettingBase<SvgDoorArcs, bool> {
static constexpr const char* const name = "door-arcs"; static constexpr const char* const name = "door-arcs";
static constexpr const char* const description = "Draw door opening arcs for IfcDoor elements."; static constexpr const char* const description = "Draw door opening arcs for IfcDoor elements.";
@@ -251,15 +280,20 @@ class SerializerSettings : public SettingsContainer <
SvgAutoSection, SvgAutoSection,
SvgAutoElevation, SvgAutoElevation,
SvgDrawStoreyHeights, SvgDrawStoreyHeights,
SvgProfileThreshold,
SvgStoreyHeightLineLength, SvgStoreyHeightLineLength,
SvgUseNamespace, SvgUseNamespace,
SvgUseHlrPoly, SvgUseHlrPoly,
SvgUsePrefiltering, SvgUsePrefiltering,
SvgUnifyInputs,
SvgSegmentProjection, SvgSegmentProjection,
SvgSubtractBefore,
SvgPolygonal, SvgPolygonal,
SvgAlwaysProject, SvgAlwaysProject,
SvgWithoutStoreys, SvgWithoutStoreys,
SvgNoCss, SvgNoCss,
SvgMirrorY,
SvgMirrorX,
SvgDoorArcs, SvgDoorArcs,
SvgSectionHeight, SvgSectionHeight,
SvgSectionHeightFromStoreys, SvgSectionHeightFromStoreys,
+27 -30
View File
@@ -159,52 +159,49 @@ def main(
# Initialize serializer # Initialize serializer
buffer = ifcopenshell.geom.serializers.buffer() buffer = ifcopenshell.geom.serializers.buffer()
serialiser_settings = ifcopenshell.geom.serializer_settings() serialiser_settings = ifcopenshell.geom.serializer_settings()
sr = ifcopenshell.geom.serializers.svg(buffer, geom_settings, serialiser_settings)
sr.setFile(files[0])
if settings.auto_floorplan: if settings.auto_floorplan:
sr.setSectionHeightsFromStoreys() serialiser_settings.set("section-height-from-storeys", True)
# setElevationRefGuid and setElevationRef are also mutually exclusive in C-code. # elevation-ref-guid and elevation-ref are also mutually exclusive in C-code.
# Note that guid or object type are not checked anywhere to be valid, # Note that guid or object type are not checked anywhere to be valid,
# it's up to user to keep them valid for the provided projects. # it's up to user to keep them valid for the provided projects.
if settings.drawing_guid or settings.drawing_object_type: if settings.drawing_guid or settings.drawing_object_type:
if settings.drawing_guid: if settings.drawing_guid:
if not by_guid(settings.drawing_guid): if not by_guid(settings.drawing_guid):
raise ValueError(f"Unable to find guid {settings.drawing_guid!r}") raise ValueError(f"Unable to find guid {settings.drawing_guid!r}")
sr.setElevationRefGuid(settings.drawing_guid) serialiser_settings.set("elevation-ref-guid", settings.drawing_guid)
elif settings.drawing_object_type: elif settings.drawing_object_type:
sr.setElevationRef(settings.drawing_object_type) serialiser_settings.set("elevation-ref", settings.drawing_object_type)
sr.setWithoutStoreys(True) serialiser_settings.set("svg-without-storeys", True)
# required for svgfill # required for svgfill
sr.setPolygonal(True) serialiser_settings.set("svg-write-poly", True)
sr.setUseNamespace(True) serialiser_settings.set("svg-xmlns", True)
sr.setAlwaysProject(settings.include_projection) serialiser_settings.set("svg-project", settings.include_projection)
serialiser_settings.set("profile-threshold", settings.profile_threshold)
sr.setProfileThreshold(settings.profile_threshold) serialiser_settings.set("bounds", f"{settings.width}x{settings.height}")
sr.setBoundingRectangle(settings.width, settings.height) serialiser_settings.set("scale", str(settings.scale))
sr.setScale(settings.scale) serialiser_settings.set("auto-elevation", settings.auto_elevation)
sr.setAutoElevation(settings.auto_elevation) serialiser_settings.set("auto-section", settings.auto_section)
sr.setAutoSection(settings.auto_section) serialiser_settings.set("print-space-names", settings.space_names)
sr.setPrintSpaceNames(settings.space_names) serialiser_settings.set("print-space-areas", settings.space_areas)
sr.setPrintSpaceAreas(settings.space_areas) serialiser_settings.set("door-arcs", settings.door_arcs)
sr.setDrawDoorArcs(settings.door_arcs) serialiser_settings.set("svg-no-css", bool(settings.css))
sr.setNoCSS(not not settings.css)
if settings.subtract_before_hlr: if settings.subtract_before_hlr:
sr.setSubtractionSettings(W.ALWAYS) serialiser_settings.set("svg-subtract-before", "always")
sr.setUseHlrPoly(settings.hlr_poly) serialiser_settings.set("svg-poly", settings.hlr_poly)
sr.setUsePrefiltering(settings.prefilter) serialiser_settings.set("svg-prefilter", settings.prefilter)
sr.setUnifyInputs(settings.unify_inputs) serialiser_settings.set("svg-unify-inputs", settings.unify_inputs)
sr.setMirrorY(settings.mirror_y) serialiser_settings.set("svg-mirror-y", settings.mirror_y)
try: if settings.storey_heights not in {"none", "full", "left"}:
sh = ["none", "full", "left"].index(settings.storey_heights)
sr.setDrawStoreyHeights(sh)
except:
raise ValueError("storey_heights should be one of {'none', 'full', 'left'}") raise ValueError("storey_heights should be one of {'none', 'full', 'left'}")
serialiser_settings.set("draw-storey-heights", settings.storey_heights)
sr = ifcopenshell.geom.serializers.svg(buffer, geom_settings, serialiser_settings)
sr.setFile(files[0])
""" """
# It is also possible to add drawing planes manually # It is also possible to add drawing planes manually
+45 -5
View File
@@ -97,10 +97,10 @@ namespace {
const double PI2 = M_PI * 2.; const double PI2 = M_PI * 2.;
std::pair<double, double> parse_svg_bounds(const std::string& value) { std::pair<double, double> parse_svg_bounds(const std::string& value) {
unsigned int width = 0; double width = 0.;
unsigned int height = 0; double height = 0.;
if (std::sscanf(value.c_str(), "%ux%u", &width, &height) == 2 && width > 0 && height > 0) { if (std::sscanf(value.c_str(), "%lfx%lf", &width, &height) == 2 && width > 0. && height > 0.) {
return { static_cast<double>(width), static_cast<double>(height) }; return { width, height };
} }
throw std::runtime_error("Invalid use of --bounds"); throw std::runtime_error("Invalid use of --bounds");
} }
@@ -123,9 +123,27 @@ double parse_svg_scale(const std::string& value) {
numerator > 0 && denominator > 0) { numerator > 0 && denominator > 0) {
return static_cast<double>(numerator) / denominator; return static_cast<double>(numerator) / denominator;
} }
double scale = 0.;
if (std::sscanf(value.c_str(), "%lf", &scale) == 1 && scale > 0.) {
return scale;
}
throw std::runtime_error("Invalid use of --scale"); throw std::runtime_error("Invalid use of --scale");
} }
subtract_before_project parse_subtract_before_project(const std::string& value) {
const auto setting = boost::to_lower_copy(value);
if (setting == "auto" || setting == "slabs-at-floorplans" || setting == "slabs-at-floor-plans") {
return ON_SLABS_AT_FLOORPLANS;
}
if (setting == "slabs-and-walls") {
return ON_SLABS_AND_WALLS;
}
if (setting == "always") {
return ALWAYS;
}
throw std::runtime_error("Invalid use of --svg-subtract-before, expected auto|slabs-and-walls|always");
}
SvgSerializer::storey_height_display_types parse_storey_height_display(const std::string& value) { SvgSerializer::storey_height_display_types parse_storey_height_display(const std::string& value) {
const auto display = boost::to_lower_copy(value); const auto display = boost::to_lower_copy(value);
if (display == "none") { if (display == "none") {
@@ -163,7 +181,7 @@ void SvgSerializer::apply_settings() {
setDrawingCenter(center.first, center.second); setDrawingCenter(center.first, center.second);
} }
if (settings().get<SvgSectionHeightFromStoreys>().get()) { if (settings().get<SvgSectionHeightFromStoreys>().get() && file) {
if (settings().get<SvgSectionHeight>().has()) { if (settings().get<SvgSectionHeight>().has()) {
setSectionHeightsFromStoreys(settings().get<SvgSectionHeight>().get()); setSectionHeightsFromStoreys(settings().get<SvgSectionHeight>().get());
} else { } else {
@@ -181,11 +199,19 @@ void SvgSerializer::apply_settings() {
setUseNamespace(settings().get<SvgUseNamespace>().get()); setUseNamespace(settings().get<SvgUseNamespace>().get());
setUseHlrPoly(settings().get<SvgUseHlrPoly>().get()); setUseHlrPoly(settings().get<SvgUseHlrPoly>().get());
setUsePrefiltering(settings().get<SvgUsePrefiltering>().get()); setUsePrefiltering(settings().get<SvgUsePrefiltering>().get());
setUnifyInputs(settings().get<SvgUnifyInputs>().get());
setSegmentProjection(settings().get<SvgSegmentProjection>().get()); setSegmentProjection(settings().get<SvgSegmentProjection>().get());
setPolygonal(settings().get<SvgPolygonal>().get()); setPolygonal(settings().get<SvgPolygonal>().get());
setAlwaysProject(settings().get<SvgAlwaysProject>().get()); setAlwaysProject(settings().get<SvgAlwaysProject>().get());
setWithoutStoreys(settings().get<SvgWithoutStoreys>().get()); setWithoutStoreys(settings().get<SvgWithoutStoreys>().get());
setNoCSS(settings().get<SvgNoCss>().get()); setNoCSS(settings().get<SvgNoCss>().get());
setMirrorY(settings().get<SvgMirrorY>().get());
setMirrorX(settings().get<SvgMirrorX>().get());
setProfileThreshold(settings().get<SvgProfileThreshold>().get());
if (settings().get<SvgSubtractBefore>().has()) {
setSubtractionSettings(parse_subtract_before_project(settings().get<SvgSubtractBefore>().get()));
}
if (settings().get<SvgDrawStoreyHeights>().has()) { if (settings().get<SvgDrawStoreyHeights>().has()) {
setDrawStoreyHeights(parse_storey_height_display(settings().get<SvgDrawStoreyHeights>().get())); setDrawStoreyHeights(parse_storey_height_display(settings().get<SvgDrawStoreyHeights>().get()));
@@ -2425,7 +2451,18 @@ std::string SvgSerializer::nameElement(express::Base elem_) {
} }
void SvgSerializer::setFile(ifcopenshell::file* f) { void SvgSerializer::setFile(ifcopenshell::file* f) {
using namespace ifcopenshell::geometry::settings;
file = f; file = f;
auto apply_section_heights_from_storeys = [&]() {
if (settings().get<SvgSectionHeightFromStoreys>().get()) {
if (settings().get<SvgSectionHeight>().has()) {
setSectionHeightsFromStoreys(settings().get<SvgSectionHeight>().get());
} else {
setSectionHeightsFromStoreys();
}
}
};
auto storeys = f->instances_by_type("IfcBuildingStorey"); auto storeys = f->instances_by_type("IfcBuildingStorey");
if (storeys.empty()) { if (storeys.empty()) {
@@ -2449,6 +2486,7 @@ void SvgSerializer::setFile(ifcopenshell::file* f) {
delete matrix; delete matrix;
#endif #endif
logger::warning("No building storeys encountered, used for reference:", product); logger::warning("No building storeys encountered, used for reference:", product);
apply_section_heights_from_storeys();
return; return;
} }
} }
@@ -2459,6 +2497,8 @@ void SvgSerializer::setFile(ifcopenshell::file* f) {
logger::warning("No building storeys encountered, output might be invalid or missing"); logger::warning("No building storeys encountered, output might be invalid or missing");
} }
apply_section_heights_from_storeys();
} }
void SvgSerializer::setSectionHeight(double h, express::Base storey) { void SvgSerializer::setSectionHeight(double h, express::Base storey) {