DLR-SC / tigl

@@ -0,0 +1,85 @@
Loading
1 +
/*
2 +
* Copyright (C) 2020 German Aerospace Center (DLR/SC)
3 +
*
4 +
* Created: 2020-09-10 Martin Siggel <Martin.Siggel@dlr.de>
5 +
*
6 +
* Licensed under the Apache License, Version 2.0 (the "License");
7 +
* you may not use this file except in compliance with the License.
8 +
* You may obtain a copy of the License at
9 +
*
10 +
*     http://www.apache.org/licenses/LICENSE-2.0
11 +
*
12 +
* Unless required by applicable law or agreed to in writing, software
13 +
* distributed under the License is distributed on an "AS IS" BASIS,
14 +
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 +
* See the License for the specific language governing permissions and
16 +
* limitations under the License.
17 +
*/
18 +
19 +
#include "CTiglConcatSurfaces.h"
20 +
21 +
#include <CTiglBSplineAlgorithms.h>
22 +
#include <CTiglError.h>
23 +
24 +
#include <algorithm>
25 +
26 +
namespace tigl
27 +
{
28 +
29 +
CTiglConcatSurfaces::CTiglConcatSurfaces(const std::vector<Handle(Geom_BSplineSurface)>& surfaces,
30 +
                                         const std::vector<double>& surfaceParams, ConcatDir dir)
31 +
    : m_surfaces(surfaces)
32 +
    , m_params(surfaceParams)
33 +
    , m_dir(dir)
34 +
{
35 +
36 +
    if (surfaces.size() + 1 != surfaceParams.size()) {
37 +
        throw CTiglError("Surfaces dont match parameters: Number of parameters != number of surfaces + 1");
38 +
    }
39 +
40 +
    if (dir ==ConcatDir::v) {
41 +
        throw CTiglError("CTiglConcatSurfaces in v-direction not yet implemented");
42 +
    }
43 +
44 +
    std::sort(m_params.begin(), m_params.end());
45 +
}
46 +
47 +
void CTiglConcatSurfaces::SetMakeKnotsUniformEnabled(unsigned int nUSeg, unsigned int nVSeg)
48 +
{
49 +
    if (nUSeg > 0 && nVSeg > 0) {
50 +
        m_approxSegments.reset({nUSeg, nVSeg});
51 +
    }
52 +
    else {
53 +
        m_approxSegments.reset();
54 +
    }
55 +
}
56 +
57 +
Handle(Geom_BSplineSurface) CTiglConcatSurfaces::Surface() const
58 +
{
59 +
    // create a copy of all surfaces
60 +
    std::vector<Handle(Geom_BSplineSurface)> surfaces;
61 +
    std::transform(std::begin(m_surfaces), std::end(m_surfaces), std::back_inserter(surfaces),
62 +
                   [](const Handle(Geom_BSplineSurface) & surf) {
63 +
                       return Handle(Geom_BSplineSurface)::DownCast(surf->Copy());
64 +
                   });
65 +
66 +
    if (m_approxSegments) {
67 +
        std::transform(
68 +
            std::begin(surfaces), std::end(surfaces), std::begin(surfaces), [this](Handle(Geom_BSplineSurface) & surf) {
69 +
                return CTiglBSplineAlgorithms::makeKnotsUniform(surf, m_approxSegments->nu, m_approxSegments->nv);
70 +
            });
71 +
    }
72 +
73 +
    for (size_t surfIdx = 0; surfIdx < surfaces.size(); ++surfIdx) {
74 +
        CTiglBSplineAlgorithms::reparametrizeBSpline(*surfaces[surfIdx], m_params[surfIdx], m_params[surfIdx + 1], 0.,
75 +
                                                     1., 1e-10);
76 +
    }
77 +
78 +
    for (size_t surfIdx = 1; surfIdx < surfaces.size(); ++surfIdx) {
79 +
        surfaces[0] = CTiglBSplineAlgorithms::concatSurfacesUDir(surfaces[0], surfaces[surfIdx]);
80 +
    }
81 +
82 +
    return surfaces[0];
83 +
}
84 +
85 +
} // namespace tigl

@@ -25,6 +25,7 @@
Loading
25 25
#include "CTiglPointsToBSplineInterpolation.h"
26 26
#include "to_string.h"
27 27
#include "tiglcommonfunctions.h"
28 +
#include "Debugging.h"
28 29
29 30
#include <Standard_Version.hxx>
30 31
#include <Geom2d_BSplineCurve.hxx>
@@ -534,24 +535,24 @@
Loading
534 535
    return std::vector<Handle(Geom_BSplineCurve)>(splines_adapter.begin(), splines_adapter.end());
535 536
}
536 537
537 -
std::vector<Handle(Geom_BSplineSurface) > CTiglBSplineAlgorithms::createCommonKnotsVectorSurface(const std::vector<Handle(Geom_BSplineSurface) >& old_surfaces_vector)
538 +
std::vector<Handle(Geom_BSplineSurface) > CTiglBSplineAlgorithms::createCommonKnotsVectorSurface(const std::vector<Handle(Geom_BSplineSurface) >& old_surfaces_vector, SurfaceDirection dir)
538 539
{
539 -
    // all B-spline surfaces must have the same parameter range in u- and v-direction
540 -
    // TODO: Match parameter range
541 -
542 540
    // Create a copy that we can modify
543 541
    std::vector<SurfAdapterView> adapterSplines;
544 542
    for (size_t i = 0; i < old_surfaces_vector.size(); ++i) {
545 543
        adapterSplines.push_back(SurfAdapterView(Handle(Geom_BSplineSurface)::DownCast(old_surfaces_vector[i]->Copy()), udir));
546 544
    }
547 545
548 -
    // first in u direction
549 -
    makeGeometryCompatibleImpl(adapterSplines, 1e-15);
550 -
551 -
    for (size_t i = 0; i < old_surfaces_vector.size(); ++i) adapterSplines[i].setDir(vdir);
546 +
    if (dir == SurfaceDirection::u || dir == SurfaceDirection::both) {
547 +
        // first in u direction
548 +
        makeGeometryCompatibleImpl(adapterSplines, 1e-14);
549 +
    }
552 550
553 -
    // now in v direction
554 -
    makeGeometryCompatibleImpl(adapterSplines, 1e-15);
551 +
    if (dir == SurfaceDirection::v || dir == SurfaceDirection::both) {
552 +
         // now in v direction
553 +
        for (size_t i = 0; i < old_surfaces_vector.size(); ++i) adapterSplines[i].setDir(vdir);
554 +
        makeGeometryCompatibleImpl(adapterSplines, 1e-14);
555 +
    }
555 556
556 557
    return std::vector<Handle(Geom_BSplineSurface)>(adapterSplines.begin(), adapterSplines.end());
557 558
}
@@ -818,6 +819,23 @@
Loading
818 819
    }
