EMANE  1.2.1
antennapattern.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 - Adjacent Link LLC, Bridgewater, New Jersey
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * * Neither the name of Adjacent Link LLC nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "antennapattern.h"
36 
37 #include <libxml/parser.h>
38 
39 EMANE::AntennaPattern::AntennaPattern(const std::string & sAntennaPatternURI,
40  const std::string sSubRootName,
41  double dMissingValue):
42  dMissingValue_{dMissingValue}
43 {
44  xmlParserCtxtPtr pContext{xmlNewParserCtxt()};
45 
46  if(!pContext)
47  {
48  throw AntennaProfileException{"Unable to create a parser context"};
49  }
50 
51  xmlDocPtr pDoc{xmlCtxtReadFile(pContext,sAntennaPatternURI.c_str(),nullptr,XML_PARSE_DTDVALID)};
52 
53  if(!pDoc)
54  {
55 
56  xmlFreeParserCtxt(pContext);
57  throw makeException<AntennaProfileException>("Unable to read %s",sAntennaPatternURI.c_str());
58  }
59 
60  if(pContext->valid == false)
61  {
62  xmlFreeDoc(pDoc);
63  xmlFreeParserCtxt(pContext);
64  throw makeException<AntennaProfileException>("Validation failure %s",sAntennaPatternURI.c_str());
65  }
66 
67  xmlNodePtr pRoot{xmlDocGetRootElement(pDoc)};
68 
69  if(!pRoot)
70  {
71  xmlFreeDoc(pDoc);
72  xmlFreeParserCtxt(pContext);
73  throw makeException<AntennaProfileException>("Invalid document root %s",
74  sAntennaPatternURI.c_str());
75  }
76 
77 
78  for(xmlNodePtr pNode = pRoot->children; pNode; pNode = pNode->next)
79  {
80  if(pNode->type == XML_ELEMENT_NODE)
81  {
82  if(!xmlStrcmp(pNode->name,BAD_CAST sSubRootName.c_str()))
83  {
84  std::int16_t i16ElevationRangeMax{};
85 
86  for(xmlNodePtr pElevationNode = pNode->children;
87  pElevationNode;
88  pElevationNode = pElevationNode->next)
89  {
90  if(pElevationNode->type == XML_ELEMENT_NODE)
91  {
92  if(!xmlStrcmp(pElevationNode->name,BAD_CAST "elevation"))
93  {
94  xmlChar * pMin{xmlGetProp(pElevationNode,BAD_CAST "min")};
95 
96  std::int16_t i16ElevationMin =
97  EMANE::Utils::ParameterConvert(reinterpret_cast<const char *>(pMin)).toINT16();
98 
99  xmlFree(pMin);
100 
101  xmlChar * pMax{xmlGetProp(pElevationNode,BAD_CAST "max")};
102 
103  std::int16_t i16ElevationMax =
104  EMANE::Utils::ParameterConvert(reinterpret_cast<const char *>(pMax)).toINT16();
105 
106  xmlFree(pMax);
107 
108  if(i16ElevationMin > i16ElevationMax)
109  {
110  throw makeException<AntennaProfileException>("Bad entry %s: elevation [%hd,%hd] min > max",
111  sAntennaPatternURI.c_str(),
112  i16ElevationMin,
113  i16ElevationMax);
114  }
115 
116  if(i16ElevationRangeMax >= i16ElevationMin && !elevationBearingGainMap_.empty())
117  {
118  throw makeException<AntennaProfileException>("Bad entry %s: elevation [%hd,%hd] may may be"
119  " out of order or overlap with a previous elevation",
120  sAntennaPatternURI.c_str(),
121  i16ElevationMin,
122  i16ElevationMax);
123  }
124  else
125  {
126  i16ElevationRangeMax = i16ElevationMax;
127  }
128 
129  BearingGainMap * pBearingGainMap{new BearingGainMap};
130 
131  bearings_.push_back(std::unique_ptr<BearingGainMap>(pBearingGainMap));
132 
133  std::int16_t i16BearingRangeMax{};
134 
135  for(xmlNodePtr pBearingNode = pElevationNode->children;
136  pBearingNode;
137  pBearingNode = pBearingNode->next)
138  {
139  if(pBearingNode->type == XML_ELEMENT_NODE)
140  {
141  if(!xmlStrcmp(pBearingNode->name,BAD_CAST "bearing"))
142  {
143  xmlChar * pMin{xmlGetProp(pBearingNode,BAD_CAST "min")};
144 
145  std::int16_t i16BearingMin =
146  EMANE::Utils::ParameterConvert(reinterpret_cast<const char *>(pMin)).toINT16();
147 
148  xmlFree(pMin);
149 
150  xmlChar * pMax{xmlGetProp(pBearingNode,BAD_CAST "max")};
151 
152  std::int16_t i16BearingMax =
153  EMANE::Utils::ParameterConvert(reinterpret_cast<const char *>(pMax)).toINT16();
154 
155  xmlFree(pMax);
156 
157  if(i16BearingMin > i16BearingMax)
158  {
159  throw makeException<AntennaProfileException>("Bad entry %s: elevation [%hd,%hd] bearing [%hd,%hd] min > max",
160  sAntennaPatternURI.c_str(),
161  i16ElevationMin,
162  i16ElevationMax,
163  i16BearingMin,
164  i16BearingMax);
165  }
166 
167  if(i16BearingRangeMax >= i16BearingMin && !pBearingGainMap->empty())
168  {
169  throw makeException<AntennaProfileException>("Bad entry %s: elevation [%hd,%hd] bearing [%hd,%hd]"
170  " may be out of order or overlap with a previous bearing",
171  sAntennaPatternURI.c_str(),
172  i16ElevationMin,
173  i16ElevationMax,
174  i16BearingMin,
175  i16BearingMax);
176  }
177  else
178  {
179  i16BearingRangeMax = i16BearingMax;
180  }
181 
182  for(xmlNodePtr pGainNode = pBearingNode->children;
183  pGainNode;
184  pGainNode = pGainNode->next)
185  {
186  if(pGainNode->type == XML_ELEMENT_NODE)
187  {
188  if(!xmlStrcmp(pGainNode->name,BAD_CAST "gain"))
189  {
190  xmlChar * pGain{xmlGetProp(pGainNode,BAD_CAST "value")};
191 
192  double dGain =
193  EMANE::Utils::ParameterConvert(reinterpret_cast<const char *>(pGain)).toDouble();
194 
195  xmlFree(pGain);
196 
197  if(pBearingGainMap->find(i16BearingMin-1) == pBearingGainMap->end())
198  {
199  (*pBearingGainMap)[i16BearingMin-1] = dMissingValue_;
200  }
201 
202  (*pBearingGainMap)[i16BearingMax] = dGain;
203  }
204  }
205  }
206  }
207  }
208  }
209 
210  if(elevationBearingGainMap_.find(i16ElevationMin-1) == elevationBearingGainMap_.end())
211  {
212  elevationBearingGainMap_[i16ElevationMin-1] = nullptr;
213  }
214 
215  elevationBearingGainMap_[i16ElevationMax] = pBearingGainMap;
216  }
217  }
218  }
219  }
220  }
221  }
222 
223  xmlFreeDoc(pDoc);
224  xmlFreeParserCtxt(pContext);
225 }
226 
227 double EMANE::AntennaPattern::getGain(std::int16_t iBearing,std::int16_t iElevation) const
228 {
229  double dGain{dMissingValue_};
230 
231  // use 0 for bearing when 360
232  if(iBearing == 360)
233  {
234  iBearing = 0;
235  }
236 
237  const auto iter = elevationBearingGainMap_.lower_bound(iElevation);
238 
239  if(iter != elevationBearingGainMap_.end())
240  {
241  if(iter->second)
242  {
243  const auto bearingIter = iter->second->lower_bound(iBearing);
244 
245  if(bearingIter != iter->second->end())
246  {
247  dGain = bearingIter->second;
248  }
249  }
250  }
251 
252  return dGain;
253 }
double toDouble(double dMin=std::numeric_limits< double >::lowest(), double dMax=std::numeric_limits< double >::max()) const
double getGain(std::int16_t iBearing, std::int16_t iElevation) const
std::int16_t toINT16(std::int16_t i16Min=std::numeric_limits< std::int16_t >::min(), std::int16_t i16Max=std::numeric_limits< std::int16_t >::max()) const
AntennaPattern(const std::string &sAntennaPatternURI, const std::string sSubRootName, double dMissingValue)
Parameter conversion class with range checks.