1
/*
2
* Copyright (C) 2007-2013 German Aerospace Center (DLR/SC)
3
*
4
* Created: 2010-08-13 Markus Litz <Markus.Litz@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
* @file
20
* @brief  Implementation of CPACS fuselage profile handling routines.
21
*/
22

23
#include "generated/TixiHelper.h"
24
#include "CCPACSFuselageProfile.h"
25
#include "CTiglError.h"
26
#include "CTiglTransformation.h"
27
#include "CTiglInterpolateBsplineWire.h"
28
#include "CTiglBSplineAlgorithms.h"
29
#include "tiglcommonfunctions.h"
30
#include "CTiglLogging.h"
31
#include "Debugging.h"
32

33
#include "TopoDS.hxx"
34
#include "TopoDS_Wire.hxx"
35
#include "gp_Pnt2d.hxx"
36
#include "gp_Vec2d.hxx"
37
#include "gp_Dir2d.hxx"
38
#include "GC_MakeSegment.hxx"
39
#include "BRepBuilderAPI_MakeEdge.hxx"
40
#include "BRepBuilderAPI_MakeWire.hxx"
41
#include "Geom_TrimmedCurve.hxx"
42
#include "GeomConvert.hxx"
43
#include "Geom_Plane.hxx"
44
#include "GCE2d_MakeSegment.hxx"
45
#include "Geom2d_Line.hxx"
46
#include "TopExp_Explorer.hxx"
47
#include "TopAbs_ShapeEnum.hxx"
48
#include "TopoDS_Edge.hxx"
49
#include "BRep_Tool.hxx"
50
#include "Geom2dAPI_InterCurveCurve.hxx"
51
#include "GeomAPI.hxx"
52
#include "gp_Pln.hxx"
53
#include "gce_MakeDir.hxx"
54
#include "gce_MakePln.hxx"
55
#include "BRepTools_WireExplorer.hxx"
56
#include "GeomAdaptor_Curve.hxx"
57
#include "GCPnts_AbscissaPoint.hxx"
58
#include "GeomAPI_IntCS.hxx"
59

60
#include "math.h"
61
#include <iostream>
62
#include <limits>
63
#include <sstream>
64
#include <algorithm>
65

66
namespace
67
{
68
// In case of a half profile, we have to compute the symmetric points and parameters
69 1
void SymmetrizeFuselageProfile(std::vector<tigl::CTiglPoint>& points, tigl::ParamMap& params,
70
                               std::vector<unsigned int>& kinks)
71
{
72 1
    size_t n_points = points.size();
73

74 1
    if (n_points == 0) {
75 0
        return;
76
    }
77

78 1
    if (fabs(points[0].y) > 1e-6) {
79 0
        throw tigl::CTiglError("Cannot create a symmetric fuselage profile. Y-Coordinate not zero!");
80
    }
81

82 1
    auto get_param_or = [&params](unsigned int idx, double def_value) -> double {
83 1
        const auto& it = params.find(idx);
84 1
        return it != params.end() ? it->second : def_value;
85 1
    };
86

87 1
    double umin = get_param_or(0, 0.);
88 1
    double umax = umin + 2. * (get_param_or(static_cast<unsigned int>(n_points - 1), 0.5) - umin);
89

90
    // y is already ~ 0, make it really zero!
91 1
    points[0].y = 0.;
92

93
    // mirror each point at x-z plane i.e. mirror y coordinate to close the profile
94
    // and skip first point
95 1
    for (size_t i = n_points - 1; i > 0; i--) {
96 1
        auto curP = points[i];
97 1
        if (i == n_points - 1 && std::abs(curP.y) < 1e-6) {
98
            // do not add the same points twice
99 1
            continue;
100
        }
101 1
        curP.y                  = -curP.y;
102 1
        unsigned int currentIdx = static_cast<unsigned int>(points.size());
103 1
        if (std::find(std::begin(kinks), std::end(kinks), i) != std::end(kinks)) {
104 0
            kinks.push_back(currentIdx);
105
        }
106 1
        auto parm_it = params.find(static_cast<unsigned int>(i));
107 1
        if (parm_it != params.end()) {
108 0
            double param_new   = umax + umin - parm_it->second;
109 0
            params[currentIdx] = param_new;
110
        }
111 1
        points.push_back(curP);
112
    }
113

114 1
    points.push_back(points[0]);
115 1
    params[0]                                            = umin;
116 1
    params[static_cast<unsigned int>(points.size() - 1)] = umax;
117
}
118
} // namespace
119