819 820
}
820 821
822 +
void CTiglBSplineAlgorithms::reparametrizeBSpline(Geom_BSplineSurface& spline, double umin, double umax, double vmin, double vmax, double tol)
823 +
{
824 +
    if (std::abs(spline.UKnot(1) - umin) > tol || std::abs(spline.UKnot(spline.NbUKnots()) - umax) > tol) {
825 +
        TColStd_Array1OfReal aKnots (1, spline.NbUKnots());
826 +
        spline.UKnots (aKnots);
827 +
        BSplCLib::Reparametrize (umin, umax, aKnots);
828 +
        spline.SetUKnots (aKnots);
829 +
    }
830 +
831 +
    if (std::abs(spline.VKnot(1) - vmin) > tol || std::abs(spline.VKnot(spline.NbVKnots()) - vmax) > tol) {
832 +
        TColStd_Array1OfReal aKnots (1, spline.NbVKnots());
833 +
        spline.VKnots (aKnots);
834 +
        BSplCLib::Reparametrize (vmin, vmax, aKnots);
835 +
        spline.SetVKnots (aKnots);
836 +
    }
837 +
}
838 +
821 839
CTiglApproxResult CTiglBSplineAlgorithms::reparametrizeBSplineNiceKnots(Handle(Geom_BSplineCurve) spline)
822 840
{
823 841
    if (spline.IsNull()) {
@@ -1139,4 +1157,140 @@
Loading
1139 1157
    return result;
1140 1158
}
1141 1159
1160 +
Handle(Geom_BSplineSurface) CTiglBSplineAlgorithms::concatSurfacesUDir(Handle(Geom_BSplineSurface) bspl1,
1161 +
                                                                       Handle(Geom_BSplineSurface) bspl2,
1162 +
                                                                       double space_tol)
1163 +
{
1164 +
1165 +
    DEBUG_SCOPE(debug);
1166 +
    debug.addShape(BRepBuilderAPI_MakeFace(bspl1, 1e-6).Face(), "surf1");
1167 +
    debug.addShape(BRepBuilderAPI_MakeFace(bspl2, 1e-6).Face(), "surf2");
1168 +
1169 +
    // the surfaces must not be periodic in u direction
1170 +
    assert (bspl1->IsUPeriodic() == false);
1171 +
    assert (bspl2->IsUPeriodic() == false);
1172 +
1173 +
    // we dont have nurbs implemented right now
1174 +
    assert (bspl1->IsURational() == false);
1175 +
    assert (bspl2->IsURational() == false);
1176 +
    assert (bspl1->IsVRational() == false);
1177 +
    assert (bspl2->IsVRational() == false);
1178 +
1179 +
    double param_tol = 1e-14;
1180 +
1181 +
    // check that surfaces are following parametrically
1182 +
    double umin1, umax1, vmin1, vmax1;
1183 +
    bspl1->Bounds(umin1, umax1, vmin1, vmax1);
1184 +
    double umin2, umax2, vmin2, vmax2;
1185 +
    bspl2->Bounds(umin2, umax2, vmin2, vmax2);
1186 +
1187 +
    if (std::abs(umax1 - umin2) > param_tol) {
1188 +
        std::stringstream str;
1189 +
        str << "Surfaces do not follow in u-parametric direction in CTiglBSplineAlgorithms::concatSurfacesUDir. ";
1190 +
        str << "Surface 1 ends at " << umax1 << ", Surface 2 begins at " << umin2 << "!";
1191 +
        throw CTiglError(str.str(), TIGL_MATH_ERROR);
1192 +
    }
1193 +
1194 +
    bspl1->SetVNotPeriodic();
1195 +
    bspl2->SetVNotPeriodic();
1196 +
1197 +
    auto u_degree = std::max(bspl1->UDegree(), bspl2->UDegree());
1198 +
    auto v_degree = std::max(bspl1->VDegree(), bspl2->VDegree());
1199 +
1200 +
    bspl1->IncreaseDegree(u_degree, v_degree);
1201 +
    bspl2->IncreaseDegree(u_degree, v_degree);
1202 +
1203 +
    // check that corner points match
1204 +
    auto leftCornerDist = bspl1->Value(umax1, vmin1).Distance(bspl2->Value(umin2, vmin2));
1205 +
    auto rightCornerDist = bspl1->Value(umax1, vmax1).Distance(bspl2->Value(umin2, vmax2)) ;
1206 +
    if (leftCornerDist > space_tol || rightCornerDist > space_tol) {
1207 +
        throw CTiglError("Surfaces don't match within tolerances in CTiglBSplineAlgorithms::concatSurfacesUDir.", TIGL_MATH_ERROR);
1208 +
    }
1209 +
1210 +
    auto spl_vec = CTiglBSplineAlgorithms::createCommonKnotsVectorSurface({bspl1, bspl2}, SurfaceDirection::v);
1211 +
    bspl1 = spl_vec[0];
1212 +
    bspl2 = spl_vec[1];
1213 +
1214 +
    assert(bspl1->NbVPoles() == bspl2->NbVPoles());
1215 +
1216 +
    // concat control points
1217 +
    TColgp_Array2OfPnt cpsNew(1, bspl1->NbUPoles() + bspl2->NbUPoles() - 1, 1, bspl1->NbVPoles());
1218 +
    for (int iv = 0; iv < bspl1->NbVPoles(); ++iv) {
1219 +
        for (int iu = 0; iu < bspl1->NbUPoles() - 1; ++iu) {
1220 +
            cpsNew.SetValue(iu+1, iv+1, bspl1->Pole(iu+1, iv+1));
1221 +
        }
1222 +
        auto offset = bspl1->NbUPoles();
1223 +
        for (int iu = 0; iu < bspl2->NbUPoles(); ++iu) {
1224 +
            cpsNew.SetValue(iu + offset, iv+1, bspl2->Pole(iu+1, iv+1));
1225 +
        }
1226 +
    }
1227 +
1228 +
    // concat knots and mults
1229 +
    TColStd_Array1OfReal uknots_new(1, bspl1->NbUKnots() + bspl2->NbUKnots() - 1);
1230 +
    TColStd_Array1OfInteger umults_new(1, bspl1->NbUKnots() + bspl2->NbUKnots() - 1);
1231 +
1232 +
    for (int i = 0; i < bspl1->NbUKnots()-1; ++i) {
1233 +
        uknots_new.SetValue(i+1, bspl1->UKnot(i+1));
1234 +
        umults_new.SetValue(i+1, bspl1->UMultiplicity(i+1));
1235 +
    }
1236 +
1237 +
    int middleIdx = bspl1->NbUKnots();
1238 +
    uknots_new.SetValue(middleIdx, 0.5 * (bspl1->UKnot(middleIdx) + bspl2->UKnot(1)));
1239 +
    umults_new.SetValue(middleIdx, bspl1->UMultiplicity(middleIdx) - 1);
1240 +
1241 +
    for (int i = 1; i < bspl2->NbUKnots(); ++i) {
1242 +
        uknots_new.SetValue(i + middleIdx, bspl2->UKnot(i+1));
1243 +
        umults_new.SetValue(i + middleIdx, bspl2->UMultiplicity(i+1));
1244 +
    }
1245 +
1246 +
    // we simply take the v-knots of the first spline
1247 +
    TColStd_Array1OfReal vknots_new(1, bspl1->NbVKnots());
1248 +
    TColStd_Array1OfInteger vmults_new(1, bspl1->NbVKnots());
1249 +
    bspl1->VKnots(vknots_new);
1250 +
    bspl1->VMultiplicities(vmults_new);
1251 +
1252 +
#ifdef DEBUG
1253 +
    int sum_umults = 0;
1254 +
    for (int i = umults_new.Lower(); i <= umults_new.Upper(); ++i) {
1255 +
        sum_umults += umults_new.Value(i);
1256 +
    }
1257 +
1258 +
    int sum_vmults = 0;
1259 +
    for (int i = vmults_new.Lower(); i <= vmults_new.Upper(); ++i) {
1260 +
        sum_vmults += vmults_new.Value(i);
1261 +
    }
1262 +
1263 +
    assert(cpsNew.ColLength() + u_degree + 1 == sum_umults);
1264 +
    assert(cpsNew.RowLength() + v_degree + 1 == sum_vmults);
1265 +
#endif
1266 +
1267 +
    return new Geom_BSplineSurface(cpsNew, uknots_new, vknots_new,
1268 +
                                   umults_new, vmults_new,
1269 +
                                   u_degree, v_degree, false, false);
1270 +
}
1271 +
1272 +
Handle(Geom_BSplineSurface) CTiglBSplineAlgorithms::makeKnotsUniform(Handle(Geom_BSplineSurface) surf, unsigned int nseg_u, unsigned int nseg_v)
1273 +
{
1274 +
    double u1, u2, v1, v2;
1275 +
    surf->Bounds(u1, u2, v1, v2);
1276 +
1277 +
    // we create a degree 3 approximation in all directions
1278 +
    auto ncp_u = std::max(4, static_cast<int>(nseg_u + 1));
1279 +
    auto ncp_v = std::max(4, static_cast<int>(nseg_v + 1));
1280 +
1281 +
    auto u = LinspaceWithBreaks(u1, u2, ncp_u, {});
1282 +
    auto v = LinspaceWithBreaks(v1, v2, ncp_v, {});
1283 +
1284 +
    TColgp_Array2OfPnt points(1, ncp_u, 1, ncp_v);
1285 +
1286 +
    for (size_t i = 0; i < u.size(); ++i) {
1287 +
        for (size_t j = 0; j < v.size(); ++j) {
1288 +
            auto pnt = surf->Value(u[i], v[j]);
1289 +
            points.SetValue(static_cast<Standard_Integer>(i+1), static_cast<Standard_Integer>(j+1), pnt);
1290 +
        }
1291 +
    }
1292 +
1293 +
    return CTiglBSplineAlgorithms::pointsToSurface(points, u, v, true, true);
1294 +
}
1295 +
1142 1296
} // namespace tigl

