Esempio n. 1
0
void
insertSegment (SegmentTree * st, int n, Coord Y1, Coord Y2) {
    Coord discriminant;

    if (st->nodes[n].left >= Y1 && st->nodes[n].right <= Y2) {
        st->nodes[n].covered++;
    } else {
        assert (n < st->size / 2);
        discriminant = st->nodes[n * 2 + 1 /*right */ ].left;

        if (Y1 < discriminant) {
            insertSegment (st, n * 2, Y1, Y2);
        }

        if (discriminant < Y2) {
            insertSegment (st, n * 2 + 1, Y1, Y2);
        }
    }

    /* fixup area */
    st->nodes[n].area = (st->nodes[n].covered > 0) ?
                        (st->nodes[n].right - st->nodes[n].left) :
                        (n >= st->size / 2) ? 0 :
                        st->nodes[n * 2].area + st->nodes[n * 2 + 1].area;
}
Esempio n. 2
0
void Model::addSortedSegment(SegmentModel* m)
{
  insertSegment(m);

  // Add points if necessary
  // If there is an existing previous segment, its end point also exists
  auto createStartPoint = [&]() {
    auto pt = new PointModel{getStrongId(m_points), this};
    pt->setFollowing(m->id());
    pt->setPos(m->start());
    addPoint(pt);
    return pt;
  };
  auto createEndPoint = [&]() {
    auto pt = new PointModel{getStrongId(m_points), this};
    pt->setPrevious(m->id());
    pt->setPos(m->end());
    addPoint(pt);
    return pt;
  };

  if (!m->previous())
  {
    createStartPoint();
  }
  else
  {
    // The previous segment has already been inserted,
    // hence the previous point is present.
    m_points.back()->setFollowing(m->id());
  }

  createEndPoint();
}
Esempio n. 3
0
void LLChatMsgBox::addText( const LLStringExplicit& text , const LLStyle::Params& input_params )
{
	S32 length = getLength();
	// if there is existing text, add a separator
	if (length > 0)
	{
		// chat separator exists right before the null terminator
		insertSegment(new ChatSeparator(length - 1, length - 1));
	}
	// prepend newline only if there is some existing text
	appendText(text, length > 0, input_params);
}
//NOTE: obliterates existing styles (including hyperlinks)
void LLExpandableTextBox::LLTextBoxEx::hideExpandText() 
{ 
	if (mExpanderVisible)
	{
		// this will overwrite the expander segment and all text styling with a single style
		LLStyleConstSP sp(new LLStyle(getDefaultStyleParams()));
		LLNormalTextSegment* segmentp = new LLNormalTextSegment(sp, 0, getLength() + 1, *this);
		insertSegment(segmentp);
		
		mExpanderVisible = false;
	}
}
Esempio n. 5
0
void LLViewerTextEditor::findEmbeddedItemSegments(S32 start, S32 end)
{
	LLWString text = getWText();

	// Start with i just after the first embedded item
	for(S32 idx = start; idx < end; idx++ )
	{
		llwchar embedded_char = text[idx];
		if( embedded_char >= FIRST_EMBEDDED_CHAR 
			&& embedded_char <= LAST_EMBEDDED_CHAR 
			&& mEmbeddedItemList->hasEmbeddedItem(embedded_char) )
		{
			LLInventoryItem* itemp = mEmbeddedItemList->getEmbeddedItemPtr(embedded_char);
			LLUIImagePtr image = mEmbeddedItemList->getItemImage(embedded_char);
			insertSegment(new LLEmbeddedItemSegment(idx, image, itemp, *this));
		}
	}
}
void LLExpandableTextBox::LLTextBoxEx::showExpandText()
{
	if (!mExpanderVisible)
	{
		// make sure we're scrolled to top when collapsing
		if (mScroller)
		{
			mScroller->goToTop();
		}
		// get fully visible lines
		std::pair<S32, S32> visible_lines = getVisibleLines(true);
		S32 last_line = visible_lines.second - 1;

		LLStyle::Params expander_style(getDefaultStyleParams());
		expander_style.font.style = "UNDERLINE";
		expander_style.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
		LLExpanderSegment* expanderp = new LLExpanderSegment(new LLStyle(expander_style), getLineStart(last_line), getLength() + 1, mExpanderLabel, *this);
		insertSegment(expanderp);
		mExpanderVisible = true;
	}

}
Esempio n. 7
0
// Walk through a string, applying the rules specified by the keyword token list and
// create a list of color segments.
void LLKeywords::findSegments(std::vector<LLTextSegment *>* seg_list, const LLWString& wtext, const LLColor4 &defaultColor)
{
	std::for_each(seg_list->begin(), seg_list->end(), DeletePointer());
	seg_list->clear();

	if( wtext.empty() )
	{
		return;
	}
	
	S32 text_len = wtext.size();

	seg_list->push_back( new LLTextSegment( LLColor3(defaultColor), 0, text_len ) ); 

	const llwchar* base = wtext.c_str();
	const llwchar* cur = base;
	const llwchar* line = NULL;

	while( *cur )
	{
		if( *cur == '\n' || cur == base )
		{
			if( *cur == '\n' )
			{
				cur++;
				if( !*cur || *cur == '\n' )
				{
					continue;
				}
			}

			// Start of a new line
			line = cur;

			// Skip white space
			while( *cur && isspace(*cur) && (*cur != '\n')  )
			{
				cur++;
			}
			if( !*cur || *cur == '\n' )
			{
				continue;
			}

			// cur is now at the first non-whitespace character of a new line	
		
			// Line start tokens
			{
				BOOL line_done = FALSE;
				for (token_list_t::iterator iter = mLineTokenList.begin();
					 iter != mLineTokenList.end(); ++iter)
				{
					LLKeywordToken* cur_token = *iter;
					if( cur_token->isHead( cur ) )
					{
						S32 seg_start = cur - base;
						while( *cur && *cur != '\n' )
						{
							// skip the rest of the line
							cur++;
						}
						S32 seg_end = cur - base;
						
						LLTextSegment* text_segment = new LLTextSegment( cur_token->getColor(), seg_start, seg_end );
						text_segment->setToken( cur_token );
						insertSegment( seg_list, text_segment, text_len, defaultColor);
						line_done = TRUE; // to break out of second loop.
						break;
					}
				}

				if( line_done )
				{
					continue;
				}
			}
		}

		// Skip white space
		while( *cur && isspace(*cur) && (*cur != '\n')  )
		{
			cur++;
		}

		while( *cur && *cur != '\n' )
		{
			// Check against delimiters
			{
				S32 seg_start = 0;
				LLKeywordToken* cur_delimiter = NULL;
				for (token_list_t::iterator iter = mDelimiterTokenList.begin();
					 iter != mDelimiterTokenList.end(); ++iter)
				{
					LLKeywordToken* delimiter = *iter;
					if( delimiter->isHead( cur ) )
					{
						cur_delimiter = delimiter;
						break;
					}
				}

				if( cur_delimiter )
				{
					S32 between_delimiters = 0;
					S32 seg_end = 0;

					seg_start = cur - base;
					cur += cur_delimiter->getLength();
					
					if( cur_delimiter->getType() == LLKeywordToken::TWO_SIDED_DELIMITER )
					{
						while( *cur && !cur_delimiter->isHead(cur))
						{
							// Check for an escape sequence.
							if (*cur == '\\')
							{
								// Count the number of backslashes.
								S32 num_backslashes = 0;
								while (*cur == '\\')
								{
									num_backslashes++;
									between_delimiters++;
									cur++;
								}
								// Is the next character the end delimiter?
								if (cur_delimiter->isHead(cur))
								{
									// Is there was an odd number of backslashes, then this delimiter
									// does not end the sequence.
									if (num_backslashes % 2 == 1)
									{
										between_delimiters++;
										cur++;
									}
									else
									{
										// This is an end delimiter.
										break;
									}
								}
							}
							else
							{
								between_delimiters++;
								cur++;
							}
						}

						if( *cur )
						{
							cur += cur_delimiter->getLength();
							seg_end = seg_start + between_delimiters + 2 * cur_delimiter->getLength();
						}
						else
						{
							// eof
							seg_end = seg_start + between_delimiters + cur_delimiter->getLength();
						}
					}
					else
					{
						llassert( cur_delimiter->getType() == LLKeywordToken::ONE_SIDED_DELIMITER );
						// Left side is the delimiter.  Right side is eol or eof.
						while( *cur && ('\n' != *cur) )
						{
							between_delimiters++;
							cur++;
						}
						seg_end = seg_start + between_delimiters + cur_delimiter->getLength();
					}


					LLTextSegment* text_segment = new LLTextSegment( cur_delimiter->getColor(), seg_start, seg_end );
					text_segment->setToken( cur_delimiter );
					insertSegment( seg_list, text_segment, text_len, defaultColor);

					// Note: we don't increment cur, since the end of one delimited seg may be immediately
					// followed by the start of another one.
					continue;
				}
			}

			// check against words
			llwchar prev = cur > base ? *(cur-1) : 0;
			if( !isalnum( prev ) && (prev != '_') )
			{
				const llwchar* p = cur;
				while( isalnum( *p ) || (*p == '_') )
				{
					p++;
				}
				S32 seg_len = p - cur;
				if( seg_len > 0 )
				{
					LLWString word( cur, 0, seg_len );
					word_token_map_t::iterator map_iter = mWordTokenMap.find(word);
					if( map_iter != mWordTokenMap.end() )
					{
						LLKeywordToken* cur_token = map_iter->second;
						S32 seg_start = cur - base;
						S32 seg_end = seg_start + seg_len;

						// llinfos << "Seg: [" << word.c_str() << "]" << llendl;


						LLTextSegment* text_segment = new LLTextSegment( cur_token->getColor(), seg_start, seg_end );
						text_segment->setToken( cur_token );
						insertSegment( seg_list, text_segment, text_len, defaultColor);
					}
					cur += seg_len; 
					continue;
				}
			}

			if( *cur && *cur != '\n' )
			{
				cur++;
			}
		}
	}
}
Esempio n. 8
0
void
Segment::insertNewSegment(const SegmentPoint& p, SegmentType type)
{
    insertSegment(duplicate(p, type));
}
Esempio n. 9
0
void Model::addSegment(SegmentModel* m)
{
  insertSegment(m);

  // Add points if necessary
  // If there is an existing previous segment, its end point also exists
  auto createStartPoint = [&]() {
    auto pt = new PointModel{getStrongId(m_points), this};
    pt->setFollowing(m->id());
    pt->setPos(m->start());
    addPoint(pt);
    return pt;
  };
  auto createEndPoint = [&]() {
    auto pt = new PointModel{getStrongId(m_points), this};
    pt->setPrevious(m->id());
    pt->setPos(m->end());
    addPoint(pt);
    return pt;
  };

  if (m->previous())
  {
    auto previousSegment = std::find_if(
        m_segments.begin(), m_segments.end(), [&](const auto& seg) {
          return seg.following() == m->id();
        });
    if (previousSegment != m_segments.end())
    {
      auto thePt = std::find_if(
          m_points.begin(), m_points.end(), [&](PointModel* pt) {
            return pt->previous() == (*previousSegment).id();
          });

      if (thePt != m_points.end())
      {
        // The previous segments and points both exist
        (*thePt)->setFollowing(m->id());
      }
      else
      {
        // The previous segment exists but not the end point.
        auto pt = createStartPoint();
        pt->setPrevious((*previousSegment).id());
      }
    }
    else // The previous segment has not yet been added.
    {
      createStartPoint();
    }
  }
  else if (std::none_of(m_points.begin(), m_points.end(), [&](PointModel* pt) {
             return pt->following() == m->id();
           }))
  {
    createStartPoint();
  }

  if (m->following())
  {
    auto followingSegment = std::find_if(
        m_segments.begin(), m_segments.end(), [&](const auto& seg) {
          return seg.previous() == m->id();
        });
    if (followingSegment != m_segments.end())
    {
      auto thePt = std::find_if(
          m_points.begin(), m_points.end(), [&](PointModel* pt) {
            return pt->following() == (*followingSegment).id();
          });

      if (thePt != m_points.end())
      {
        (*thePt)->setPrevious(m->id());
      }
      else
      {
        auto pt = createEndPoint();
        pt->setFollowing((*followingSegment).id());
      }
    }
    else
    {
      createEndPoint();
    }
  }
  else if (std::none_of(m_points.begin(), m_points.end(), [&](PointModel* pt) {
             return pt->previous() == m->id();
           }))
  {
    // Note : if one day a buggy case happens here, check that set
    // following/previous
    // are correctly set after cloning the segment.
    createEndPoint();
  }
}
Esempio n. 10
0
    uint32 All_RoadSegment::AnalysisSegment()
    {
        uint32 firstSegId = 0;
        
        //open XML
        TiXmlDocument XMLdoc("./config/DE_Airport_ParamConfig.xml");
        if(!XMLdoc.LoadFile())
	    {
		    cout<<"fail to load config file"<<endl;
		    return 0;
	    }

        TiXmlElement* root = XMLdoc.RootElement();
	    TiXmlElement* segment;
        //segnumber
	    segment = root->FirstChildElement();
        segmentnum = stringToNum<uint32>(segment->GetText());
        segment = segment->NextSiblingElement();

        int index = -1;
        int insert_idex;
        while(NULL != segment)
        {
            RoadSegment *p_seg_t = new RoadSegment;
            //segID
            TiXmlElement* nextElement = segment->FirstChildElement();
		    p_seg_t->segId = stringToNum<uint16>(nextElement->GetText());
            if(-1 == index)//first segment
            {firstSegId = p_seg_t->segId;}
            //segType
            nextElement = nextElement->NextSiblingElement();
		    p_seg_t->segType = stringToNum<uint32>(nextElement->GetText());
            //lanenum
            nextElement = nextElement->NextSiblingElement();
		    p_seg_t->laneNum = stringToNum<uint32>(nextElement->GetText());
            //lineNum
            nextElement = nextElement->NextSiblingElement();
		    p_seg_t->lineNum = stringToNum<uint32>(nextElement->GetText());
            //gpspoint number
            nextElement = nextElement->NextSiblingElement();
            p_seg_t->pointNum = stringToNum<uint32>(nextElement->GetText());
            
            //point element
            index = p_seg_t->pointNum;
            while(index)
            {
                Segmentpoint *p_point_t = new Segmentpoint;
                index--;
                nextElement = nextElement->NextSiblingElement();
                TiXmlElement* pointElement = nextElement->FirstChildElement();
                //point ID
                p_point_t->pointId = stringToNum<uint32>(pointElement->GetText());
                pointElement = pointElement->NextSiblingElement();
                //point type
                p_point_t->point_type = stringToNum<uint32>(pointElement->GetText());
                pointElement = pointElement->NextSiblingElement();
                //connect segmentID
                p_point_t->conn_segId = stringToNum<uint32>(pointElement->GetText());
                pointElement = pointElement->NextSiblingElement();
                //gps 
                p_point_t->point.lat = stringToNum<double>(pointElement->GetText());
                pointElement = pointElement->NextSiblingElement();
                p_point_t->point.lon = stringToNum<double>(pointElement->GetText());
                pointElement = pointElement->NextSiblingElement();

                //inert lane and sort
                insert_idex = p_seg_t->insertPoint(p_point_t);
                p_seg_t->_segpoint.insert(p_seg_t->_segpoint.begin()+insert_idex , *p_point_t);
            }
            //check gps point
            if(!p_seg_t->CheckPointId())
                return false;

            //lane element
            index = p_seg_t->laneNum;
            while(index)
            {
                Segmentlane *p_lane_t = new Segmentlane;
                index--;
                nextElement = nextElement->NextSiblingElement();
                TiXmlElement* laneElement = nextElement->FirstChildElement();
                //laneID
                p_lane_t->laneId = stringToNum<uint32>(laneElement->GetText());
                laneElement = laneElement->NextSiblingElement();
                //start position
                p_lane_t->start_pos.lat = stringToNum<double>(laneElement->GetText());
                laneElement = laneElement->NextSiblingElement();
                p_lane_t->start_pos.lon = stringToNum<double>(laneElement->GetText());
                laneElement = laneElement->NextSiblingElement();
                //stop position
                p_lane_t->end_pos.lat = stringToNum<double>(laneElement->GetText());
                laneElement = laneElement->NextSiblingElement();
                p_lane_t->end_pos.lon = stringToNum<double>(laneElement->GetText());
                laneElement = laneElement->NextSiblingElement();
                //direction
                p_lane_t->derection = stringToNum<uint32>(laneElement->GetText());
                laneElement = laneElement->NextSiblingElement();
                //merge left 
                p_lane_t->merge_left = stringToNum<uint32>(laneElement->GetText()); 
                laneElement = laneElement->NextSiblingElement();
                //merge right
                p_lane_t->merge_right = stringToNum<uint32>(laneElement->GetText()); 
                laneElement = laneElement->NextSiblingElement();
                //left line
                p_lane_t->leftlineID = stringToNum<uint32>(laneElement->GetText());
                laneElement = laneElement->NextSiblingElement();
                //right line
                p_lane_t->rightlineID = stringToNum<uint32>(laneElement->GetText());
                laneElement = laneElement->NextSiblingElement();
                
                //inert lane and sort
                insert_idex = p_seg_t->insertLane(p_lane_t);
                p_seg_t->_seglane.insert(p_seg_t->_seglane.begin()+insert_idex , *p_lane_t);
            }
            //check lane
            if(!p_seg_t->CheckLaneId())
                return false;

            //line element
            index = p_seg_t->lineNum;
            while(index)
            {
                Segmentline *p_line_t = new Segmentline;
                index--;
                nextElement = nextElement->NextSiblingElement();
                TiXmlElement* lineElement = nextElement->FirstChildElement();
                //line ID
                p_line_t->lineId = stringToNum<uint32>(lineElement->GetText());
                lineElement = lineElement->NextSiblingElement();
                //line type
                p_line_t->linetype = stringToNum<uint32>(lineElement->GetText());
                lineElement = lineElement->NextSiblingElement();
                //connection segID
                p_line_t->connSegID = stringToNum<uint32>(lineElement->GetText());
                lineElement = lineElement->NextSiblingElement();
                //connection lineID 
                p_line_t->connLineID = stringToNum<uint32>(lineElement->GetText());
                lineElement = lineElement->NextSiblingElement();

                //insert line and sort
                insert_idex = p_seg_t->insertLine(p_line_t);
                p_seg_t->_segline.insert(p_seg_t->_segline.begin()+insert_idex , *p_line_t);
            }
            //check line
            if(!p_seg_t->CheckLineId())
                return false;

            //insert segment and sort
            insert_idex = insertSegment(p_seg_t);
            _roadsegment.insert(_roadsegment.begin()+insert_idex , *p_seg_t);

            //point to next segmen 
		    segment = segment->NextSiblingElement();
        }

        //check segment
        if(!CheckSegmentID())
            return false;

        return firstSegId;
    }
