/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/modules/audio_processing/beamformer/array_util.h" #include #include #include "webrtc/base/checks.h" namespace webrtc { namespace { const float kMaxDotProduct = 1e-6f; } // namespace float GetMinimumSpacing(const std::vector& array_geometry) { RTC_CHECK_GT(array_geometry.size(), 1u); float mic_spacing = std::numeric_limits::max(); for (size_t i = 0; i < (array_geometry.size() - 1); ++i) { for (size_t j = i + 1; j < array_geometry.size(); ++j) { mic_spacing = std::min(mic_spacing, Distance(array_geometry[i], array_geometry[j])); } } return mic_spacing; } Point PairDirection(const Point& a, const Point& b) { return {b.x() - a.x(), b.y() - a.y(), b.z() - a.z()}; } float DotProduct(const Point& a, const Point& b) { return a.x() * b.x() + a.y() * b.y() + a.z() * b.z(); } Point CrossProduct(const Point& a, const Point& b) { return {a.y() * b.z() - a.z() * b.y(), a.z() * b.x() - a.x() * b.z(), a.x() * b.y() - a.y() * b.x()}; } bool AreParallel(const Point& a, const Point& b) { Point cross_product = CrossProduct(a, b); return DotProduct(cross_product, cross_product) < kMaxDotProduct; } bool ArePerpendicular(const Point& a, const Point& b) { return std::abs(DotProduct(a, b)) < kMaxDotProduct; } rtc::Maybe GetDirectionIfLinear( const std::vector& array_geometry) { RTC_DCHECK_GT(array_geometry.size(), 1u); const Point first_pair_direction = PairDirection(array_geometry[0], array_geometry[1]); for (size_t i = 2u; i < array_geometry.size(); ++i) { const Point pair_direction = PairDirection(array_geometry[i - 1], array_geometry[i]); if (!AreParallel(first_pair_direction, pair_direction)) { return rtc::Maybe(); } } return rtc::Maybe(first_pair_direction); } rtc::Maybe GetNormalIfPlanar(const std::vector& array_geometry) { RTC_DCHECK_GT(array_geometry.size(), 1u); const Point first_pair_direction = PairDirection(array_geometry[0], array_geometry[1]); Point pair_direction(0.f, 0.f, 0.f); size_t i = 2u; bool is_linear = true; for (; i < array_geometry.size() && is_linear; ++i) { pair_direction = PairDirection(array_geometry[i - 1], array_geometry[i]); if (!AreParallel(first_pair_direction, pair_direction)) { is_linear = false; } } if (is_linear) { return rtc::Maybe(); } const Point normal_direction = CrossProduct(first_pair_direction, pair_direction); for (; i < array_geometry.size(); ++i) { pair_direction = PairDirection(array_geometry[i - 1], array_geometry[i]); if (!ArePerpendicular(normal_direction, pair_direction)) { return rtc::Maybe(); } } return rtc::Maybe(normal_direction); } rtc::Maybe GetArrayNormalIfExists( const std::vector& array_geometry) { const rtc::Maybe direction = GetDirectionIfLinear(array_geometry); if (direction) { return rtc::Maybe(Point(direction->y(), -direction->x(), 0.f)); } const rtc::Maybe normal = GetNormalIfPlanar(array_geometry); if (normal && normal->z() < kMaxDotProduct) { return normal; } return rtc::Maybe(); } Point AzimuthToPoint(float azimuth) { return Point(std::cos(azimuth), std::sin(azimuth), 0.f); } } // namespace webrtc