@@ -189,7 +189,8 @@
Loading
189 189
    surfaces_vector_unmod.push_back(tensorProdSurf);
190 190
191 191
    // create common knot vector for all three surfaces
192 -
    std::vector<Handle(Geom_BSplineSurface)> surfaces_vector = CTiglBSplineAlgorithms::createCommonKnotsVectorSurface(surfaces_vector_unmod);
192 +
    std::vector<Handle(Geom_BSplineSurface)> surfaces_vector = CTiglBSplineAlgorithms::createCommonKnotsVectorSurface(surfaces_vector_unmod,
193 +
                                                                                                                      SurfaceDirection::both);
193 194
194 195
    assert(surfaces_vector.size() == 3);
195 196

@@ -39,6 +39,14 @@
Loading
39 39
namespace tigl
40 40
{
41 41
42 +
enum class SurfaceDirection
43 +
{
44 +
    u,
45 +
    v,
46 +
    both
47 +
};
48 +
49 +
42 50
class CTiglBSplineAlgorithms
43 51
{
44 52
public:
@@ -117,21 +125,31 @@
Loading
117 125
118 126
    /**
119 127
     * @brief createCommonKnotsVectorSurface:
120 -
     *          Creates a common knot vector in both u- and v-direction of the given vector of B-spline surfaces
128 +
     *          Creates a common knot vector in both u- and / or v-direction of the given vector of B-spline surfaces
121 129
     *          The common knot vector contains all knots in u- and v-direction of all surfaces with the highest multiplicity of all surfaces.
122 -
     *          !!! This method calls the method createCommonKnotsVectorSurfaceOneDir two times to create a common knot vector in both directions !!!
130 +
     *
131 +
     *          Note: the parameter range of the surfaces must match before calling this function.
132 +
     *
123 133
     * @param old_surfaces_vector:
124 134
     *          the given vector of B-spline surfaces that could have a different knot vector in u- and v-direction
135 +
     * @param dir:
136 +
     *          Defines, which knot vector (u/v/both) is modified
125 137
     * @return
126 138
     *          the given vector of B-spline surfaces, now with a common knot vector
127 139
     *          The B-spline surface geometry remains the same.
128 140
     */
129 -
    TIGL_EXPORT static std::vector<Handle(Geom_BSplineSurface) > createCommonKnotsVectorSurface(const std::vector<Handle(Geom_BSplineSurface)>& old_surfaces_vector);
141 +
    TIGL_EXPORT static std::vector<Handle(Geom_BSplineSurface) > createCommonKnotsVectorSurface(const std::vector<Handle(Geom_BSplineSurface)>& old_surfaces_vector, SurfaceDirection dir);
130 142
131 143
    /**
144 +
     * Changes the parameter range of the b-spline curve
132 145
     */
133 146
    TIGL_EXPORT static void reparametrizeBSpline(Geom_BSplineCurve& spline, double umin, double umax, double tol=1e-15);
134 147
148 +
    /**
149 +
     * Changes the parameter range of the b-spline surfae
150 +
     */
151 +
    TIGL_EXPORT static void reparametrizeBSpline(Geom_BSplineSurface& spline, double umin, double umax, double vmin, double vmax, double tol);
152 +
135 153
    /**
136 154
     * Reparametrizes the B-Spline such that the knot distribution is uniform and the number of
137 155
     * Segments is a power of 2
@@ -262,6 +280,38 @@
Loading
262 280
    TIGL_EXPORT static Handle(Geom_BSplineCurve) concatCurves(std::vector<Handle(Geom_BSplineCurve)> curves,
263 281
                                                              bool parByLength=true, double tolerance = 1e-6);
264 282
283 +
    /**
284 +
     * @brief Concatenates two surfaces in u direction
285 +
     *
286 +
     * Note: This function has the following requirements
287 +
     *   - s2 follows s1 in u direction and have a common boundary
288 +
     *   - s2 follows s1 also in parametric domain
289 +
     *   - both surfaces are non-rational!
290 +
     *   - the surfaces a non-periodic in u direction
291 +
     *
292 +
     * The resulting surface might not C1 and C2 continuous.
293 +
     * We still have geometric continuity.
294 +
     *
295 +
     * To achieve parametric continuity, the surfaces must be
296 +
     * re-parametrized accordingly before
297 +
     */
298 +
    TIGL_EXPORT static Handle(Geom_BSplineSurface) concatSurfacesUDir(Handle(Geom_BSplineSurface) bspl1, Handle(Geom_BSplineSurface) bspl2, double space_tol=1e-5);
299 +
300 +
    /**
301 +
     * @ brief Changes the knot sequence to be uniform after calling the function
302 +
     *
303 +
     * Technically, this is done by approximating the surface with a new surface
304 +
     * which also adds an approximation error.
305 +
     * For the surface approximation, derivatives at the boundary are not taken into account yet.
306 +
     *
307 +
     * The approximation error depends on the number of knot segments,
308 +
     * the more segments are used, the better will be the result.
309 +
     *
310 +
     * @param surf Surface to approximate
311 +
     * @param nseg_u Number of knot segments in u direction
312 +
     * @param nseg_v Number of knot segments in v direction
313 +
    */
314 +
    TIGL_EXPORT static Handle(Geom_BSplineSurface) makeKnotsUniform(Handle(Geom_BSplineSurface) surf, unsigned int nseg_u, unsigned int nseg_v);
265 315
};
266 316
} // namespace tigl
267 317

