CGR Localization
 All Classes Namespaces Files Functions Variables Macros Pages
vector_map.cpp
Go to the documentation of this file.
1 //========================================================================
2 // This software is free: you can redistribute it and/or modify
3 // it under the terms of the GNU Lesser General Public License Version 3,
4 // as published by the Free Software Foundation.
5 //
6 // This software is distributed in the hope that it will be useful,
7 // but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // GNU Lesser General Public License for more details.
10 //
11 // You should have received a copy of the GNU Lesser General Public License
12 // Version 3 in the file COPYING that came with this distribution.
13 // If not, see <http://www.gnu.org/licenses/>.
14 //========================================================================
20 //========================================================================
21 
22 #include "vector_map.h"
23 
24 //============================================================================================
25 
26 bool ctxVectorMapErrorOccurred = false;
27 
28 bool VectorMap::loadMap(const char* name, bool usePreRender)
29 {
30  static const bool debug = false;
31  static const bool debugBitmap = false;
32  static const bool debugVector = false;
33 
34  char vectorFile[4096];
35  char renderFile[4096];
36  FILE * pFile;
37 
38  mapName = string(name);
39 
40  snprintf(vectorFile, 4095, "%s/%s/%s_vector.txt",mapsFolder.c_str(),name,name);
41  snprintf(renderFile, 4095, "%s/%s/%s_render.dat",mapsFolder.c_str(),name,name);
42  if(debug) printf("Loading map: %s\n",name);
43 
44  //Read Vector data
45  if(debug) printf("Loading vector map from %s\n",vectorFile);
46  pFile = fopen (vectorFile,"r");
47  if(pFile==NULL){
48  char buf[1024];
49  snprintf(buf, 1023, "Unable to load vector file %s!",vectorFile);
50  TerminalWarning(buf);
51  return false;
52  }
53  float x1,y1,x2,y2;
54  minX = minY = FLT_MAX;
55  maxX = maxY = -FLT_MAX;
56  lines.clear();
57  while(fscanf(pFile,"%f,%f,%f,%f",&x1,&y1,&x2,&y2)==4){
58  if(debugVector) printf("Line%d: <%f %f> <%f %f>\n",(int)lines.size(),x1,y1,x2,y2);
59  minX = min(minX,x1);
60  minX = min(minX,x2);
61  minY = min(minY,y1);
62  minY = min(minY,y2);
63  maxX = max(maxX,x1);
64  maxX = max(maxX,x2);
65  maxY = max(maxY,y1);
66  maxY = max(maxY,y2);
67  vector2f p0(x1,y1);
68  vector2f p1(x2,y2);
69 
70  lines.push_back(line2f(p0,p1));
71  lines.at(lines.size()-1).calcValues();
72  }
73  if(debug) printf("%d lines loaded into vector map\n",(int)lines.size());
74  if(debug) printf("Extents: %.3f,%.3f : %.3f,%.3f\n",minX, minY, maxX, maxY);
75  fclose(pFile);
76 
77  //Read Pre-Render data
78  preRenderExists = false;
79  if(usePreRender){
80  pFile = fopen(renderFile, "r");
81  if(pFile==NULL){
82  char buf[1024];
83  snprintf(buf, 1023, "Unable to load pre-render file %s!",renderFile);
84  TerminalWarning(buf);
85  }else{
86  bool error = false;
87  int x=0, y=0;
88  int cnt = 0;
89  error = fread(&visListWidth,sizeof(unsigned int),1,pFile)!=1;
90  error = error || (fread(&visListHeight,sizeof(unsigned int),1,pFile)!=1);
91  error = error || (fread(&visListResolution,sizeof(double),1,pFile)!=1);
92  if(!error){
93  if(debug) printf("Pre-render size: %d x %d, resolution: %.3f\n",visListWidth, visListHeight, visListResolution);
94  visibilityList.resize(visListWidth);
95  for(int i=0; i<visListWidth; i++)
96  visibilityList[i].resize(visListHeight);
97  }
98  while(cnt<visListHeight*visListWidth && !error){
99  int size = 0;
100  error = fread(&x,sizeof(int),1,pFile)!=1;
101  error = error || (fread(&y,sizeof(int),1,pFile)!=1);
102  error = error || (fread(&size,sizeof(int),1,pFile)!=1);
103 
104  if(x<0 || y<0 || x>visListWidth-1 || y>visListHeight-1){
105  char msg[4096];
106  snprintf(msg, 4095, "Invalid loc (%d,%d) in pre-render file",x,y);
107  TerminalWarning(msg);
108  error = true;
109  }
110  visibilityList[x][y].resize(size);
111 
112  error = error || (fread(visibilityList[x][y].data(),sizeof(int),size,pFile) != size);
113 
114  if(!error && debug && ((y+1)*100)%visListHeight==0){
115  int progress = (y+1)*100/visListHeight;
116  printf("\rReading pre-render file... %3d%% ",progress);
117  fflush(stdout);
118  }
119  if(!error)
120  cnt++;
121  }
122  if(error){
123  char buf[1024];
124  snprintf(buf, 1023, "\nUnable to parse pre-render file %s",renderFile);
125  TerminalWarning(buf);
126  preRenderExists = false;
127  }else{
128  if(debug) printf("\nRead %d locations into visibility list\n",cnt);
129  preRenderExists = true;
130  }
131  }
132  }
133 
134  if(debug) printf("Done loading map\n\n");
135  return true;
136 }
137 
138 
139 VectorMap::VectorMap(const char* name, const char* _mapsFolder, bool usePreRender)
140 {
141  mapsFolder=string(_mapsFolder);
142  loadMap(name, usePreRender);
143  //initOpenGL();
144 }
145 
146 VectorMap::~VectorMap()
147 {
148 }
149 
150 std::vector< int >* VectorMap::getVisibilityList(float x, float y)
151 {
152  int xInd = bound((x-minX)/visListResolution,0.0,visListWidth-1.0);
153  int yInd = bound((y-minY)/visListResolution,0.0,visListHeight-1.0);
154  return &visibilityList[xInd][yInd];
155 }
156 
157 vector<float> VectorMap::getRayCast(vector2f loc, float angle, float da, int numRays, float minRange, float maxRange)
158 {
159  static const bool UsePreRender = true;
160  float intervals = numRays - 1.0;
161  float a0 = angle - 0.5*intervals*da;
162  float a1 = angle + 0.5*intervals*da;
163  vector<float> rayCast;
164  rayCast.clear();
165  vector< int >* visibilityList;
166 
167  for(float a=a0; a<a1; a += da){
168  float ray = maxRange;
169  if(preRenderExists && UsePreRender){
170  visibilityList = getVisibilityList(loc);
171  for(unsigned int i=0; i<visibilityList->size(); i++){
172  int lineIndex = visibilityList->at(i);
173  float curRay = maxRange;
174  if(lines[lineIndex].intersects((vector2f)loc,(float)a)){
175  line2f &l = lines[lineIndex];
176  //curRay = l.distFromLine1((vector2f)loc,(double)a, false);
177  {
178  vector2f heading;
179  heading.heading(a);
180  if(l.intersects(loc,heading,true)){
181  float sinTheta = l.Dir().cross(heading.norm());
182  curRay = fabs(l.Perp().dot(loc-l.P0())/sinTheta);
183  }else{
184  curRay = NAN;
185  }
186  }
187  if(curRay<0.0){
188  TerminalWarning("Ray Cast Fail!");
189  printf("line: %.3f,%.3f : %.3f,%.3f loc:%.3f,%.3f a:%.1f\u00b0 curRay:%f\n",V2COMP(lines[lineIndex].P0()),V2COMP(lines[lineIndex].P1()),V2COMP(loc),DEG(a),curRay);
190  fflush(stdout);
191  while(1){
192  Sleep(0.05);
193  }
194  //exit(0);
195  //alarm(1);
196  }
197  ray = min(ray, curRay);
198  }
199  }
200  }else{
201  /*
202  for(unsigned int i=0; i<lines.size(); i++){
203  if(lines[i].intersects(loc,a))
204  ray = min(ray, lines[i].distFromLine1((vector2f)loc,(double)a, false));
205  }
206  */
207  vector<int> sceneLines = getSceneLines(loc, maxRange);
208  for(unsigned int i=0; i<sceneLines.size(); i++){
209  if(lines[sceneLines[i]].intersects(loc,a)){
210  ray = min(ray, lines[sceneLines[i]].distFromLine1((vector2f)loc,(float)a, false));
211  }
212  }
213 
214  }
215  rayCast.push_back(ray);
216  }
217  return rayCast;
218 }
219 
220 int VectorMap::getLineCorrespondence(vector2f loc, float angle, float minRange, float maxRange, const std::vector< int >& visibilityList)
221 {
222  vector2f loc1, loc2, dir;
223  dir.heading(angle);
224  loc1 = loc + minRange*dir;
225  loc2 = loc + maxRange*dir;
226 
227  vector2f p = loc2;
228  int bestLine = -1;
229  for(unsigned int i=0; i<visibilityList.size(); i++){
230  int lineIndex = visibilityList[i];
231  if(!lines[lineIndex].intersects(loc1,loc2,false,false,true))
232  continue;
233 
234  vector2f p2 = lines[lineIndex].intersection(loc1,loc2,false,false);
235  if( (p2-loc).sqlength()<(p-loc).sqlength()){
236  p = p2;
237  bestLine = lineIndex;
238  }
239  }
240  return bestLine;
241 }
242 
243 vector<int> VectorMap::getRayToLineCorrespondences(vector2f loc, float angle, float a0, float a1, const vector<vector2f> pointCloud, float minRange, float maxRange, bool analytical, vector<line2f> *lines )
244 {
245  //FunctionTimer ft(__FUNCTION__);
246  static const bool UsePreRender = true;
247 
248  vector<int> correspondences;
249  correspondences.clear();
250  vector<int> locVisibilityList;
251  if(UsePreRender && preRenderExists)
252  locVisibilityList = *getVisibilityList(loc);
253  else
254  getSceneLines(loc,maxRange);
255 
256  if(analytical && lines!=NULL){
257  *lines = sceneRender(loc, a0, a1);
258  vector<LineSegment> segments = sortLineSegments(loc,*lines);
259  float rotMat1[4] = {cos(angle), -sin(angle), sin(angle), cos(angle)};
260  vector2f p(0.0,0.0);
261  correspondences.resize(pointCloud.size());
262  for(int i=0; i<pointCloud.size(); i++){
263  p = pointCloud[i];
264  p.set(p.x*rotMat1[0] + p.y*rotMat1[1], p.x*rotMat1[2] + p.y*rotMat1[3]);
265  int correspondence = -1;
266 
267  for(int j=0; j<segments.size() && correspondence<0; j++){
268  if(segments[j].v0.cross(p)>=0.0f && segments[j].v1.cross(p)<=0.0f)
269  correspondence = segments[j].index;
270  }
271  correspondences[i] = correspondence;
272  }
273  }else{
274  for(int i=0; i<pointCloud.size(); i++){
275  float curAngle = angle_mod(pointCloud[i].angle() + angle);
276  correspondences.push_back(getLineCorrespondence(loc,curAngle,minRange, maxRange, locVisibilityList));
277  }
278  }
279  return correspondences;
280 }
281 
282 vector<int> VectorMap::getRayToLineCorrespondences(vector2f loc, float a0, float a1, float da, float minRange, float maxRange)
283 {
284  //FunctionTimer ft(__PRETTY_FUNCTION__);
285  vector<int> correspondences;
286  correspondences.clear();
287  vector<int> locVisibilityList;
288  if(preRenderExists)
289  locVisibilityList = *getVisibilityList(loc);
290  else
291  locVisibilityList = getSceneLines(loc,maxRange);
292  for(float a=a0; a<a1; a += da){
293  correspondences.push_back(getLineCorrespondence(loc,a,minRange, maxRange, locVisibilityList));
294  }
295  return correspondences;
296 }
297 
298 vector< VectorMap::LineSegment > VectorMap::sortLineSegments(vector2f& loc, vector< line2f >& lines)
299 {
300  static const float eps = RAD(0.001);
301  vector< VectorMap::LineSegment > segments;
302  segments.clear();
303  for(unsigned int i=0; i<lines.size(); i++){
304  float a0 = angle_pos((lines[i].P0()-loc).angle());
305  float a1 = angle_pos((lines[i].P1()-loc).angle());
306  if((lines[i].P0()-loc).cross(lines[i].P1()-loc)<0.0)
307  swap(a0,a1);
308  LineSegment curSegment;
309  curSegment.a0 = a0;
310  curSegment.a1 = a1;
311  curSegment.index = i;
312  curSegment.v0.heading(a0);
313  curSegment.v1.heading(a1);
314 
315  if(segments.size()<1){
316  segments.push_back(curSegment);
317  continue;
318  }
319 
320  //Special case: line intersects the x axis, so curSegment MUST be the first segment
321  if(a0>a1){
322  segments.insert(segments.begin(), curSegment);
323  continue;
324  }
325  unsigned int j=0;
326  bool found = false;
327  for(; j<segments.size()-1 && !found; j++){
328  if( segments[j].a1<=a0+eps && segments[j+1].a0>=a1-eps )
329  found = true;
330  }
331 
332  if(found && j<segments.size())
333  segments.insert(segments.begin()+j,curSegment);
334  else
335  segments.push_back(curSegment);
336  }
337 
338  if(segments.size()>0){
339  if(segments[0].a0>segments[0].a1){
340  LineSegment curSegment;
341  curSegment.a0 = segments[0].a0;
342  curSegment.a1 = M_2PI;
343  curSegment.index = segments[0].index;
344  segments[0].a0 = 0.0;
345  segments.push_back(curSegment);
346  }
347  }
348 
349  return segments;
350 }
351 
352 vector<int> VectorMap::getRayToLineCorrespondences(vector2f loc, float angle, float da, int numRays, float minRange, float maxRange, bool analytical, vector< line2f > *lines)
353 {
354  //FunctionTimer ft("getRayToLineCorrespondences");
355  float intervals = numRays - 1.0;
356  float a0 = angle - 0.5*intervals*da;
357  float a1 = angle + 0.5*intervals*da;
358 
359  if(analytical && (lines!=NULL)){
360  //FunctionTimer ft("Analytic Render");
361  a0 = angle_pos(a0);
362  *lines = sceneRender(loc,a0,a1);
363  vector< VectorMap::LineSegment > segments = sortLineSegments(loc,*lines);
364  vector<int> correspondences;
365  correspondences.clear();
366  for(unsigned int i=0; i<numRays; i++){
367  correspondences.push_back(-1);
368  }
369  int maxScanRays = floor((float)M_2PI/da);
370 
371  for(unsigned int i=0; i<segments.size(); i++){
372  float aStart = segments[i].a0;
373  float aEnd = segments[i].a1;
374  if(aEnd<aStart)
375  aEnd += M_2PI;
376  int index = ceil( (float) (aStart - a0)/da );
377  if(index<0)
378  index+=maxScanRays;
379  for(float a = aStart; a<aEnd; a+=da, index++){
380  int j = index%maxScanRays;
381  if(j<numRays){
382  correspondences[j] = segments[i].index;
383  }
384  }
385  }
386 
387  return correspondences;
388  }else
389  return getRayToLineCorrespondences(loc,a0,a1,da,minRange,maxRange);
390 }
391 
392 std::vector<int> VectorMap::getSceneLines(vector2f loc, float maxRange)
393 {
394  static const float eps = 1e-6;
395  vector<int> linesList, sceneLines;
396  vector<line2f> tmpList;
397  linesList.clear();
398  sceneLines.clear();
399 
400  for(unsigned int i=0; i<lines.size(); i++){
401  if(lines[i].closestDistFromLine(loc, true)<maxRange)
402  linesList.push_back(i);
403  }
404  for(unsigned int i=0; i<linesList.size(); i++){
405  line2f curLine = lines[linesList[i]];
406  //Check if any part of curLine is unoccluded by present list of lines, as seen from loc
407  for(unsigned int j=0;j<linesList.size() && curLine.Length()>=eps; j++){
408  if(i==j)
409  continue;
410  if(lines[linesList[j]].Length()<eps)
411  continue;
412  trimOcclusion(loc, lines[linesList[j]], curLine,tmpList);
413  }
414  if( curLine.Length()>eps ){ //At least part of curLine is unoccluded
415  sceneLines.push_back(linesList[i]);
416  }
417  }
418  return sceneLines;
419 }
420 
421 inline float cross(const Eigen::Vector3f &v1, const Eigen::Vector3f &v2)
422 {
423  return v1.cross(v2).z();
424 }
425 
426 static const float eps = 1e-5;
427 
428 inline bool lineIntersectsLine(const Eigen::Vector3f &l1_p0, const Eigen::Vector3f &l1_p1, const Eigen::Vector3f &l1_dir,
429  const Eigen::Vector3f &l2_p0, const Eigen::Vector3f &l2_p1, const Eigen::Vector3f &l2_dir)
430 {
431  return cross(l1_dir,l2_p0-l1_p0)*cross(l1_dir,l2_p1-l1_p0)<eps && cross(l2_dir,l1_p0-l2_p0)*cross(l2_dir,l1_p1-l2_p0)<eps;
432 }
433 
434 inline bool lineIntersectsRay(const Eigen::Vector3f &l1_p0, const Eigen::Vector3f &l1_p1,
435  const Eigen::Vector3f &r_p0, const Eigen::Vector3f &r_dir)
436 {
437  return cross(l1_p0-r_p0,r_dir)*cross(l1_p1-r_p0,r_dir)<eps;
438 }
439 
440 inline vector2f tovector2f(const Eigen::Vector3f &v)
441 {
442  return vector2f(v.x(),v.y());
443 }
444 
445 inline Eigen::Vector3f lineIntersectionLine(const Eigen::Vector3f &l1_p0, const Eigen::Vector3f &l1_p1, const Eigen::Vector3f &l1_dir,
446  const Eigen::Vector3f &l2_p0, const Eigen::Vector3f &l2_p1, const Eigen::Vector3f &l2_dir)
447 {
448  float den = cross(l2_dir, l1_dir);
449  float ua = cross(l1_p0-l2_p0, l1_dir)/den;
450  return l2_p0 + ua*l2_dir;
451 }
452 
453 inline Eigen::Vector3f lineIntersectionLine(const Eigen::Vector3f &l1_p0, const Eigen::Vector3f &l1_p1,
454  const Eigen::Vector3f &l2_p0, const Eigen::Vector3f &l2_p1)
455 {
456  Eigen::Vector3f l1_dir(l1_p1-l1_p0), l2_dir(l2_p1-l2_p0);
457  float den = cross(l2_dir, l1_dir);
458  float ua = cross(l1_p0-l2_p0, l1_dir)/den;
459  return l2_p0 + ua*l2_dir;
460 }
461 
462 void VectorMap::trimOcclusion2(vector2f& loc_g, line2f& line1, line2f& line2, vector< line2f >& sceneLines)
463 {
464  using namespace Eigen;
465  // Checks if any part of line2 is occluded by line1 when seen from loc, and if so, line2 is trimmed accordingly, adding sub-lines to sceneLines if necessary
466  static const float eps = 1e-4;
467  static const float sqeps = 1e-8;
468  if(line1.Length()<eps || line2.Length()<eps)
469  return;
470 
471  Vector3f loc(V2COMP(loc_g),0);
472  Vector3f l1_p0(V2COMP(line1.P0()),0);
473  Vector3f l1_p1(V2COMP(line1.P1()),0);
474  Vector3f l1_dir(l1_p1-l1_p0);
475  Vector3f l1_r0(l1_p0-loc);
476  Vector3f l1_r1(l1_p1-loc);
477  Vector3f l2_p0(V2COMP(line2.P0()),0);
478  Vector3f l2_p1(V2COMP(line2.P1()),0);
479  Vector3f l2_dir(l2_p1-l2_p0);
480  Vector3f l2_r0(l2_p0-loc);
481  Vector3f l2_r1(l2_p1-loc);
482 
483  vector2f l1_p0_g(line1.P0());
484  vector2f l1_p1_g(line1.P1());
485  vector2f l2_p0_g(line2.P0());
486  vector2f l2_p1_g(line2.P1());
487 
488  //Ensure that r0 vector to r1 vector is in the positive right-handed order
489  if( cross(l1_r0,l1_r1)<0.0 ){
490  swap(l1_r0,l1_r1);
491  swap(l1_p0,l1_p1);
492  }
493  if( cross(l2_r0,l2_r1)<0.0 ){
494  swap(l2_r0,l2_r1);
495  swap(l2_p0,l2_p1);
496  }
497 
498  if( (cross(l1_r0, l2_r0)>=0.0 && cross(l1_r1, l2_r0)>=0.0) || (cross(l2_r1, l1_r0)>=0.0 && cross(l2_r1, l2_r1)>=0.0) )
499  return; //No Line interaction
500  bool intersects, rayOcclusion1, rayOcclusion2;
501 
502  //completeOcclusion = line1.intersects(loc,l2_p0,false, false, true) && line1.intersects(loc,l2_p1,false, false, true);
503 
504  //intersects = line2.intersects(line1,false,false,false);
505  //rayOcclusion1 = line2.intersects(loc,l1_r0, false); // The semi-infinite ray from loc and passing through line1.p0 intersects line2
506  //rayOcclusion2 = line2.intersects(loc,l1_r1, false); // The semi-infinite ray from loc and passing through line1.p1 intersects line2
507 
508  intersects = lineIntersectsLine(l1_p0,l1_p1,l1_dir, l2_p0,l2_p1,l2_dir);
509  rayOcclusion1 = lineIntersectsRay(l2_p0,l2_p1, loc,l1_r0); // The semi-infinite ray from loc and passing through line1.p0 intersects line2
510  rayOcclusion2 = lineIntersectsRay(l2_p0,l2_p1, loc,l1_r1); // The semi-infinite ray from loc and passing through line1.p1 intersects line2
511 
512  Vector3f p, mid;
513  if(intersects){
514  //line1 and line2 intersect
515  //mid = line2.intersection(line1,false,false);
516  mid = lineIntersectionLine(l1_p0,l1_p1,l1_dir, l2_p0,l2_p1,l2_dir);
517  if( cross((l1_p0-mid), l2_p0-mid) > 0.0){
518  //Delete the right hand part of line2
519  line2 = line2f(tovector2f(mid),l2_p1_g);
520  //line2f l(tovector2f(mid), l2_p0_g);
521  //if(l.intersects(loc,l1_r0,false)){
522  if(lineIntersectsRay(mid,l2_p0, loc, l1_r0)){
523  //p = l.intersection(loc,l1_p0,false, true);
524  p = lineIntersectionLine(mid, l2_p0, loc,l1_p0);
525  if((l2_p0-p).squaredNorm()>sqeps) //Part of the right hand part of line2 extends beyond line1, it may still be visible
526  sceneLines.push_back(line2f(l2_p0_g, tovector2f(p)));
527  }
528  }else{
529  //Delete the left hand part of line2
530  line2 = line2f(l2_p0_g,tovector2f(mid));
531  //line2f l(mid, l2_p1);
532  //if(l.intersects(loc,l1_r1,false)){
533  if(lineIntersectsRay(mid,l2_p1, loc, l1_r1)){
534  //p = l.intersection(loc,l1_p1,false, true);
535  p = lineIntersectionLine(mid, l2_p0, loc,l1_p1);
536  if((l2_p1-p).squaredNorm()>sqeps) //Part of the left hand part of line2 extends beyond line1, it may still be visible
537  sceneLines.push_back(line2f(l2_p1_g, tovector2f(p)));
538  }
539  }
540  }else{
541  bool completeOcclusion = line1.intersects(line2f(loc_g,l2_p0_g),false, false, true) && line1.intersects(line2f(loc_g,l2_p1_g),false, false, true);
542 
543  bool occlusion0 = rayOcclusion1 && !line2.intersects(line2f(loc_g,l1_p0_g), false, false, false); // line1.p0 is in front of, and occludes line2
544  bool occlusion1 = rayOcclusion2 && !line2.intersects(line2f(loc_g,l1_p1_g), false, false, false); // line1.p1 is in front of, and occludes line2
545  if(completeOcclusion){
546  //Trim the line to zero length
547  line2 = line2f(0.0,0.0,0.0,0.0);
548  }else if(occlusion0 && occlusion1){
549  //line2 is partially occluded in the middle by line1. Break up into 2 segments, make line2 one segment, push back the other segment to the sceneLines list
550  //mid = line2.intersection(line2f(loc,l1_p0),false, true);
551  mid = lineIntersectionLine(l2_p0,l2_p1,l2_dir,loc,l1_p0,l1_r0);
552  // newLine2 = the unoccluded part of line2 at its right hand end
553  line2f newLine2(l2_p0_g,tovector2f(mid));
554  //mid = line2.intersection(line2f(loc_g,l1_p1_g),false, true);
555  mid = lineIntersectionLine(l2_p0,l2_p1,l2_dir,loc,l1_p1,l1_r1);
556  line2 = newLine2;
557  // save the unoccluded part of line2 at its left hand end, if any
558  if((mid-l2_p1).squaredNorm()>sqeps)
559  sceneLines.push_back(line2f(tovector2f(mid),l2_p1_g));
560  }else if(occlusion0){
561  //The left hand end of line2 is occluded, trim it
562  //vector2f mid = line2.intersection(loc,l1_p0,false, true);
563  mid = lineIntersectionLine(l2_p0,l2_p1,l2_dir,loc,l1_p0,l1_r0);
564  line2 = line2f(l2_p0_g,tovector2f(mid));
565  }else if(occlusion1){
566  //The right hand end of line2 is occluded, trim it
567  //vector2f mid = line2.intersection(line2f(loc,l1_p1),false, true);
568  mid = lineIntersectionLine(l2_p0,l2_p1,l2_dir,loc,l1_p1,l1_r1);
569  line2 = line2f(tovector2f(mid),l2_p1_g);
570  }
571  }
572 }
573 
574 void VectorMap::trimOcclusion(vector2f& loc, line2f& line1, line2f& line2, vector< line2f >& sceneLines)
575 {
576  // Checks if any part of line2 is occluded by line1 when seen from loc, and if so, line2 is trimmed accordingly, adding sub-lines to sceneLines if necessary
577  static const float eps = 1e-4;
578  static const float sqeps = 1e-8;
579  if(line1.Length()<eps || line2.Length()<eps)
580  return;
581 
582  vector2f l1_p0 = line1.P0();
583  vector2f l1_p1 = line1.P1();
584  vector2f l1_r0 = l1_p0-loc;
585  vector2f l1_r1 = l1_p1-loc;
586  vector2f l2_p0 = line2.P0();
587  vector2f l2_p1 = line2.P1();
588  vector2f l2_r0 = l2_p0-loc;
589  vector2f l2_r1 = l2_p1-loc;
590 
591  //Ensure that r0 vector to r1 vector is in the positive right-handed order
592  if( l1_r0.cross(l1_r1)<0.0 ){
593  swap(l1_r0,l1_r1);
594  swap(l1_p0,l1_p1);
595  }
596  if( l2_r0.cross(l2_r1)<0.0 ){
597  swap(l2_r0,l2_r1);
598  swap(l2_p0,l2_p1);
599  }
600 
601  if( (l1_r0.cross(l2_r0)>=0.0 && l1_r1.cross(l2_r0)>=0.0) || (l2_r1.cross(l1_r0)>=0.0 && l2_r1.cross(l2_r1)>=0.0) )
602  return; //No Line interaction
603  bool intersects, rayOcclusion1, rayOcclusion2;
604 
605  //completeOcclusion = line1.intersects(loc,l2_p0,false, false, true) && line1.intersects(loc,l2_p1,false, false, true);
606 
607  intersects = line2.intersects(line1,false,false,false);
608  rayOcclusion1 = line2.intersects(loc,l1_r0, false); // The semi-infinite ray from loc and passing through line1.p0 intersects line2
609  rayOcclusion2 = line2.intersects(loc,l1_r1, false); // The semi-infinite ray from loc and passing through line1.p1 intersects line2
610 
611  vector2f p;
612  if(intersects){
613  //line1 and line2 intersect
614  vector2f mid = line2.intersection(line1,false,false);
615  if( (l1_p0-mid).cross(l2_p0-mid) > 0.0){
616  //Delete the right hand part of line2
617  line2 = line2f(mid,l2_p1);
618  line2f l(mid, l2_p0);
619  if(l.intersects(loc,l1_r0,false)){
620  p = l.intersection(loc,l1_p0,false, true);
621  if((l2_p0-p).sqlength()>sqeps) //Part of the right hand part of line2 extends beyond line1, it may still be visible
622  sceneLines.push_back(line2f(l2_p0, p));
623  }
624  }else{
625  //Delete the left hand part of line2
626  line2 = line2f(l2_p0,mid);
627  line2f l(mid, l2_p1);
628  if(l.intersects(loc,l1_r1,false)){
629  p = l.intersection(loc,l1_p1,false, true);
630  if((l2_p1-p).sqlength()>sqeps) //Part of the left hand part of line2 extends beyond line1, it may still be visible
631  sceneLines.push_back(line2f(l2_p1, p));
632  }
633  }
634  }else{
635  bool completeOcclusion = line1.intersects(line2f(loc,l2_p0),false, false, true) && line1.intersects(line2f(loc,l2_p1),false, false, true);
636 
637  bool occlusion0 = rayOcclusion1 && !line2.intersects(line2f(loc,l1_p0), false, false, false); // line1.p0 is in front of, and occludes line2
638  bool occlusion1 = rayOcclusion2 && !line2.intersects(line2f(loc,l1_p1), false, false, false); // line1.p1 is in front of, and occludes line2
639  if(completeOcclusion){
640  //Trim the line to zero length
641  line2 = line2f(0.0,0.0,0.0,0.0);
642  }else if(occlusion0 && occlusion1){
643  //line2 is partially occluded in the middle by line1. Break up into 2 segments, make line2 one segment, push back the other segment to the sceneLines list
644  vector2f mid;
645  mid = line2.intersection(line2f(loc,l1_p0),false, true);
646  // newLine2 = the unoccluded part of line2 at its right hand end
647  line2f newLine2(l2_p0,mid);
648  mid = line2.intersection(line2f(loc,l1_p1),false, true);
649  line2 = newLine2;
650  // save the unoccluded part of line2 at its left hand end, if any
651  if((mid-l2_p1).sqlength()>sqeps)
652  sceneLines.push_back(line2f(mid,l2_p1));
653  }else if(occlusion0){
654  //The left hand end of line2 is occluded, trim it
655  vector2f mid = line2.intersection(loc,l1_p0,false, true);
656  line2 = line2f(l2_p0,mid);
657  }else if(occlusion1){
658  //The right hand end of line2 is occluded, trim it
659  vector2f mid = line2.intersection(line2f(loc,l1_p1),false, true);
660  line2 = line2f(mid,l2_p1);
661  }
662  }
663 }
664 
665 vector<line2f> VectorMap::sceneRender(vector2f loc, float a0, float a1)
666 {
667  //FunctionTimer ft("Scene Render");
668  static const float eps = 0.001;
669  static const float MinRange = 0.03;
670  static const float MaxRange = 5.0;
671  static const unsigned int MaxLines = 200;
672 
673  vector2f leftMargin, rightMargin;
674  rightMargin.heading(a0);
675  leftMargin.heading(a1);
676  bool obtuseView = rightMargin.cross(leftMargin)<=0.0;
677 
678  vector<line2f> scene, sceneCleaned;
679  vector<line2f> linesList;
680  vector<int>* locVisibilityList;
681 
682  scene.clear();
683  sceneCleaned.clear();
684  linesList.clear();
685 
686  if(preRenderExists){
687  locVisibilityList = getVisibilityList(loc);
688  }else{
689  locVisibilityList = new vector<int>;
690  *locVisibilityList = getSceneLines(loc,MaxRange);
691  }
692  for(unsigned int i=0; i<locVisibilityList->size(); i++){
693  linesList.push_back(lines[locVisibilityList->at(i)]);
694  }
695  unsigned int i, j;
696  for(i=0; i<linesList.size() && i<MaxLines; i++){
697  line2f curLine = linesList[i];
698  //Check if any part of curLine is unoccluded by present list of lines, as seen from loc
699  for(j=0;j<scene.size() && curLine.Length()>=eps; j++){
700  if(scene[j].Length()<eps)
701  continue;
702  trimOcclusion(loc, scene[j], curLine,linesList);
703  }
704 
705  if( curLine.Length()>eps ){ //At least part of curLine is unoccluded
706  for(j=0; j<scene.size(); j++){
707  if(scene[j].Length()<eps)
708  continue;
709  trimOcclusion(loc, curLine, scene[j],linesList);
710  }
711  //add the visible part of curLine
712  scene.push_back(curLine);
713  }
714  }
715 
716  if(linesList.size()>=MaxLines){
717  char buf[2048];
718  sprintf(buf,"Runaway Analytic Scene Render at %.30f,%.30f, %.3f : %.3f\u00b0",V2COMP(loc),DEG(a0),DEG(a1));
719  TerminalWarning(buf);
720  }
721  for(i=0; i<scene.size(); i++){
722  if(scene[i].Length()>eps)
723  sceneCleaned.push_back(scene[i]);
724  }
725  return sceneCleaned;
726 }
vector< int > getRayToLineCorrespondences(vector2f loc, float angle, float a0, float a1, const std::vector< vector2f > pointCloud, float minRange, float maxRange, bool analytical=false, vector< line2f > *lines=0)
Get lines (for each ray) which intersect first the rays starting at angles a0 to a1, at increments of da.
C++ Interfaces: VectorMap, LineSection.
unsigned int visListWidth
size of the visibilityList array
Definition: vector_map.h:62
Definition: line.h:33
vector< int > * getVisibilityList(float x, float y)
Get Visibility list for specified location.
Definition: vector_map.cpp:150
int getLineCorrespondence(vector2f loc, float angle, float minRange, float maxRange, const std::vector< int > &visibilityList)
Get line which intersects first the given ray first.
Definition: vector_map.cpp:220
vector< line2f > sceneRender(vector2f loc, float a0=0.0, float a1=M_2PI)
Perform an analytical scene render. i.e. Generate a list of lines visible from loc, and the start and end angles subtended by them.
Definition: vector_map.cpp:665
GVector::vector2d< num > intersection(Line2d< num > l1, bool extendL0, bool extendL1)
Return the point of intersection of two lines.
void trimOcclusion(vector2f &loc, line2f &line1, line2f &line2, vector< line2f > &sceneLines)
Checks if any part of line2 is occluded by line1 when seen from loc, and if so, line2 is trimmed acco...
Definition: vector_map.cpp:574
num cross(const vector2d< num > p) const MustUseResult
return z component of 3D cross product on 2D vectors. right handed.
Definition: gvector.h:968
vector2d< num > norm() const MustUseResult
return a unit length vector in the same direction
Definition: gvector.h:892
bool intersects(Line2d< num > l1, bool extendL0, bool extendL1, bool touch)
Return true if the line l1 intersects this line. If touch==true then touching counts as intersection...
bool loadMap(const char *name, bool usePreRender)
Load map by name.
Definition: vector_map.cpp:28
float minX
Map Extents.
Definition: vector_map.h:58
double visListResolution
number of meters per cell in visibilityList array
Definition: vector_map.h:60
void heading(num angle)
make a unit vector at given angle
Definition: gvector.h:802
vector< int > getSceneLines(vector2f loc, float maxRange)
Get a set of lines which are visible from loc.
Definition: vector_map.cpp:392
vector< float > getRayCast(vector2f loc, float angle, float da, int numRays, float minRange, float maxRange)
Get ray cast from vector map at given location and angle, as specified by center angle, angle increment (da), and numRays to scan.
Definition: vector_map.cpp:157