/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file PolySolver.cpp14/// @author Jakub Sevcik (RICE)15/// @author Jan Prikryl (RICE)16/// @date 2019-12-0617///18//19/****************************************************************************/20#include <config.h>2122#include <math.h>23#include <cmath>24#include <limits>25#include <utils/geom/GeomHelper.h> // defines M_PI26#include "PolySolver.h"272829// ===========================================================================30// member method definitions31// ===========================================================================32std::tuple<int, double, double>33PolySolver::quadraticSolve(double a, double b, double c) {34// ax^2 + bx + c = 035// return only real roots36if (a == 0) {37//WRITE_WARNING(TL("The coefficient of the quadrat of x is 0. Please use the utility for a FIRST degree linear. No further action taken."));38if (b == 0) {39if (c == 0) {40return std::make_tuple(2, std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity());41} else {42return std::make_tuple(0, NAN, NAN);43}44} else {45return std::make_tuple(1, -c / b, NAN);46}47}4849if (c == 0) {50//WRITE_WARNING(TL("One root is 0. Now divide through by x and use the utility for a FIRST degree linear to solve the resulting equation for the other one root. No further action taken."));51return std::make_tuple(2, 0, -b / a);52}5354double disc, x1_real, x2_real ;55disc = b * b - 4 * a * c;5657if (disc > 0) {58// two different real roots59x1_real = (-b + sqrt(disc)) / (2 * a);60x2_real = (-b - sqrt(disc)) / (2 * a);61return std::make_tuple(2, x1_real, x2_real);62} else if (disc == 0) {63// a real root with multiplicity 264x1_real = (-b + sqrt(disc)) / (2 * a);65return std::make_tuple(1, x1_real, NAN);66} else {67// all roots are complex68return std::make_tuple(0, NAN, NAN);69}70}7172std::tuple<int, double, double, double>73PolySolver::cubicSolve(double a, double b, double c, double d) {74// ax^3 + bx^2 + cx + d = 075// return only real roots76if (a == 0) {77//WRITE_WARNING(TL("The coefficient of the cube of x is 0. Please use the utility for a SECOND degree quadratic. No further action taken."));78int numX;79double x1, x2;80std::tie(numX, x1, x2) = quadraticSolve(b, c, d);81return std::make_tuple(numX, x1, x2, NAN);82}83if (d == 0) {84//WRITE_WARNING(TL("One root is 0. Now divide through by x and use the utility for a SECOND degree quadratic to solve the resulting equation for the other two roots. No further action taken."));85int numX;86double x1, x2;87std::tie(numX, x1, x2) = quadraticSolve(a, b, c);88return std::make_tuple(numX + 1, 0, x1, x2);89}9091b /= a;92c /= a;93d /= a;9495double disc, q, r, dum1, s, t, term1, r13;96q = (3.0 * c - (b * b)) / 9.0;97r = -(27.0 * d) + b * (9.0 * c - 2.0 * (b * b));98r /= 54.0;99disc = q * q * q + r * r;100term1 = (b / 3.0);101102double x1_real, x2_real, x3_real;103if (disc > 0) { // One root real, two are complex104s = r + sqrt(disc);105s = s < 0 ? -cbrt(-s) : cbrt(s);106t = r - sqrt(disc);107t = t < 0 ? -cbrt(-t) : cbrt(t);108x1_real = -term1 + s + t;109term1 += (s + t) / 2.0;110x3_real = x2_real = -term1;111return std::make_tuple(1, x1_real, NAN, NAN);112}113// The remaining options are all real114else if (disc == 0) { // All roots real, at least two are equal.115r13 = r < 0 ? -cbrt(-r) : cbrt(r);116x1_real = -term1 + 2.0 * r13;117x3_real = x2_real = -(r13 + term1);118return std::make_tuple(2, x1_real, x2_real, NAN);119}120// Only option left is that all roots are real and unequal (to get here, q < 0)121else {122q = -q;123dum1 = q * q * q;124dum1 = acos(r / sqrt(dum1));125r13 = 2.0 * sqrt(q);126x1_real = -term1 + r13 * cos(dum1 / 3.0);127x2_real = -term1 + r13 * cos((dum1 + 2.0 * M_PI) / 3.0);128x3_real = -term1 + r13 * cos((dum1 + 4.0 * M_PI) / 3.0);129return std::make_tuple(3, x1_real, x2_real, x3_real);130}131}132133134/****************************************************************************/135136137