120
namespace tigl
121
{
122
// Constructor
123 1
CCPACSFuselageProfile::CCPACSFuselageProfile(CCPACSFuselageProfiles* parent, CTiglUIDManager* uidMgr)
124
    : generated::CPACSProfileGeometry(parent, uidMgr)
125
    , mirrorSymmetry(false)
126
    , wireCache(*this, &CCPACSFuselageProfile::BuildWires)
127
    , diameterPointsCache(*this, &CCPACSFuselageProfile::BuildDiameterPoints)
128 1
    , profileWireAlgo(new CTiglInterpolateBsplineWire)
129
{
130
}
131

132 1
CCPACSFuselageProfile::~CCPACSFuselageProfile()
133
{
134
}
135

136
// Read fuselage profile file
137 1
void CCPACSFuselageProfile::ReadCPACS(const TixiDocumentHandle& tixiHandle, const std::string& xpath)
138
{
139 1
    Invalidate();
140 1
    generated::CPACSProfileGeometry::ReadCPACS(tixiHandle, xpath);
141

142
    // symmetry element does not conform to CPACS spec
143 1
    if (tixi::TixiCheckElement(tixiHandle, xpath + "/symmetry")) {
144 1
        mirrorSymmetry = tixi::TixiGetTextElement(tixiHandle, xpath + "/symmetry") == "half";
145
    }
146
}
147

148 1
const int CCPACSFuselageProfile::GetNumPoints() const
149
{
150 1
    if (!m_pointList_choice1)
151 0
        return 0;
152 1
    return static_cast<int>(m_pointList_choice1->AsVector().size());
153
}
154

155
// Returns the flag for the mirror symmetry with respect to the x-z-plane in the fuselage profile
156 1
bool CCPACSFuselageProfile::GetMirrorSymmetry() const
157
{
158 1
    return mirrorSymmetry;
159
}
160

161
// Invalidates internal fuselage profile state
162 1
void CCPACSFuselageProfile::InvalidateImpl(const boost::optional<std::string>& source) const
163
{
164 1
    wireCache.clear();
165 1
    diameterPointsCache.clear();
166
}
167

168
// Returns the fuselage profile wire
169 1
TopoDS_Wire CCPACSFuselageProfile::GetWire(bool forceClosed) const
170
{
171 1
    return forceClosed ? wireCache->closed : wireCache->original;
172
}
173

174
// Builds the fuselage profile wire. The returned wire is already transformed by the
175
// fuselage profile element transformation.
176 1
void CCPACSFuselageProfile::BuildWires(WireCache& cache) const
177
{
178 1
    if (!m_pointList_choice1)
179 0
        throw CTiglError("No pointlist specified");
180 1
    if (GetNumPoints() < 2) {
181 0
        throw CTiglError("Number of points is less than 2 in CCPACSFuselageProfile::BuildWire", TIGL_ERROR);
182
    }
183

184 1
    auto points = m_pointList_choice1->AsVector();
185 1
    auto params = m_pointList_choice1->GetParamsAsMap();
186 1
    auto kinks  = m_pointList_choice1->GetKinksAsVector();
187 1
    if (mirrorSymmetry) {
188 1
        SymmetrizeFuselageProfile(points, params, kinks);
189
    }
190

191
    // Build the B-Spline
192 1
    auto occPoints = OccArray(points);
193

194
    // we always want to include the endpoint, if it's the same as the startpoint
195
    // we use the middle to enforce closing of the spline
196 1
    gp_Pnt pStart = points.front().Get_gp_Pnt();
197 1
    gp_Pnt pEnd   = points.back().Get_gp_Pnt();
198

199
    // this check allows some tolerance, based on the absolute size of the profile
200 1
    if (pStart.Distance(pEnd) < 0.005 * CTiglBSplineAlgorithms::scale(occPoints->Array1())) {
201 1
        gp_Pnt pMiddle = 0.5 * (pStart.XYZ() + pEnd.XYZ());
202 1
        occPoints->SetValue(occPoints->Lower(), pMiddle);
203 1
        occPoints->SetValue(occPoints->Upper(), pMiddle);
204
    }
205

206 1
    CTiglInterpolatePointsWithKinks interp(occPoints, kinks, params, 0.5, 3);
207 1
    auto spline = interp.Curve();
208

209 1
    if (mirrorSymmetry) {
210 1
        double umin = spline->FirstParameter();
211 1
        double umax = spline->LastParameter();
212 1
        spline      = CTiglBSplineAlgorithms::trimCurve(spline, umin, 0.5 * (umin + umax));
213 1
        CTiglBSplineAlgorithms::reparametrizeBSpline(*spline, umin, umax);
214
    }
215

216
    // we reparametrize the spline to get better performing lofts.
217
    // there might be a small accuracy loss though.
218 1
    spline = CTiglBSplineAlgorithms::reparametrizeBSplineNiceKnots(spline).curve;
219

220
    // Create wires
221 1
    TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(spline).Edge();
222 1
    BRepBuilderAPI_MakeWire builder1(edge);
223 1
    TopoDS_Wire tempWireOriginal = builder1.Wire();
224

225 1
    BRepBuilderAPI_MakeWire builder2(edge);
226 1
    if (!spline->IsClosed()) {
227 1
        builder2.Add(BRepBuilderAPI_MakeEdge(spline->EndPoint(), spline->StartPoint()));
228
    }
229 1
    TopoDS_Wire tempWireClosed = builder2.Wire();
230 1
    if (tempWireClosed.IsNull() == Standard_True || tempWireOriginal.IsNull() == Standard_True) {
231 0
        throw CTiglError("TopoDS_Wire is null in CCPACSFuselageProfile::BuildWire", TIGL_ERROR);
232
    }
233

234 1
    cache.closed   = tempWireClosed;
235 1
    cache.original = tempWireOriginal;
236
}
237

238
// Transforms a point by the fuselage profile transformation
239 0
gp_Pnt CCPACSFuselageProfile::TransformPoint(const gp_Pnt& aPoint) const
240
{
241 0
    CTiglTransformation transformation;
242 0
    return transformation.Transform(aPoint);
243
}
244

245
// Gets a point on the fuselage profile wire in dependence of a parameter zeta with
246
// 0.0 <= zeta <= 1.0. For zeta = 0.0 this is the wire start point,
247
// for zeta = 1.0 the last wire point.
248 0
gp_Pnt CCPACSFuselageProfile::GetPoint(double zeta) const
249
{
250 0
    if (zeta < 0.0 || zeta > 1.0) {
251
        throw CTiglError("Parameter zeta not in the range 0.0 <= zeta <= 1.0 in CCPACSFuselageProfile::GetPoint",
252 0
                         TIGL_ERROR);
253
    }
254

255
    // Get the first edge of the wire
256 0
    BRepTools_WireExplorer wireExplorer(wireCache->original);
257 0
    if (!wireExplorer.More()) {
258 0
        throw CTiglError("Not enough edges found in CCPACSFuselageProfile::GetPoint", TIGL_ERROR);
259
    }
260

261 0
    Standard_Real firstParam = 0.;
262 0
    Standard_Real lastParam  = 1.;
263 0
    Handle(Geom_Curve) curve = BRep_Tool::Curve(wireExplorer.Current(), firstParam, lastParam);
264

265 0
    gp_Pnt point = curve->Value(firstParam * (1 - zeta) + lastParam * zeta);
266

267 0
    return point;
268
}
269

270 1
void CCPACSFuselageProfile::BuildDiameterPoints(DiameterPointsCache& cache) const
271
{
272 1
    if (!m_pointList_choice1)
273 0
        throw CTiglError("No pointlist specified");
274 1
    const std::vector<CTiglPoint>& coordinates = m_pointList_choice1->AsVector();
275

276 1
    if (mirrorSymmetry) {
277 1
        cache.start = coordinates[0].Get_gp_Pnt();
278 1
        cache.end   = coordinates[coordinates.size() - 1].Get_gp_Pnt();
279
    }
280
    else {
281
        // compute starting diameter point
282 1
        gp_Pnt firstPnt = coordinates[0].Get_gp_Pnt();
283 1
        gp_Pnt lastPnt  = coordinates[coordinates.size() - 1].Get_gp_Pnt();
284 1
        double x        = (firstPnt.X() + lastPnt.X()) / 2.;
285 1
        double y        = (firstPnt.Y() + lastPnt.Y()) / 2.;
286 1
        double z        = (firstPnt.Z() + lastPnt.Z()) / 2.;
287 1
        cache.start     = gp_Pnt(x, y, z);
288

289
        // find the point with the max dist to starting point
290 1
        cache.end = cache.start;
291 1
        for (std::vector<CTiglPoint>::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) {
292 1
            gp_Pnt point = it->Get_gp_Pnt();
293 1
            if (cache.start.Distance(point) > cache.start.Distance(cache.end)) {
294 1
                cache.end = point;
295
            }
296
        }
297
    }
298
}
299

300 1
TopoDS_Wire CCPACSFuselageProfile::GetDiameterWire() const
301
{
302 1
    Handle(Geom_TrimmedCurve) diameterCurve = GC_MakeSegment(diameterPointsCache->start, diameterPointsCache->end);
303 1
    TopoDS_Edge diameterEdge                = BRepBuilderAPI_MakeEdge(diameterCurve);
304 1
    TopoDS_Wire diameterWire                = BRepBuilderAPI_MakeWire(diameterEdge);
305 1
    return diameterWire;
306
}
307

308
} // end namespace tigl

Read our documentation on viewing source code .

Loading