Esempio n. 11
0
void fill(const TRaster32P &ras, const TRaster32P &ref,
          const FillParameters &params, TTileSaverFullColor *saver) {
  TPixel32 *pix, *limit, *pix0, *oldpix;
  int oldy, xa, xb, xc, xd, dy;
  int oldxc, oldxd;
  int matte, oldMatte;
  int x = params.m_p.x, y = params.m_p.y;
  TRaster32P workRas = ref ? ref : ras;

  TRect bbbox = workRas->getBounds();

  if (!bbbox.contains(params.m_p)) return;

  TPaletteP plt  = params.m_palette;
  TPixel32 color = plt->getStyle(params.m_styleId)->getMainColor();
  int fillDepth =
      params.m_shiftFill ? params.m_maxFillDepth : params.m_minFillDepth;

  assert(fillDepth >= 0 && fillDepth < 16);
  fillDepth = ((15 - fillDepth) << 4) | (15 - fillDepth);

  // looking for any  pure transparent pixel along the border; if after filling
  // that pixel will be changed,
  // it means that I filled the bg and the savebox needs to be recomputed!
  TPixel32 borderIndex;
  TPixel32 *borderPix = 0;
  pix                 = workRas->pixels(0);
  int i;
  for (i = 0; i < workRas->getLx(); i++, pix++)  // border down
    if (pix->m == 0) {
      borderIndex = *pix;
      borderPix   = pix;
      break;
    }
  if (borderPix == 0)  // not found in border down...try border up (avoid left
                       // and right borders...so unlikely)
  {
    pix = workRas->pixels(workRas->getLy() - 1);
    for (i = 0; i < workRas->getLx(); i++, pix++)  // border up
      if (pix->m == 0) {
        borderIndex = *pix;
        borderPix   = pix;
        break;
      }
  }

  std::stack<FillSeed> seeds;
  std::map<int, std::vector<std::pair<int, int>>> segments;

  // fillRow(r, params.m_p, xa, xb, color ,saver);
  findSegment(workRas, params.m_p, xa, xb, color);
  segments[y].push_back(std::pair<int, int>(xa, xb));
  seeds.push(FillSeed(xa, xb, y, 1));
  seeds.push(FillSeed(xa, xb, y, -1));

  while (!seeds.empty()) {
    FillSeed fs = seeds.top();
    seeds.pop();

    xa   = fs.m_xa;
    xb   = fs.m_xb;
    oldy = fs.m_y;
    dy   = fs.m_dy;
    y    = oldy + dy;
    if (y > bbbox.y1 || y < bbbox.y0) continue;
    pix = pix0 = workRas->pixels(y) + xa;
    limit      = workRas->pixels(y) + xb;
    oldpix     = workRas->pixels(oldy) + xa;
    x          = xa;
    oldxd      = (std::numeric_limits<int>::min)();
    oldxc      = (std::numeric_limits<int>::max)();
    while (pix <= limit) {
      oldMatte  = threshMatte(oldpix->m, fillDepth);
      matte     = threshMatte(pix->m, fillDepth);
      bool test = false;
      if (segments.find(y) != segments.end())
        test = isPixelInSegment(segments[y], x);
      if (*pix != color && !test && matte >= oldMatte && matte != 255) {
        findSegment(workRas, TPoint(x, y), xc, xd, color);
        // segments[y].push_back(std::pair<int,int>(xc, xd));
        insertSegment(segments[y], std::pair<int, int>(xc, xd));
        if (xc < xa) seeds.push(FillSeed(xc, xa - 1, y, -dy));
        if (xd > xb) seeds.push(FillSeed(xb + 1, xd, y, -dy));
        if (oldxd >= xc - 1)
          oldxd = xd;
        else {
          if (oldxd >= 0) seeds.push(FillSeed(oldxc, oldxd, y, dy));
          oldxc = xc;
          oldxd = xd;
        }
        pix += xd - x + 1;
        oldpix += xd - x + 1;
        x += xd - x + 1;
      } else {
        pix++;
        oldpix++, x++;
      }
    }
    if (oldxd > 0) seeds.push(FillSeed(oldxc, oldxd, y, dy));
  }

  std::map<int, std::vector<std::pair<int, int>>>::iterator it;
  for (it = segments.begin(); it != segments.end(); it++) {
    TPixel32 *line    = ras->pixels(it->first);
    TPixel32 *refLine = 0;
    TPixel32 *refPix;
    if (ref) refLine = ref->pixels(it->first);
    std::vector<std::pair<int, int>> segmentVector = it->second;
    for (int i = 0; i < (int)segmentVector.size(); i++) {
      std::pair<int, int> segment = segmentVector[i];
      if (segment.second >= segment.first) {
        pix             = line + segment.first;
        if (ref) refPix = refLine + segment.first;
        int n;
        for (n = 0; n < segment.second - segment.first + 1; n++, pix++) {
          if (ref) {
            *pix = *refPix;
            refPix++;
          } else
            *pix = pix->m == 0 ? color : overPix(color, *pix);
        }
      }
    }
  }
}
Esempio n. 12
0
/* ---------------------------------------------------------------------------
 * Compute the area of the union of the given rectangles.
 * O(N ln N) time.
 */