@@ -59,6 +59,8 @@
Loading
59 59
#include "CGroupShapes.h"
60 60
#include <TopExp.hxx>
61 61
#include <TopTools_IndexedMapOfShape.hxx>
62 +
#include <TopoDS_Iterator.hxx>
63 +
#include <TopoDS.hxx>
62 64
63 65
64 66
namespace tigl
@@ -858,9 +860,25 @@
Loading
858 860
859 861
TopoDS_Compound CCPACSWing::GetGuideCurveWires() const
860 862
{
861 -
    return *guideCurves;
863 +
    return guideCurves->wiresAsCompound;
862 864
}
863 865
866 +
std::vector<double> CCPACSWing::GetGuideCurveStartParameters() const
867 +
{
868 +
    if (GetSegmentCount() == 0) {
869 +
        return {};
870 +
    }
871 +
872 +
    const auto& segment = GetSegment(1);
873 +
    const auto& guides = segment.GetGuideCurves();
874 +
    if (!guides) {
875 +
        return {};
876 +
    }
877 +
878 +
    return guides->GetRelativeCircumferenceParameters();
879 +
}
880 +
881 +
864 882
std::vector<gp_Pnt> CCPACSWing::GetGuideCurvePoints()
865 883
{
866 884
    std::vector<gp_Pnt> points;
@@ -884,7 +902,7 @@
Loading
884 902
}
885 903
886 904
887 -
void CCPACSWing::BuildGuideCurveWires(TopoDS_Compound& cache) const
905 +
void CCPACSWing::BuildGuideCurveWires(LocatedGuideCurves& cache) const
888 906
{
889 907
    // check, if the wing has a blunt trailing edge
890 908
    bool hasBluntTE = true;
@@ -938,7 +956,24 @@
Loading
938 956
939 957
    // connect guide curve segments to a spline with given continuity conditions and tangents
940 958
    CTiglCurveConnector connector(roots, sectionParams);
941 -
    cache = connector.GetConnectedGuideCurves();
959 +
    auto wires = connector.GetConnectedGuideCurves();
960 +
961 +
    //  collect the from_ref_circumference values
962 +
    assert(roots.size() == GetNumberOfSubshapes(wires));
963 +
964 +
    cache.wiresAsCompound = wires;
965 +
    cache.curves.clear();
966 +
967 +
    auto rootIt = roots.begin();
968 +
    for (TopoDS_Iterator anIter(wires); anIter.More(); anIter.Next(), rootIt++) {
969 +
        cache.curves.push_back({TopoDS::Wire(anIter.Value()), rootIt->first});
970 +
    }
971 +
972 +
    // sort according to from location parameter
973 +
    using LocCurve = LocatedGuideCurves::LocatedGuideCurve;
974 +
    std::sort(std::begin(cache.curves), std::end(cache.curves), [](const LocCurve& c1, const LocCurve& c2) {
975 +
        return c1.fromRelCircumference < c2.fromRelCircumference;
976 +
    });
942 977
}
943 978
944 979
TopoDS_Shape transformWingProfileGeometry(const CTiglTransformation& wingTransform, const CTiglWingConnection& connection, const TopoDS_Shape& wire)

@@ -0,0 +1,83 @@
Loading
1 +
/*
2 +
* Copyright (C) 2020 German Aerospace Center (DLR/SC)
3 +
*
4 +
* Created: 2020-09-10 Martin Siggel <Martin.Siggel@dlr.de>
5 +
*
6 +
* Licensed under the Apache License, Version 2.0 (the "License");
7 +
* you may not use this file except in compliance with the License.
8 +
* You may obtain a copy of the License at
9 +
*
10 +
*     http://www.apache.org/licenses/LICENSE-2.0
11 +
*
12 +
* Unless required by applicable law or agreed to in writing, software
13 +
* distributed under the License is distributed on an "AS IS" BASIS,
14 +
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 +
* See the License for the specific language governing permissions and
16 +
* limitations under the License.
17 +
*/
18 +
19 +
#ifndef CTIGLCONCATSURFACES_H
20 +
#define CTIGLCONCATSURFACES_H
21 +
22 +
#include "tigl_internal.h"
23 +
#include <vector>
24 +
#include <Geom_BSplineSurface.hxx>
25 +
#include <boost/optional.hpp>
26 +
27 +
namespace tigl
28 +
{
29 +
30 +
enum class ConcatDir
31 +
{
32 +
    u,
33 +
    v
34 +
};
35 +
36 +
class CTiglConcatSurfaces
37 +
{
38 +
public:
39 +
    /**
40 +
     * @brief Concatenes multiple surfaces along the given directions
41 +
     *
42 +
     * Note: The surfaces must follow in the correct order in the specified direction
43 +
     *
44 +
     * @param surfaces      The surfaces to concatenate
45 +
     * @param surfaceParams A vector of parameters that define the parameters at the final surface, at which
46 +
     *                      the input surfaces are stitched.
47 +
     * @param dir           Direction to concatenate
48 +
     */
49 +
    TIGL_EXPORT CTiglConcatSurfaces(const std::vector<Handle(Geom_BSplineSurface)>& surfaces,
50 +
                                    const std::vector<double>& surfaceParams, ConcatDir dir);
51 +
52 +
    /**
53 +
     * @brief This allows the algorithm to make the knot sequence of each input
54 +
     * surface uniform.
55 +
     *
56 +
     * This might be useful, if the input surfaces have very different knot distributions
57 +
     * leaving a resulting in a bad balanced knot vector of the final surfaces.
58 +
     * This approximation comes however with an error.
59 +
     *
60 +
     * @param nUSeg Number of knot segments in u dir to approximate
61 +
     * @param nVSeg Number of knot segments in v dir to approximate
62 +
     */
63 +
    TIGL_EXPORT void SetMakeKnotsUniformEnabled(unsigned int nUSeg, unsigned int nVSeg);
64 +
65 +
    /**
66 +
     + @brief Returns the final surface
67 +
     */
68 +
    TIGL_EXPORT Handle(Geom_BSplineSurface) Surface() const;
69 +
70 +
private:
71 +
    std::vector<Handle(Geom_BSplineSurface)> m_surfaces;
72 +
    std::vector<double> m_params;
73 +
    ConcatDir m_dir;
74 +
75 +
    struct SegmentsSize {
76 +
        unsigned int nu, nv;
77 +
    };
78 +
    boost::optional<SegmentsSize> m_approxSegments;
79 +
};
80 +
81 +
} // namespace tigl
82 +
83 +
#endif // CTIGLCONCATSURFACES_H

@@ -45,6 +45,9 @@
Loading
45 45
#include "tigl_config.h"
46 46
#include "math/tiglmathfunctions.h"
47 47
#include "CNamedShape.h"
48 +
#include "CTiglWingBuilder.h"
49 +
#include "CTiglConcatSurfaces.h"
50 +
#include "GeomConvert.hxx"
48 51
49 52
#include "BRepOffsetAPI_ThruSections.hxx"
50 53
#include "TopExp_Explorer.hxx"
@@ -126,42 +129,6 @@
Loading
126 129
        return trafo.Transform(point);
127 130
    }
128 131
129 -
    // Set the face traits
130 -
    void SetFaceTraits (PNamedShape loft, std::string shapeUID) 
