/*
 * Split selected sectors in a brush in this world with one brush in other world.
 * (other brush must have only one sector)
 */
void CWorld::SplitSectors(CEntity &enThis, CBrushSectorSelection &selbscSectorsToSplit,
  CWorld &woOther, CEntity &enOther, const CPlacement3D &plOther)
{
  _pfWorldEditingProfile.StartTimer(CWorldEditingProfile::PTI_CSGTOTAL);
  _pfWorldEditingProfile.IncrementAveragingCounter();
  // assure that floating point precision is 53 bits
  AssureFPT_53();

  // get relevant brush mip in this brush
  CBrushMip &bmThis = *GetBrushMip(enThis);
  if (&bmThis==NULL) {
    _pfWorldEditingProfile.StopTimer(CWorldEditingProfile::PTI_CSGTOTAL);
    return;
  }

  // get relevant brush mip in other brush
  CBrushMip &bmOther = *GetBrushMip(enOther);
  if (&bmOther==NULL) {
    _pfWorldEditingProfile.StopTimer(CWorldEditingProfile::PTI_CSGTOTAL);
    return;
  }

  /* Assure that the other brush has only one sector. */

  // if other brush has more than one sector
  if (bmOther.bm_abscSectors.Count()>1) {
    // join all sectors of the other brush together
    CBrushSectorSelection selbscOtherAll;
    bmOther.SelectAllSectors(selbscOtherAll);
    woOther.JoinSectors(selbscOtherAll);
  }

  /* Split selected sectors with the one sector in the other brush. */

  // get the sector of the other brush to object
  CBrushSectorSelectionForCSG selbscOther;
  bmOther.SelectAllSectors(selbscOther);
  CObject3D obOther;
  DOUBLEaabbox3D boxOther;
  woOther.CopySourceBrushSectorsToObject(enOther, selbscOther, plOther,
    obOther, enThis.en_plPlacement, boxOther);

  // if the selection is empty
  if (selbscSectorsToSplit.Count()==0) {
    // select all sectors near the splitting tool
    bmThis.SelectSectorsInRange(selbscSectorsToSplit, DOUBLEtoFLOAT(boxOther));
  }
  // for all sectors in the selection
  FOREACHINDYNAMICCONTAINER(selbscSectorsToSplit, CBrushSector, itbsc) {
    // split the sector using the copy of other object
    CObject3D obj(obOther);
    SplitOneSector(*itbsc, obj);
  }
/*
 * Do some CSG operation with one brush in this world and one brush in other world.
 */
void CWorld::DoCSGOperation(
    CEntity &enThis,
    CWorld &woOther,
    CEntity &enOther,
    const CPlacement3D &plOther,
    void (CObject3D::*DoCSGOpenSector)(CObject3D &obA, CObject3D &obB),
    void (CObject3D::*DoCSGClosedSectors)(CObject3D &obA, CObject3D &obB)
    )
{
  // assure that floating point precision is 53 bits
  AssureFPT_53();

  // get relevant brush mips in each brush
  CBrushMip &bmThis  = *GetBrushMip(enThis);
  CBrushMip &bmOther = *GetBrushMip(enOther);
  if (&bmThis==NULL || &bmOther==NULL) {
    return;
  }

  // get open sector of the other brush to object
  CBrushSectorSelectionForCSG selbscOtherOpen;
  bmOther.SelectOpenSector(selbscOtherOpen);
  CObject3D obOtherOpen;
  DOUBLEaabbox3D boxOtherOpen;
  woOther.CopySourceBrushSectorsToObject(enOther, selbscOtherOpen, plOther,
    obOtherOpen, enThis.en_plPlacement, boxOtherOpen);

  // if there is an open sector in other object
  if (obOtherOpen.ob_aoscSectors.Count()>0) {
    CObject3D obResult;
    // deportalize the open sector
    obOtherOpen.TurnPortalsToWalls();

    // if there are any sectors in this brush
    if (bmThis.bm_abscSectors.Count()>0) {
      // move affected part of this brush to an object3d object
      CObject3D obThis;
      MoveTargetBrushPartToObject(enThis, boxOtherOpen, obThis);
      // do the open sector CSG operation on the objects
      _pfWorldEditingProfile.StartTimer(CWorldEditingProfile::PTI_OBJECTCSG);
      (obResult.*DoCSGOpenSector)(obThis, obOtherOpen);
      _pfWorldEditingProfile.StopTimer(CWorldEditingProfile::PTI_OBJECTCSG);

    // if there are no sectors in this brush
    } else {
      // just put the open sector directly in the result
      obResult = obOtherOpen;
    }
    // return the result back to this brush
    AddObjectToBrush(obResult, enThis);
  }

  // get closed sectors of the other brush to object
  CBrushSectorSelectionForCSG selbscOtherClosed;
  bmOther.SelectClosedSectors(selbscOtherClosed);
  CObject3D obOtherClosed;
  DOUBLEaabbox3D boxOtherClosed;
  woOther.CopySourceBrushSectorsToObject(enOther, selbscOtherClosed, plOther,
    obOtherClosed, enThis.en_plPlacement, boxOtherClosed);

  // if there are closed sectors in other object
  if (obOtherClosed.ob_aoscSectors.Count()>0) {
    CObject3D obResult;

    // if there are any sectors in this brush
    if (bmThis.bm_abscSectors.Count()>0) {
      // move affected part of this brush to an object3d object
      CObject3D obThis;
      MoveTargetBrushPartToObject(enThis, boxOtherClosed, obThis);
      // do the closed sectors CSG operation on the objects
      _pfWorldEditingProfile.StartTimer(CWorldEditingProfile::PTI_OBJECTCSG);
      (obResult.*DoCSGClosedSectors)(obThis, obOtherClosed);
      _pfWorldEditingProfile.StopTimer(CWorldEditingProfile::PTI_OBJECTCSG);

    // if there are no sectors in this brush
    } else {
      // just put the closed sectors directly in the result
      obResult = obOtherClosed;
    }
    // return the result back to this brush
    AddObjectToBrush(obResult, enThis);
  }
}