double
ComputeUnionArea (BoxListType *boxlist)
{
  BoxType **rectLeft, **rectRight;
  Cardinal i, j;
  LocationList yCoords;
  SegmentTree segtree;
  Coord lastX;
  double area = 0.0;

  if (boxlist->BoxN == 0)
    return 0.0;
  /* create sorted list of Y coordinates */
  yCoords = createSortedYList (boxlist);
  /* now create empty segment tree */
  segtree = createSegmentTree (yCoords.p, yCoords.size);
  free (yCoords.p);
  /* create sorted list of left and right X coordinates of rectangles */
  rectLeft = (BoxType **)calloc (boxlist->BoxN, sizeof (*rectLeft));
  rectRight = (BoxType **)calloc (boxlist->BoxN, sizeof (*rectRight));
  for (i = 0; i < boxlist->BoxN; i++)
    {
      assert (boxlist->Box[i].X1 <= boxlist->Box[i].X2);
      assert (boxlist->Box[i].Y1 <= boxlist->Box[i].Y2);
      rectLeft[i] = rectRight[i] = &boxlist->Box[i];
    }
  qsort (rectLeft, boxlist->BoxN, sizeof (*rectLeft), compareleft);
  qsort (rectRight, boxlist->BoxN, sizeof (*rectRight), compareright);
  /* sweep through x segments from left to right */
  i = j = 0;
  lastX = rectLeft[0]->X1;
  while (j < boxlist->BoxN)
    {
      assert (i <= boxlist->BoxN);
      /* i will step through rectLeft, j will through rectRight */
      if (i == boxlist->BoxN || rectRight[j]->X2 < rectLeft[i]->X1)
        {
          /* right edge of rectangle */
          BoxType *b = rectRight[j++];
          /* check lastX */
          if (b->X2 != lastX)
            {
              assert (lastX < b->X2);
              area += (double) (b->X2 - lastX) * segtree.nodes[1].area;
              lastX = b->X2;
            }
          /* remove a segment from the segment tree. */
          deleteSegment (&segtree, 1, b->Y1, b->Y2);
        }
      else
        {
          /* left edge of rectangle */
          BoxType *b = rectLeft[i++];
          /* check lastX */
          if (b->X1 != lastX)
            {
              assert (lastX < b->X1);
              area += (double) (b->X1 - lastX) * segtree.nodes[1].area;
              lastX = b->X1;
            }
          /* add a segment from the segment tree. */
          insertSegment (&segtree, 1, b->Y1, b->Y2);
        }
    }
  free (rectLeft);
  free (rectRight);
  free (segtree.nodes);
  return area * 0.0001;
}