131 -
    { 
132 -
        // designated names of the faces
133 -
        std::vector<std::string> names(5);
134 -
        names[0]="Bottom";
135 -
        names[1]="Top";
136 -
        names[2]="TrailingEdge";
137 -
        names[3]="Inside";
138 -
        names[4]="Outside";
139 -
140 -
        // map of faces
141 -
        TopTools_IndexedMapOfShape map;
142 -
        TopExp::MapShapes(loft->Shape(), TopAbs_FACE, map);
143 -
        
144 -
        for (int iFace = 0; iFace < map.Extent(); ++iFace) {
145 -
            loft->FaceTraits(iFace).SetComponentUID(shapeUID);
146 -
        }
147 -
148 -
        // check if number of faces is correct (only valid for ruled surfaces lofts)
149 -
        if (map.Extent() != 5 && map.Extent() != 4) {
150 -
            LOG(ERROR) << "CCPACSWingSegment: Unable to determine face names in ruled surface loft";
151 -
            return;
152 -
        }
153 -
        // remove trailing edge name if there is no trailing edge
154 -
        if (map.Extent() == 4) {
155 -
            names.erase(names.begin()+2);
156 -
        }
157 -
        // set face trait names
158 -
        for (int i = 0; i < map.Extent(); i++) {
159 -
            CFaceTraits traits = loft->GetFaceTraits(i);
160 -
            traits.SetName(names[i].c_str());
161 -
            loft->SetFaceTraits(i, traits);
162 -
        }
163 -
    }
164 -
    
