/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2020-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ #include "searchablePlate.H" #include "addToRunTimeSelectionTable.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(searchablePlate, 0); addToRunTimeSelectionTable ( searchableSurface, searchablePlate, dict ); addNamedToRunTimeSelectionTable ( searchableSurface, searchablePlate, dict, plate ); } // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // Foam::direction Foam::searchablePlate::calcNormal(const point& span) { direction normalDir = 3; for (direction dir = 0; dir < vector::nComponents; ++dir) { if (span[dir] < 0) { // Negative entry. Flag and exit. normalDir = 3; break; } else if (span[dir] < VSMALL) { if (normalDir != 3) { // Multiple zero entries. Flag and exit. normalDir = 3; break; } normalDir = dir; } } if (normalDir == 3) { FatalErrorInFunction << "Span should have two positive and one zero entry: " << span << nl << exit(FatalError); } return normalDir; } // Returns miss or hit with face (always 0) Foam::pointIndexHit Foam::searchablePlate::findNearest ( const point& sample, const scalar nearestDistSqr ) const { // For every component direction can be // left of min, right of max or inbetween. // - outside points: project first one x plane (either min().x() // or max().x()), then onto y plane and finally z. You should be left // with intersection point // - inside point: find nearest side (compare to mid point). Project onto // that. // Project point on plane. pointIndexHit info(true, sample, 0); info.point()[normalDir_] = origin_[normalDir_]; // Clip to edges if outside for (direction dir = 0; dir < vector::nComponents; ++dir) { if (dir != normalDir_) { if (info.point()[dir] < origin_[dir]) { info.point()[dir] = origin_[dir]; } else if (info.point()[dir] > origin_[dir]+span_[dir]) { info.point()[dir] = origin_[dir]+span_[dir]; } } } // Check if outside. Optimisation: could do some checks on distance already // on components above if (info.point().distSqr(sample) > nearestDistSqr) { info.setMiss(); info.setIndex(-1); } return info; } Foam::pointIndexHit Foam::searchablePlate::findLine ( const point& start, const point& end ) const { pointIndexHit info ( true, Zero, 0 ); const vector dir(end-start); if (mag(dir[normalDir_]) < VSMALL) { info.setMiss(); info.setIndex(-1); } else { scalar t = (origin_[normalDir_]-start[normalDir_]) / dir[normalDir_]; if (t < 0 || t > 1) { info.setMiss(); info.setIndex(-1); } else { info.point() = start+t*dir; info.point()[normalDir_] = origin_[normalDir_]; // Clip to edges for (direction dir = 0; dir < vector::nComponents; ++dir) { if (dir != normalDir_) { if (info.point()[dir] < origin_[dir]) { info.setMiss(); info.setIndex(-1); break; } else if (info.point()[dir] > origin_[dir]+span_[dir]) { info.setMiss(); info.setIndex(-1); break; } } } } } // Debug if (info.hit()) { treeBoundBox bb(origin_, origin_+span_); bb.min()[normalDir_] -= 1e-6; bb.max()[normalDir_] += 1e-6; if (!bb.contains(info.point())) { FatalErrorInFunction << "bb:" << bb << endl << "origin_:" << origin_ << endl << "span_:" << span_ << endl << "normalDir_:" << normalDir_ << endl << "hitPoint:" << info.point() << abort(FatalError); } } return info; } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::searchablePlate::searchablePlate ( const IOobject& io, const point& origin, const vector& span ) : searchableSurface(io), origin_(origin), span_(span), normalDir_(calcNormal(span_)) { DebugInFunction << " origin:" << origin_ << " origin+span:" << origin_+span_ << " normal:" << vector::componentNames[normalDir_] << nl; bounds() = boundBox(origin_, origin_ + span_); } Foam::searchablePlate::searchablePlate ( const IOobject& io, const dictionary& dict ) : searchablePlate(io, dict.get("origin"), dict.get("span")) {} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // const Foam::wordList& Foam::searchablePlate::regions() const { if (regions_.empty()) { regions_.resize(1); regions_.first() = "region0"; } return regions_; } Foam::tmp Foam::searchablePlate::coordinates() const { return tmp::New(1, origin_ + 0.5*span_); } void Foam::searchablePlate::boundingSpheres ( pointField& centres, scalarField& radiusSqr ) const { centres.resize(1); radiusSqr.resize(1); centres[0] = origin_ + 0.5*span_; radiusSqr[0] = Foam::magSqr(0.5*span_); // Add a bit to make sure all points are tested inside radiusSqr += Foam::sqr(SMALL); } Foam::tmp Foam::searchablePlate::points() const { auto tpts = tmp::New(4, origin_); auto& pts = tpts.ref(); pts[2] += span_; if (span_.x() < span_.y() && span_.x() < span_.z()) { pts[1].y() += span_.y(); pts[3].z() += span_.z(); } else if (span_.y() < span_.z()) { pts[1].x() += span_.x(); pts[3].z() += span_.z(); } else { pts[1].x() += span_.x(); pts[3].y() += span_.y(); } return tpts; } bool Foam::searchablePlate::overlaps(const boundBox& bb) const { return bb.overlaps(bounds()); } void Foam::searchablePlate::findNearest ( const pointField& samples, const scalarField& nearestDistSqr, List& info ) const { info.setSize(samples.size()); forAll(samples, i) { info[i] = findNearest(samples[i], nearestDistSqr[i]); } } void Foam::searchablePlate::findLine ( const pointField& start, const pointField& end, List& info ) const { info.setSize(start.size()); forAll(start, i) { info[i] = findLine(start[i], end[i]); } } void Foam::searchablePlate::findLineAny ( const pointField& start, const pointField& end, List& info ) const { findLine(start, end, info); } void Foam::searchablePlate::findLineAll ( const pointField& start, const pointField& end, List>& info ) const { List nearestInfo; findLine(start, end, nearestInfo); info.setSize(start.size()); forAll(info, pointi) { if (nearestInfo[pointi].hit()) { info[pointi].setSize(1); info[pointi][0] = nearestInfo[pointi]; } else { info[pointi].clear(); } } } void Foam::searchablePlate::getRegion ( const List& info, labelList& region ) const { region.setSize(info.size()); region = 0; } void Foam::searchablePlate::getNormal ( const List& info, vectorField& normal ) const { normal.setSize(info.size()); normal = Zero; forAll(normal, i) { normal[i][normalDir_] = 1.0; } } void Foam::searchablePlate::getVolumeType ( const pointField& points, List& volType ) const { FatalErrorInFunction << "Volume type not supported for plate." << exit(FatalError); } // ************************************************************************* //