165 132
    /**
166 133
     * @brief getFaceTrimmingEdge Creates an edge in parameter space to trim a face
167 134
     * @return 
@@ -486,7 +453,11 @@
Loading
486 453
    std::string loftName = GetUID();
487 454
    std::string loftShortName = GetShortShapeName();
488 455
    PNamedShape loft (new CNamedShape(loftShape, loftName.c_str(), loftShortName.c_str()));
489 -
    SetFaceTraits(loft, GetUID());
456 +
    std::vector<double> guideCurveParams = {};
457 +
    if (GetGuideCurves()) {
458 +
        guideCurveParams = GetGuideCurves()->GetRelativeCircumferenceParameters();
459 +
    }
460 +
    CTiglWingBuilder::SetFaceTraits(guideCurveParams,  GetUID(), loft, innerConnection.GetProfile().HasBluntTE());
490 461
    return loft;
491 462
}
492 463
@@ -974,11 +945,61 @@
Loading
974 945
975 946
void CCPACSWingSegment::MakeSurfaces(SurfaceCache& cache) const
976 947
{
977 -
    // make upper and lower surface
978 -
    cache.lowerSurface = BRep_Tool::Surface(TopoDS::Face(GetLowerShape()));
979 -
    cache.upperSurface = BRep_Tool::Surface(TopoDS::Face(GetUpperShape()));
980 -
    cache.lowerSurfaceLocal = BRep_Tool::Surface(TopoDS::Face(GetLowerShape(WING_COORDINATE_SYSTEM)));
981 -
    cache.upperSurfaceLocal = BRep_Tool::Surface(TopoDS::Face(GetUpperShape(WING_COORDINATE_SYSTEM)));
948 +
    auto globalToLocalTrsf = GetParent()->GetParent<CCPACSWing>()->GetTransformationMatrix()
949 +
                                 .Inverted();
950 +
951 +
    auto lowerShape = GetLowerShape(GLOBAL_COORDINATE_SYSTEM);
952 +
    auto upperShape = GetUpperShape(GLOBAL_COORDINATE_SYSTEM);
953 +
954 +
    if (m_guideCurves) {
955 +
        auto params = m_guideCurves->GetRelativeCircumferenceParameters();
956 +
        auto it = std::find_if(std::begin(params), std::end(params), [](double val) {
957 +
            // the leading edge is defined at parameter 0, we allow some tolerance
958 +
            return std::abs(val) < 1e-3;
959 +
        });
960 +
961 +
        if (it == params.end()) {
962 +
            // could not find leading edge guide curve
963 +
            throw CTiglError ("There is no guide curve defined at the leading edge");
964 +
        }
965 +
966 +
        // split into upper and lower parameters
967 +
        std::vector<double> lower_params, upper_params;
968 +
        std::copy(std::begin(params), it+1, std::back_inserter(lower_params));
969 +
        std::copy(it, std::end(params), std::back_inserter(upper_params));
970 +
971 +
        auto concatSurfs = [](const TopoDS_Shape& shape, const std::vector<double>& parms) {
972 +
            if (GetNumberOfFaces(shape) == 1) {
973 +
                return BRep_Tool::Surface(TopoDS::Face(shape));
974 +
            }
975 +
            else {
976 +
                std::vector<Handle(Geom_BSplineSurface)> surfs;
977 +
978 +
                for (TopExp_Explorer expl(shape, TopAbs_FACE); expl.More(); expl.Next()) {
979 +
                    const TopoDS_Face& face = TopoDS::Face(expl.Current());
980 +
                    auto bspl = GeomConvert::SurfaceToBSplineSurface(BRep_Tool::Surface(face));
981 +
                    surfs.push_back(bspl);
982 +
                }
983 +
984 +
                CTiglConcatSurfaces concat(surfs, parms, ConcatDir::u);
985 +
                return Handle(Geom_Surface)(concat.Surface());
986 +
            }
987 +
        };
988 +
989 +
        // make upper and lower surface
990 +
        cache.lowerSurface = concatSurfs(lowerShape, lower_params);
991 +
        cache.upperSurface = concatSurfs(upperShape, upper_params);
992 +
993 +
    }
994 +
    else {
995 +
        // make upper and lower surface
996 +
        cache.lowerSurface = BRep_Tool::Surface(TopoDS::Face(lowerShape));
997 +
        cache.upperSurface = BRep_Tool::Surface(TopoDS::Face(upperShape));
998 +
    }
999 +
1000 +
    cache.lowerSurfaceLocal = globalToLocalTrsf.Transform(cache.lowerSurface);
1001 +
    cache.upperSurfaceLocal = globalToLocalTrsf.Transform(cache.upperSurface);
1002 +
982 1003
}
983 1004
984 1005
void CCPACSWingSegment::MakeChordSurfaces(ChordSurfaceCache& cache) const

@@ -24,7 +24,10 @@
Loading
24 24
#include "tigl.h"
25 25
#include "BRepBuilderAPI_GTransform.hxx"
26 26
#include "BRepBuilderAPI_Transform.hxx"
27 +
#include "BRepBuilderAPI_MakeFace.hxx"
28 +
#include "BRep_Tool.hxx"
27 29
#include "gp_XYZ.hxx"
30 +
#include "TopoDS_Face.hxx"
28 31
#include "Standard_Version.hxx"
29 32
#include "CNamedShape.h"
30 33
@@ -428,6 +431,21 @@
Loading
428 431
    }
429 432
}
430 433
434 +
// Transforms a surface with the current transformation matrix and
435 +
// returns the transformed point
436 +
TIGL_EXPORT Handle(Geom_Surface) CTiglTransformation::Transform(const Handle(Geom_Surface)& surf) const
437 +
{
438 +
    auto surfCopy = Handle(Geom_Surface)::DownCast(surf->Copy());
439 +
440 +
    TopoDS_Face tmpFace = BRepBuilderAPI_MakeFace(surfCopy, 1e-6);
441 +
    tmpFace = TopoDS::Face(Transform(tmpFace));
442 +
    TopLoc_Location L;
443 +
    surfCopy = BRep_Tool::Surface(tmpFace, L);
444 +
    surfCopy->Transform(L.Transformation());
445 +
446 +
    return surfCopy;
447 +
}
448 +
431 449
PNamedShape tigl::CTiglTransformation::Transform(PNamedShape shape) const
432 450
{
433 451
    if (!shape) {

@@ -39,181 +39,17 @@
Loading
39 39
#include <Geom_Plane.hxx>
40 40
41 41
#include <cassert>
42 -
43 -
#define NO_EXPLICIT_TE_MODELING
42 +
#include <algorithm>
44 43
45 44
namespace tigl
46 45
{
47 46
48 -
Standard_Boolean CreateSideCap(const TopoDS_Wire& W,
49 -
                               const Standard_Real presPln,
50 -
                               TopoDS_Face& theFace);
51 47
52 48
CTiglWingBuilder::CTiglWingBuilder(const CCPACSWing& wing)
53 49
    : _wing(wing)
54 50
{
55 51
}
56 52
57 -
#ifndef NO_EXPLICIT_TE_MODELING
58 -
PNamedShape CTiglWingBuilder::BuildShape()
59 -
{
60 -
    const CCPACSWingSegments& segments = _wing.m_segments;
61 -
62 -
    // check whether we have a blunt TE or not
63 -
    const CCPACSWingProfile& innerProfile = segments.GetSegment(1).GetInnerConnection().GetProfile();
64 -
65 -
    TopoDS_Compound guideCurves = _wing.GetGuideCurveWires();
66 -
67 -
    std::vector<TopoDS_Wire> guides;
68 -
    for (TopoDS_Iterator anIter(guideCurves); anIter.More(); anIter.Next()) {
69 -
        TopoDS_Wire aSh = TopoDS::Wire(anIter.Value());
70 -
        guides.push_back(aSh);
71 -
    }
72 -
73 -
    // we assume, that all profiles of one wing are either blunt or not
74 -
    // this is checked during cpacs loading of each wing segment
75 -
    bool hasBluntTE = innerProfile.HasBluntTE();
76 -
    bool hasGuideCurves = guides.size() > 0;
77 -
78 -
79 -
    CTiglMakeLoft lofter;
80 -
    lofter.setMakeSolid(false);
81 -
82 -
    std::vector<gp_Pnt> upperTEPoints, lowerTEPoints;
83 -
    for (int i=1; i <= segments.GetSegmentCount(); i++) {
84 -
        const TopoDS_Wire& startWire = segments.GetSegment(i).GetInnerWire();
85 -
86 -
        // extract trailing edge, in case of a blunt TE
87 -
        // we assume, that the TE is the last edge of the wire
88 -
        if (hasBluntTE) {
89 -
            BRepBuilderAPI_MakeWire wireMaker;
90 -
            TopTools_IndexedMapOfShape edgeMap;
91 -
            TopExp::MapShapes(startWire, TopAbs_EDGE, edgeMap);
92 -
            for (int i = 1; i <= edgeMap.Extent(); ++i) {
93 -
                const TopoDS_Edge& e = TopoDS::Edge(edgeMap(i));
94 -
                if (i < edgeMap.Extent()) {
95 -
                    wireMaker.Add(e);
96 -
                }
97 -
            }
98 -
            TopoDS_Wire aeroProfile = wireMaker.Wire();
99 -
            lofter.addProfiles(aeroProfile);
100 -
            upperTEPoints.push_back(GetLastPoint(aeroProfile));
101 -
            lowerTEPoints.push_back(GetFirstPoint(aeroProfile));
102 -
        }
103 -
        else {
104 -
            lofter.addProfiles(startWire);
105 -
        }
106 -
    }
107 -
108 -
    TopoDS_Wire endWire =  segments.GetSegment(segments.GetSegmentCount()).GetOuterWire();
109 -
    if (hasBluntTE) {
110 -
        // extract the wire without the trailing edge
111 -
112 -
        BRepBuilderAPI_MakeWire wireMaker;
113 -
        TopTools_IndexedMapOfShape edgeMap;
114 -
        TopExp::MapShapes(endWire, TopAbs_EDGE, edgeMap);
115 -
        for (int i = 1; i <= edgeMap.Extent(); ++i) {
116 -
            const TopoDS_Edge& e = TopoDS::Edge(edgeMap(i));
117 -
            if (i < edgeMap.Extent()) {
118 -
                wireMaker.Add(e);
119 -
            }
120 -
        }
121 -
        TopoDS_Wire aeroProfile = wireMaker.Wire();
122 -
        lofter.addProfiles(aeroProfile);
123 -
        upperTEPoints.push_back(GetLastPoint(aeroProfile));
124 -
        lowerTEPoints.push_back(GetFirstPoint(aeroProfile));
125 -
    }
126 -
    else {
127 -
        lofter.addProfiles(endWire);
128 -
    }
129 -
130 -
    // add guide curves
131 -
    lofter.addGuides(guideCurves);
132 -
133 -
    TopoDS_Shape aeroShape = lofter.Shape();
134 -
    BRepBuilderAPI_Sewing sewingAlgo;
135 -
    sewingAlgo.Add(aeroShape);
136 -
137 -
    // If blunt trailing edge is available, model it explicitly
138 -
    if (hasBluntTE) {
139 -
140 -
        TopoDS_Wire upperTE, lowerTE;
141 -
        if (hasGuideCurves) {
142 -
            // The guide curves are sorted in the order of the relative starting coordinate
143 -
            // at the innermost section
144 -
            upperTE = guides.back();
145 -
            lowerTE = guides.front();
146 -
        }
147 -
        else {
148 -
            // model the edges by taking the first and last profile points
149 -
150 -
            assert(lowerTEPoints.size() == upperTEPoints.size());
151 -
            assert(lowerTEPoints.size() > 1);
152 -
153 -
            // build upper edge
154 -
            BRepBuilderAPI_MakeWire upperWireMaker, lowerWireMaker;
155 -
            for (unsigned int i = 0; i < upperTEPoints.size() - 1; ++i) {
156 -
                upperWireMaker.Add(BRepBuilderAPI_MakeEdge(upperTEPoints.at(i), upperTEPoints.at(i+1)));
157 -
                lowerWireMaker.Add(BRepBuilderAPI_MakeEdge(lowerTEPoints.at(i), lowerTEPoints.at(i+1)));
158 -
            }
159 -
            upperTE = upperWireMaker.Wire();
160 -
            lowerTE = lowerWireMaker.Wire();
161 -
        }
162 -
163 -
        // the TE is build using a ruled loft
164 -
        BRepOffsetAPI_ThruSections trailingEdgeBuilder(Standard_False, Standard_True);
165 -
        trailingEdgeBuilder.AddWire(upperTE);
166 -
        trailingEdgeBuilder.AddWire(lowerTE);
167 -
        trailingEdgeBuilder.Build();
168 -
        TopoDS_Shape trailingEdge = trailingEdgeBuilder.Shape();
169 -
        sewingAlgo.Add(trailingEdge);
170 -
171 -
    } // hasBluntTE
172 -
173 -
174 -
    // get the profiles
175 -
    TopoDS_Wire innerWire = segments.GetSegment(1).GetInnerWire();
176 -
    TopoDS_Wire outerWire = segments.GetSegment(segments.GetSegmentCount()).GetOuterWire();
177 -
178 -
    TopoDS_Face innerFace, outerFace;
179 -
    CreateSideCap(innerWire, 1e-6, innerFace);
180 -
    CreateSideCap(outerWire, 1e-6, outerFace);
181 -
182 -
    sewingAlgo.Add(innerFace);
183 -
    sewingAlgo.Add(outerFace);
184 -
185 -
    sewingAlgo.Perform();
186 -
    TopoDS_Shape shellClosed  = sewingAlgo.SewedShape();
187 -
    if (shellClosed.ShapeType() != TopAbs_SHELL)
188 -
        throw CTiglError("Expected sewing algo to construct a shell when building wing loft");
189 -
    shellClosed.Closed(Standard_True);
190 -
191 -
    // make solid from shell
192 -
    TopoDS_Solid solid;
193 -
    BRep_Builder solidMaker;
194 -
    solidMaker.MakeSolid(solid);
195 -
    solidMaker.Add(solid, shellClosed);
196 -
197 -
    // verify the orientation the solid
198 -
    BRepClass3d_SolidClassifier clas3d(solid);
199 -
    clas3d.PerformInfinitePoint(Precision::Confusion());
200 -
    if (clas3d.State() == TopAbs_IN) {
201 -
     solidMaker.MakeSolid(solid);
202 -
        TopoDS_Shape aLocalShape = shellClosed.Reversed();
203 -
        solidMaker.Add(solid, TopoDS::Shell(aLocalShape));
204 -
    }
205 -
206 -
    solid.Closed(Standard_True);
207 -
    BRepLib::EncodeRegularity(solid);
208 -
209 -
    std::string loftName = _wing.GetUID();
210 -
    std::string loftShortName = _wing.GetShortShapeName();
211 -
    PNamedShape loft(new CNamedShape(solid, loftName.c_str(), loftShortName.c_str()));
212 -
    SetFaceTraits(_wing.GetUID(), loft, hasBluntTE);
213 -
214 -
    return loft;
215 -
}
216 -
#else
217 53
PNamedShape CTiglWingBuilder::BuildShape()
218 54
{
219 55
    const CCPACSWingSegments& segments = _wing.GetSegments();
@@ -241,11 +77,9 @@
Loading
241 77
    std::string loftName = _wing.GetUID();
242 78
    std::string loftShortName = _wing.GetShortShapeName();
243 79
    PNamedShape loft(new CNamedShape(loftShape, loftName.c_str(), loftShortName.c_str()));
244 -
    SetFaceTraits(_wing.GetUID(), loft, hasBluntTE);
80 +
    SetFaceTraits(_wing.GetGuideCurveStartParameters(), _wing.GetUID(), loft, hasBluntTE);
245 81
    return loft;
246 82
}
247 -
#endif
248 -
249 83
250 84
251 85
CTiglWingBuilder::operator PNamedShape()
@@ -253,106 +87,81 @@
Loading
253 87
    return BuildShape();
254 88
}
255 89
// Set the name of each wing face
256 -
void CTiglWingBuilder::SetFaceTraits (const std::string& wingUID, PNamedShape loft, bool hasBluntTE)
90 +
void CTiglWingBuilder::SetFaceTraits (const std::vector<double>& guideCurveParams, const std::string& shapeUID, PNamedShape shape, bool hasBluntTE)
257 91
{
258 -
    unsigned int nSegments = _wing.GetSegmentCount();
92 +
    auto params = guideCurveParams;
93 +
    assert(std::is_sorted(std::begin(params), std::end(params)));
94 +
95 +
    bool hasGuideCurves = params.size() > 0.;
96 +
97 +
    size_t nFacesPerSegment = 2; // Without trailing edge
98 +
    size_t idx_leading_edge = 1;
99 +
    if (hasGuideCurves) {
100 +
        double tolerance = 1e-3;
101 +
        if (std::abs(params.front() + 1.) > tolerance) {
102 +
            params.insert(params.begin(), -1.);
103 +
        }
104 +
105 +
        if (std::abs(params.back() - 1.) > tolerance) {
106 +
            params.push_back(1.);
107 +
        }
108 +
109 +
        // find leading edge curve
110 +
        idx_leading_edge = FindIndex(params.cbegin(), params.cend(), [tolerance] (double val) {
111 +
            return fabs(val) < tolerance;
112 +
        });
113 +
114 +
        if (idx_leading_edge == params.size()) {
115 +
            // no guide curve at leading edge
116 +
            LOG(ERROR) << "No guide curve at leading edge defined";
117 +
            return;
118 +
        }
119 +
        nFacesPerSegment = params.size() - 1;
120 +
    }
259 121
260 122
    // designated names of the faces
261 -
    std::vector<std::string> names(3);
262 -
    names[0]="Bottom";
263 -
    names[1]="Top";
264 -
    names[2]="TrailingEdge";
123 +
    std::vector<std::string> names;
124 +
    for (size_t i = 0; i < idx_leading_edge; ++i) {
125 +
        names.push_back("Bottom");
126 +
    }
127 +
128 +
    for (size_t i = idx_leading_edge; i < nFacesPerSegment; ++i) {
129 +
        names.push_back("Top");
130 +
    }
131 +
132 +
    if (hasBluntTE) {
133 +
        names.push_back("TrailingEdge");
134 +
        nFacesPerSegment += 1;
135 +
    }
136 +
265 137
    std::vector<std::string> endnames(2);
266 138
    endnames[0]="Inside";
267 139
    endnames[1]="Outside";
268 140
269 -
    unsigned int nFaces = GetNumberOfFaces(loft->Shape());
141 +
    unsigned int nFaces = GetNumberOfFaces(shape->Shape());
270 142
271 143
    for (unsigned int i = 0; i < nFaces; i++) {
272 -
        loft->FaceTraits(i).SetComponentUID(wingUID);
144 +
        shape->FaceTraits(i).SetComponentUID(shapeUID);
273 145
    }
274 -
    
275 -
    // check if number of faces without inside and outside surface (nFaces-2)
276 -
    // is a multiple of 2 (without Trailing Edges) or 3 (with Trailing Edges)
277 -
    if (!((nFaces-2)/nSegments == 2 || (nFaces-2)/nSegments == 3) || nFaces < 4) {
146 +
147 +
    if ((nFaces - 2) % nFacesPerSegment != 0) {
278 148
        LOG(ERROR) << "CCPACSWingBuilder: Unable to determine wing face names from wing loft.";
279 149
        return;
280 150
    }
281 151
282 -
#ifndef NO_EXPLICIT_TE_MODELING
283 -
284 -
    unsigned int nTEFaces = hasBluntTE ? nSegments : 0;
285 -
    unsigned int nAeroFaces = nFaces - nTEFaces - 2;
286 -
287 -
    // assign "Top" and "Bottom" to face traits
288 -
    for (unsigned int i = 0; i < nAeroFaces; i++) {
289 -
        CFaceTraits traits = loft->GetFaceTraits(i);
290 -
        traits.SetName(names[i%2].c_str());
291 -
        loft->SetFaceTraits(i, traits);
292 -
    }
293 -
294 -
    // assign TE to face traits
295 -
    for (unsigned int i = nAeroFaces; i < nAeroFaces + nTEFaces; ++i) {
296 -
        CFaceTraits traits = loft->GetFaceTraits(i);
297 -
        traits.SetName(names[2].c_str());
298 -
        loft->SetFaceTraits(i, traits);
299 -
    }
300 -
#else
301 -
    // remove trailing edge name if there is no trailing edge
302 -
    if (!hasBluntTE) {
303 -
        names.pop_back();
304 -
    }
305 152
    // assign "Top" and "Bottom" to face traits
306 153
    for (unsigned int i = 0; i < nFaces-2; i++) {
307 -
        CFaceTraits traits = loft->GetFaceTraits(i);
308 -
        traits.SetName(names[i%names.size()].c_str());
309 -
        loft->SetFaceTraits(i, traits);
154 +
        CFaceTraits traits = shape->GetFaceTraits(i);
155 +
        traits.SetName(names[i%names.size()]);
156 +
        shape->SetFaceTraits(i, traits);
310 157
    }
311 -
#endif
312 158
313 159
    // assign "Inside" and "Outside" to face traits
314 160
    for (unsigned int i = nFaces-2; i < nFaces; i++) {
315 -
        CFaceTraits traits = loft->GetFaceTraits(i);
316 -
        traits.SetName(endnames[i-nFaces+2].c_str());
317 -
        loft->SetFaceTraits(i, traits);
318 -
    }
319 -
}
320 -
321 -
// creates the inside and outside cap of the wing
322 -
Standard_Boolean CreateSideCap(const TopoDS_Wire& W,
323 -
                               const Standard_Real presPln,
324 -
                               TopoDS_Face& theFace)
325 -
{
326 -
    Standard_Boolean isDegen = Standard_True;
327 -
    TopoDS_Iterator iter(W);
328 -
    for (; iter.More(); iter.Next())
329 -
    {
330 -
        const TopoDS_Edge& anEdge = TopoDS::Edge(iter.Value());
331 -
        if (!BRep_Tool::Degenerated(anEdge))
332 -
            isDegen = Standard_False;
161 +
        CFaceTraits traits = shape->GetFaceTraits(i);
162 +
        traits.SetName(endnames[i-nFaces+2]);
163 +
        shape->SetFaceTraits(i, traits);
333 164
    }
334 -
    if (isDegen)
335 -
        return Standard_True;
336 -
337 -
    Standard_Boolean Ok = Standard_False;
338 -
    if (!W.IsNull()) {
339 -
        BRepBuilderAPI_FindPlane Searcher( W, presPln );
340 -
        if (Searcher.Found()) {
341 -
            theFace = BRepBuilderAPI_MakeFace(Searcher.Plane(), W);
342 -
            Ok = Standard_True;
343 -
        }
344 -
        else {
345 -
            // try to find another surface
346 -
            BRepBuilderAPI_MakeFace MF( W );
347 -
            if (MF.IsDone())
348 -
            {
349 -
                theFace = MF.Face();
350 -
                Ok = Standard_True;
351 -
            }
352 -
        }
353 -
    }
354 -
355 -
    return Ok;
356 165
}
357 166
358 167
} //namespace tigl

@@ -165,6 +165,9 @@
Loading
165 165
    // Returns all guide curve wires as a compound
166 166
    TIGL_EXPORT TopoDS_Compound GetGuideCurveWires() const;
167 167
168 +
    // Returns the "fromRelCirc" parameter for each guide curve wire
169 +
    TIGL_EXPORT std::vector<double> GetGuideCurveStartParameters() const;
170 +
168 171
    // Adjust, whether the wing should be modeled with the flaps or not
169 172
    TIGL_EXPORT void SetBuildFlaps(bool enabled);
170 173
@@ -172,7 +175,20 @@
Loading
172 175
    TIGL_EXPORT PNamedShape GetWingCleanShape() const;
173 176
174 177
protected:
175 -
    void BuildGuideCurveWires(TopoDS_Compound& cache) const;
178 +
179 +
    struct LocatedGuideCurves
180 +
    {
181 +
        struct LocatedGuideCurve
182 +
        {
183 +
            TopoDS_Wire wire;
184 +
            double fromRelCircumference;
185 +
        };
186 +
187 +
        TopoDS_Compound wiresAsCompound;
188 +
        std::vector<LocatedGuideCurve> curves;
189 +
    };
190 +
191 +
    void BuildGuideCurveWires(LocatedGuideCurves& cache) const;
176 192
177 193
    // Cleanup routine
178 194
    void Cleanup();
@@ -205,7 +221,8 @@
Loading
205 221
    TopoDS_Shape                   fusedSegmentWithEdge;     /**< All Segments in one shape plus modelled leading edge */ 
206 222
    TopoDS_Shape                   upperShape;
207 223
    TopoDS_Shape                   lowerShape;
208 -
    Cache<TopoDS_Compound, CCPACSWing> guideCurves;
224 +
225 +
    Cache<LocatedGuideCurves, CCPACSWing> guideCurves;
209 226
210 227
    Cache<PNamedShape, CCPACSWing> wingShapeWithCutouts;     /**< Wing without flaps / flaps removed */
211 228
    Cache<PNamedShape, CCPACSWing> wingCleanShape;           /**< Clean wing surface without flaps cutout*/

@@ -324,6 +324,44 @@
Loading
324 324
    return found - vectorOfPointers.begin();
325 325
}
326 326
327 +
/**
328 +
 * @brief Searches for a entry in a range and returns its index
329 +
 *
330 +
 * This function can be used with std::arrays, std::vectors
331 +
 * and also possible other containers supported by std::distance
332 +
 *
333 +
 * If the index is not found, the size of the range will be returned instead
334 +
 */
335 +
template <typename ForwardIter, typename Compare>
336 +
size_t FindIndex(ForwardIter begin, ForwardIter end, Compare comp)
337 +
{
338 +
    const auto it = std::find_if(begin, end, comp);
339 +
    if (it != end) {
340 +
        return std::distance(begin, it);
341 +
    }
342 +
    else {
343 +
        return std::distance(begin, end);
344 +
    }
345 +
}
346 +
347 +
/**
348 +
 * @brief Checks, whether an array contains a value or not
349 +
 *
350 +
 * @param array The array to be searched in
351 +
 * @param val The value to be saerched for
352 +
 * @param tolerance This functions is typically used with floating point values. The tolerance allows
353 +
 *                  to search for a value within the specified tolerance.
354 +
 */
355 +
template <typename ArrayLike, typename ValueType>
356 +
bool Contains(const ArrayLike& array, ValueType val, ValueType tolerance)
357 +
{
358 +
    auto idx = FindIndex(std::begin(array), std::end(array), [val, tolerance](const typename ArrayLike::value_type& cval) {
359 +
        return fabs(cval - val) < tolerance;
360 +
    });
361 +
362 +
    return idx < array.size();
363 +
}
364 +
327 365
template <class ArrayType, typename BinaryPredicate, typename BinaryMerge>
328 366
void ReplaceAdjacentWithMerged(ArrayType& list, BinaryPredicate is_adjacent, BinaryMerge merged)
329 367
{

@@ -101,12 +101,13 @@
Loading
101 101
        const CCPACSGuideCurve* root = GetGuideCurve(iguide).GetRootCurve();
102 102
        relCircs.push_back(*root->GetFromRelativeCircumference_choice2());
103 103
    }
104 -
    if ( relCircs.back() < 1.0 ) {
105 -
        relCircs.push_back(1.0);
106 -
    }
107 104
108 105
    std::sort(relCircs.begin(), relCircs.end());
109 106
107 +
    if (std::abs(relCircs.back() - 1.0) >= 1e-3 ) {
108 +
        relCircs.push_back(1.0);
109 +
    }
110 +
110 111
    return relCircs;
111 112
}
112 113
Files Coverage
src 69.42%
Project Totals (425 files) 69.42%
1
codecov:
2
  require_ci_to_pass: yes
3

4
coverage:
5
  precision: 2
6
  round: down
7
  range: "25...100"
8

9
parsers:
10
  gcov:
11
    branch_detection:
12
      conditional: yes
13
      loop: yes
14
      method: no
15
      macro: no
16

17
comment:
18
  layout: "reach,diff,flags,tree"
19
  behavior: default
20
  require_changes: no
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading