<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2016 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes

// Local includes
#include "libmesh/side.h"
#include "libmesh/cell_pyramid5.h"
#include "libmesh/edge_edge2.h"
#include "libmesh/face_tri3.h"
#include "libmesh/face_quad4.h"

namespace libMesh
{

// ------------------------------------------------------------
// Pyramid5 class static member initializations
const unsigned int Pyramid5::side_nodes_map[5][4] =
  {
    {0, 1, 4, 99}, // Side 0
    {1, 2, 4, 99}, // Side 1
    {2, 3, 4, 99}, // Side 2
    {3, 0, 4, 99}, // Side 3
    {0, 3, 2,  1}  // Side 4
  };

const unsigned int Pyramid5::edge_nodes_map[8][2] =
  {
    {0, 1}, // Side 0
    {1, 2}, // Side 1
    {2, 3}, // Side 2
    {0, 3}, // Side 3
    {0, 4}, // Side 4
    {1, 4}, // Side 5
    {2, 4}, // Side 6
    {3, 4}  // Side 7
  };

// ------------------------------------------------------------
// Pyramid5 class member functions

bool Pyramid5::is_vertex(const unsigned int) const
{
  return true;
}

bool Pyramid5::is_edge(const unsigned int) const
{
  return false;
}

bool Pyramid5::is_face(const unsigned int) const
{
  return false;
}

bool Pyramid5::is_node_on_side(const unsigned int n,
                               const unsigned int s) const
{
  libmesh_assert_less (s, n_sides());
  for (unsigned int i = 0; i != 4; ++i)
    if (side_nodes_map[s][i] == n)
      return true;
  return false;
}

bool Pyramid5::is_node_on_edge(const unsigned int n,
                               const unsigned int e) const
{
  libmesh_assert_less (e, n_edges());
  for (unsigned int i = 0; i != 2; ++i)
    if (edge_nodes_map[e][i] == n)
      return true;
  return false;
}

bool Pyramid5::has_affine_map() const
{
  //  Point v = this->point(3) - this->point(0);
  //  return (v.relative_fuzzy_equals(this->point(2) - this->point(1)));
  return false;
}

UniquePtr<Elem> Pyramid5::build_side (const unsigned int i,
                                      bool proxy) const
{
  libmesh_assert_less (i, this->n_sides());

  if (proxy)
    {
      switch (i)
        {
        case 0:
        case 1:
        case 2:
        case 3:
          return UniquePtr<Elem>(new Side<Tri3,Pyramid5>(this,i));

        case 4:
          return UniquePtr<Elem>(new Side<Quad4,Pyramid5>(this,i));

        default:
          libmesh_error_msg("Invalid side i = " << i);
        }
    }

  else
    {
      // Create NULL pointer to be initialized, returned later.
      Elem * face = libmesh_nullptr;

      switch (i)
        {
        case 0: // triangular face 1
        case 1: // triangular face 2
        case 2: // triangular face 3
        case 3: // triangular face 4
          {
            face = new Tri3;
            break;
          }
        case 4: // the quad face at z=0
          {
            face = new Quad4;
            break;
          }
        default:
          libmesh_error_msg("Invalid side i = " << i);
        }

      face->subdomain_id() = this->subdomain_id();

      // Set the nodes
      for (unsigned n=0; n<face->n_nodes(); ++n)
        face->set_node(n) = this->get_node(Pyramid5::side_nodes_map[i][n]);

      return UniquePtr<Elem>(face);
    }

  libmesh_error_msg("We'll never get here!");
  return UniquePtr<Elem>();
}

UniquePtr<Elem> Pyramid5::build_edge (const unsigned int i) const
{
  libmesh_assert_less (i, this->n_edges());

  return UniquePtr<Elem>(new SideEdge<Edge2,Pyramid5>(this,i));
}

void Pyramid5::connectivity(const unsigned int libmesh_dbg_var(sc),
                            const IOPackage iop,
                            std::vector<dof_id_type> & conn) const
{
  libmesh_assert(_nodes);
  libmesh_assert_less (sc, this->n_sub_elem());
  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);

  switch (iop)
    {
    case TECPLOT:
      {
        conn.resize(8);
        conn[0] = this->node(0)+1;
        conn[1] = this->node(1)+1;
        conn[2] = this->node(2)+1;
        conn[3] = this->node(3)+1;
        conn[4] = this->node(4)+1;
        conn[5] = this->node(4)+1;
        conn[6] = this->node(4)+1;
        conn[7] = this->node(4)+1;
        return;
      }

    case VTK:
      {
        conn.resize(5);
        conn[0] = this->node(3);
        conn[1] = this->node(2);
        conn[2] = this->node(1);
        conn[3] = this->node(0);
        conn[4] = this->node(4);
        return;
      }

    default:
      libmesh_error_msg("Unsupported IO package " << iop);
    }
}

Real Pyramid5::volume () const
{
  // The pyramid with a bilinear base has volume given by the
  // formula in: "Calculation of the Volume of a General Hexahedron
  // for Flow Predictions", AIAA Journal v.23, no.6, 1984, p.954-
  Node * node0 = this->get_node(0);
  Node * node1 = this->get_node(1);
  Node * node2 = this->get_node(2);
  Node * node3 = this->get_node(3);
  Node * node4 = this->get_node(4);

  // Construct Various edge and diagonal vectors
  Point v40 ( *node0 - *node4 );
  Point v13 ( *node3 - *node1 );
  Point v02 ( *node2 - *node0 );
  Point v03 ( *node3 - *node0 );
  Point v01 ( *node1 - *node0 );

  // Finally, ready to return the volume!
  return (1./6.)*(v40*(v13.cross(v02))) + (1./12.)*(v02*(v01.cross(v03)));
}

} // namespace libMesh
<commit_msg>Add quadrature-based volume() implementation for Pyramid5.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2016 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes

// Local includes
#include "libmesh/side.h"
#include "libmesh/cell_pyramid5.h"
#include "libmesh/edge_edge2.h"
#include "libmesh/face_tri3.h"
#include "libmesh/face_quad4.h"

namespace libMesh
{

// ------------------------------------------------------------
// Pyramid5 class static member initializations
const unsigned int Pyramid5::side_nodes_map[5][4] =
  {
    {0, 1, 4, 99}, // Side 0
    {1, 2, 4, 99}, // Side 1
    {2, 3, 4, 99}, // Side 2
    {3, 0, 4, 99}, // Side 3
    {0, 3, 2,  1}  // Side 4
  };

const unsigned int Pyramid5::edge_nodes_map[8][2] =
  {
    {0, 1}, // Side 0
    {1, 2}, // Side 1
    {2, 3}, // Side 2
    {0, 3}, // Side 3
    {0, 4}, // Side 4
    {1, 4}, // Side 5
    {2, 4}, // Side 6
    {3, 4}  // Side 7
  };

// ------------------------------------------------------------
// Pyramid5 class member functions

bool Pyramid5::is_vertex(const unsigned int) const
{
  return true;
}

bool Pyramid5::is_edge(const unsigned int) const
{
  return false;
}

bool Pyramid5::is_face(const unsigned int) const
{
  return false;
}

bool Pyramid5::is_node_on_side(const unsigned int n,
                               const unsigned int s) const
{
  libmesh_assert_less (s, n_sides());
  for (unsigned int i = 0; i != 4; ++i)
    if (side_nodes_map[s][i] == n)
      return true;
  return false;
}

bool Pyramid5::is_node_on_edge(const unsigned int n,
                               const unsigned int e) const
{
  libmesh_assert_less (e, n_edges());
  for (unsigned int i = 0; i != 2; ++i)
    if (edge_nodes_map[e][i] == n)
      return true;
  return false;
}

bool Pyramid5::has_affine_map() const
{
  //  Point v = this->point(3) - this->point(0);
  //  return (v.relative_fuzzy_equals(this->point(2) - this->point(1)));
  return false;
}

UniquePtr<Elem> Pyramid5::build_side (const unsigned int i,
                                      bool proxy) const
{
  libmesh_assert_less (i, this->n_sides());

  if (proxy)
    {
      switch (i)
        {
        case 0:
        case 1:
        case 2:
        case 3:
          return UniquePtr<Elem>(new Side<Tri3,Pyramid5>(this,i));

        case 4:
          return UniquePtr<Elem>(new Side<Quad4,Pyramid5>(this,i));

        default:
          libmesh_error_msg("Invalid side i = " << i);
        }
    }

  else
    {
      // Create NULL pointer to be initialized, returned later.
      Elem * face = libmesh_nullptr;

      switch (i)
        {
        case 0: // triangular face 1
        case 1: // triangular face 2
        case 2: // triangular face 3
        case 3: // triangular face 4
          {
            face = new Tri3;
            break;
          }
        case 4: // the quad face at z=0
          {
            face = new Quad4;
            break;
          }
        default:
          libmesh_error_msg("Invalid side i = " << i);
        }

      face->subdomain_id() = this->subdomain_id();

      // Set the nodes
      for (unsigned n=0; n<face->n_nodes(); ++n)
        face->set_node(n) = this->get_node(Pyramid5::side_nodes_map[i][n]);

      return UniquePtr<Elem>(face);
    }

  libmesh_error_msg("We'll never get here!");
  return UniquePtr<Elem>();
}

UniquePtr<Elem> Pyramid5::build_edge (const unsigned int i) const
{
  libmesh_assert_less (i, this->n_edges());

  return UniquePtr<Elem>(new SideEdge<Edge2,Pyramid5>(this,i));
}

void Pyramid5::connectivity(const unsigned int libmesh_dbg_var(sc),
                            const IOPackage iop,
                            std::vector<dof_id_type> & conn) const
{
  libmesh_assert(_nodes);
  libmesh_assert_less (sc, this->n_sub_elem());
  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);

  switch (iop)
    {
    case TECPLOT:
      {
        conn.resize(8);
        conn[0] = this->node(0)+1;
        conn[1] = this->node(1)+1;
        conn[2] = this->node(2)+1;
        conn[3] = this->node(3)+1;
        conn[4] = this->node(4)+1;
        conn[5] = this->node(4)+1;
        conn[6] = this->node(4)+1;
        conn[7] = this->node(4)+1;
        return;
      }

    case VTK:
      {
        conn.resize(5);
        conn[0] = this->node(3);
        conn[1] = this->node(2);
        conn[2] = this->node(1);
        conn[3] = this->node(0);
        conn[4] = this->node(4);
        return;
      }

    default:
      libmesh_error_msg("Unsupported IO package " << iop);
    }
}

Real Pyramid5::volume () const
{
  // Make copies of our points.  It makes the subsequent calculations a bit
  // shorter and avoids dereferencing the same pointer multiple times.
  Point
    x0 = point(0), x1 = point(1), x2 = point(2), x3 = point(3), x4 = point(4);

  // The number of components in the dx_dxi, dx_deta, and dx_dzeta arrays.
  const int n_components = 4;

  Point dx_dxi[n_components] =
    {
      -x0/4 + x1/4 + x2/4 - x3/4, // const
      x0/4 - x1/4 - x2/4 + x3/4,  // zeta
      x0/4 - x1/4 + x2/4 - x3/4   // eta
    };

  Point dx_deta[n_components] =
    {
      -x0/4 - x1/4 + x2/4 + x3/4, // const
      x0/4 + x1/4 - x2/4 - x3/4,  // zeta
      x0/4 - x1/4 + x2/4 - x3/4,  // xi
    };

  Point dx_dzeta[n_components] =
    {
      -x0/4 - x1/4 - x2/4 - x3/4 + x4,  // const
      x0/2 + x1/2 + x2/2 + x3/2 - 2*x4, // zeta
      -x0/4 - x1/4 - x2/4 - x3/4 + x4,  // zeta**2
      x0/4 - x1/4 + x2/4 - x3/4         // xi*eta
    };

  // Number of points in the 2D quadrature rule
  const int N = 8;

  // Parameters of the quadrature rule
  static const Real
    a1 = -5.0661630334978742377431469429037e-01L,
    a2 = -2.6318405556971359557121701304557e-01L,
    b1 = 1.2251482265544137786674043037115e-01L,
    b2 = 5.4415184401122528879992623629551e-01L,
    w1 = 2.3254745125350790274997694884235e-01L,
    w2 = 1.0078588207982543058335638449098e-01L;

  // The points and weights of the 2x2x2 quadrature rule
  static const Real xi[8]   = {a1,  a2,  a1,  a2, -a1, -a2, -a1, -a2};
  static const Real eta[8]  = {a1,  a2, -a1, -a2,  a1,  a2, -a1, -a2};
  static const Real zeta[8] = {b1,  b2,  b1,  b2,  b1,  b2,  b1,  b2};
  static const Real w[8] = {w1, w2, w1, w2, w1, w2, w1, w2};

  Real vol = 0.;
  for (int q=0; q<N; ++q)
    {
      // Note: we need to scale dx/dxi and dx/deta by (1-z), and dx/dzeta by (1-z)**2
      Point
        dx_dxi_q   = (dx_dxi[0] + zeta[q]*dx_dxi[1] + eta[q]*dx_dxi[2]) / (1. - zeta[q]),
        dx_deta_q  = (dx_deta[0] + zeta[q]*dx_deta[1] + xi[q]*dx_deta[2]) / (1. - zeta[q]),
        dx_dzeta_q = (dx_dzeta[0] + zeta[q]*dx_dzeta[1] + zeta[q]*zeta[q]*dx_dzeta[2] + xi[q]*eta[q]*dx_dzeta[3]) / (1. - zeta[q]) / (1. - zeta[q]);

      // Compute scalar triple product, multiply by weight, and accumulate volume.
      vol += w[q] * dx_dxi_q * dx_deta_q.cross(dx_dzeta_q);
    }

  return vol;
}

} // namespace libMesh
<|endoftext|>


<commit_before>#ifndef DEDICATED_ONLY

#include "CViewport.h"

#include "gusgame.h"
#include "sound/sfx.h"
#include "gfx.h"
#include "gusanos/allegro.h"
#include "game/CWorm.h"
#include "game/WormInputHandler.h"
#include "CWormHuman.h"
#include "LuaCallbacks.h"
#include "lua/bindings-gfx.h"
#include "blitters/blitters.h"
#include "culling.h"
#include "game/CMap.h"
#include "game/Game.h"
#include "FlagInfo.h"
#include "CGameMode.h"
#include <list>

#include "sprite_set.h" // TEMP
#include "sprite.h" // TEMP
#include "CGameScript.h"

#include <iostream>

LuaReference CViewport::metaTable;

using namespace std;

void CViewport::gusInit()
{
	dest = 0;
	fadeBuffer = 0;
}

void CViewport::gusReset()
{
	destroy_bitmap(dest); dest = 0;
	destroy_bitmap(fadeBuffer); fadeBuffer = 0;
}

struct TestCuller : public Culler<TestCuller>
{
	TestCuller(ALLEGRO_BITMAP* dest_, ALLEGRO_BITMAP* src_, int scrOffX_, int scrOffY_, int destOffX_, int destOffY_, Rect const& rect)
			: Culler<TestCuller>(rect), dest(dest_), src(src_),
			scrOffX(scrOffX_), scrOffY(scrOffY_), destOffX(destOffX_), destOffY(destOffY_)
	{
	}

	bool block(int64_t x, int64_t y)
	{
		// doubleRes to singleRes coords
		return !game.gameMap()->unsafeGetMaterial(uint32_t(x/2), uint32_t(y/2)).worm_pass;
	}

	void line(int64_t y, int64_t x1, int64_t x2)
	{
		drawSpriteLine_add(
		    dest,
		    src,
		    int(x1 + scrOffX),
		    int(y + scrOffY),
		    int(x1 + destOffX),
		    int(y + destOffY),
		    int(x2 + destOffX + 1),
		    255);
	}

	ALLEGRO_BITMAP* dest;
	ALLEGRO_BITMAP* src;

	int scrOffX;
	int scrOffY;
	int destOffX;
	int destOffY;
};

static Sprite* testLight = 0;

void CViewport::setDestination(int width, int height)
{
	destroy_bitmap(fadeBuffer);
	fadeBuffer = create_bitmap_ex(8, width, height);
}

void CViewport::drawLight(IVec const& v)
{
	ALLEGRO_BITMAP* renderBitmap = testLight->m_bitmap;
	IVec off = getPos() * 2;
	IVec loff(v*2 - IVec(testLight->m_xPivot, testLight->m_yPivot));

	Rect r(0, 0, game.gameMap()->GetWidth()*2 - 1, game.gameMap()->GetHeight()*2 - 1);
	r &= Rect(renderBitmap) + loff;

	// we use drawSpriteLine_add which requires the same bit depths
	assert(renderBitmap->surf->format->BitsPerPixel == 8);
	TestCuller testCuller(fadeBuffer, renderBitmap, -off.x, -off.y, -loff.x, -loff.y, r);

	testCuller.cullOmni(v.x*2, v.y*2);
}

void CViewport::gusRender(const SmartPointer<SDL_Surface>& bmpDest)
{
	{
		int destw = Width*2;
		int desth = Height*2;
		bool needDestReset = false;
		if(!dest || !fadeBuffer || !testLight)
			needDestReset = true;
		else if(fadeBuffer->w != destw || fadeBuffer->h != desth)
			needDestReset = true;

		if(needDestReset)
			setDestination(destw, desth);

		destroy_bitmap(dest);
		dest = create_bitmap_from_sdl(bmpDest, Left/2, Top/2, Width*2, Height*2);
	}

	{
		int r = game.darkMode_wormLightRadius;
		if(r < 1) r = 1;
		if(r > 500) r = 500; // sane maximum. dont crash OLX

		bool needLightReset = false;
		if(!testLight)
			needLightReset = true;
		else if(testLight->m_xPivot != r * 2 /*doubleRes*/)
			needLightReset = true;

		if(needLightReset)
			testLight = genLight(r);
	}

	game.gameMap()->gusDraw(dest, WorldX, WorldY);

	if ( game.isLevelDarkMode() && game.gameMap()->lightmap )
		blit( game.gameMap()->lightmap, fadeBuffer, WorldX*2, WorldY*2, 0, 0, fadeBuffer->w, fadeBuffer->h );

	if (game.state == Game::S_Playing)  {
		// update the drawing position
		for_each_iterator(CWorm*, w, game.aliveWorms())
			w->get()->UpdateDrawPos();

		if( tLXOptions->bShadows ) {
			// Draw the projectile shadows
			cClient->DrawProjectileShadows(bmpDest.get(), this);

			// Draw the worm shadows
			for_each_iterator(CWorm*, w, game.aliveWorms())
				w->get()->DrawShadow(bmpDest.get(), this);
		}

		// Draw the entities
		DrawEntities(bmpDest.get(), this);

		// Draw the projectiles
		cClient->DrawProjectiles(bmpDest.get(), this);

		// Draw the bonuses
		cClient->DrawBonuses(bmpDest.get(), this);

		// draw unattached flags and flag spawnpoints
		cClient->flagInfo()->draw(bmpDest.get(), this);

		// draw worms
		for_each_iterator(CWorm*, w, game.aliveWorms())
			w->get()->Draw(bmpDest.get(), this);
	}

	for ( Grid::iterator iter = game.objects.beginAll(); iter; ++iter)
		iter->draw(this);

	if(game.isLevelDarkMode() && pcTargetWorm) {
		if(pcTargetWorm->isActive())
			drawLight(pcTargetWorm->pos().get());
	}

	if(game.gameMap()->bmpForeground.get()) {
		DrawImageAdv(bmpDest.get(), game.gameMap()->bmpForeground, WorldX*2, WorldY*2, 0, 0, Width*2, Height*2);
	}

	if(game.isLevelDarkMode())
		drawSprite_mult_8(dest, fadeBuffer, 0, 0);

	// only use the player/worm specific drawings in gus mods
	if(game.gameScript()->gusEngineUsed()) {
		CWormInputHandler* targetPlayer = pcTargetWorm ? pcTargetWorm->inputHandler() : NULL;

		// Note that we only process worms in the Lua callbacks which have a player set.
		// Most Lua code depends on this assumption so it would break otherwise.

		for(CWormInputHandler* player : game.players) {
			CWorm* worm = player->getWorm();
			if(!worm) continue;
			if(!worm->isActive()) continue;
			if(!worm->inputHandler()) continue;

			IVec renderPos( worm->getRenderPos() );
			int x = renderPos.x - WorldX;
			int y = renderPos.y - WorldY;
			LuaReferenceLazy ownerRef;
			if(targetPlayer)
				ownerRef = targetPlayer->getLuaReference();

			LUACALLBACK(wormRender).call()
				((lua_Number)x)
				((lua_Number)y)
				(worm->getLuaReference())
				(getLuaReference())
				(ownerRef)
				();
		}

		// draw viewport specific stuff only for human worms
		if(pcTargetWorm && dynamic_cast<CWormHumanInputHandler*>(pcTargetWorm->inputHandler()) != NULL) {
			LUACALLBACK(viewportRender).call()(getLuaReference())(pcTargetWorm->getLuaReference())();
		}
	}

	if(getTarget() && game.gameMode() && game.gameMode()->HaveTargetPos(getTarget())) {
		CVec wormPos = convertCoordsPrec(getTarget()->pos());
		CVec targetPos = convertCoordsPrec(game.gameMode()->TargetPos(getTarget()));
		CVec dir = targetPos - wormPos;

		if(dir.length() > 1) {
			CVec dirNormal = dir.normal();
			dir -= dirNormal * 50.f;

			static const int arrowW = 30;
			float f = 1.f;
			if(dir.x && (wormPos + dir * f).x - arrowW/2 < 0)
				f = CLAMP((arrowW/2 - wormPos.x) / dir.x, 0.f, f);
			if(dir.y && (wormPos + dir * f).y - arrowW/2 < 0)
				f = CLAMP((arrowW/2 - wormPos.y) / dir.y, 0.f, f);
			if(dir.x && (wormPos + dir * f).x + arrowW/2 > dest->w)
				f = CLAMP((dest->w - arrowW/2 - wormPos.x) / dir.x, 0.f, f);
			if(dir.y && (wormPos + dir * f).y + arrowW/2 > dest->h)
				f = CLAMP((dest->h - arrowW/2 - wormPos.y) / dir.y, 0.f, f);

			dir *= f;
			float diffToTarget = (float)(wormPos - targetPos).length();
			if(diffToTarget > 1) {
				CVec p = wormPos + dir;

				int alpha = 200;
				if(diffToTarget < 100)
					alpha = CLAMP(int(alpha * (diffToTarget - 50.f) / 50.f), 0, alpha);

				DrawArrow(dest->surf.get(), (int)p.x-arrowW/2, (int)p.y-arrowW/2, arrowW, arrowW, dirNormal.getAngle(), Color(0,255,30,alpha));
			}
		}
	}
}

#endif
<commit_msg>fix map foreground drawing order<commit_after>#ifndef DEDICATED_ONLY

#include "CViewport.h"

#include "gusgame.h"
#include "sound/sfx.h"
#include "gfx.h"
#include "gusanos/allegro.h"
#include "game/CWorm.h"
#include "game/WormInputHandler.h"
#include "CWormHuman.h"
#include "LuaCallbacks.h"
#include "lua/bindings-gfx.h"
#include "blitters/blitters.h"
#include "culling.h"
#include "game/CMap.h"
#include "game/Game.h"
#include "FlagInfo.h"
#include "CGameMode.h"
#include <list>

#include "sprite_set.h" // TEMP
#include "sprite.h" // TEMP
#include "CGameScript.h"

#include <iostream>

LuaReference CViewport::metaTable;

using namespace std;

void CViewport::gusInit()
{
	dest = 0;
	fadeBuffer = 0;
}

void CViewport::gusReset()
{
	destroy_bitmap(dest); dest = 0;
	destroy_bitmap(fadeBuffer); fadeBuffer = 0;
}

struct TestCuller : public Culler<TestCuller>
{
	TestCuller(ALLEGRO_BITMAP* dest_, ALLEGRO_BITMAP* src_, int scrOffX_, int scrOffY_, int destOffX_, int destOffY_, Rect const& rect)
			: Culler<TestCuller>(rect), dest(dest_), src(src_),
			scrOffX(scrOffX_), scrOffY(scrOffY_), destOffX(destOffX_), destOffY(destOffY_)
	{
	}

	bool block(int64_t x, int64_t y)
	{
		// doubleRes to singleRes coords
		return !game.gameMap()->unsafeGetMaterial(uint32_t(x/2), uint32_t(y/2)).worm_pass;
	}

	void line(int64_t y, int64_t x1, int64_t x2)
	{
		drawSpriteLine_add(
		    dest,
		    src,
		    int(x1 + scrOffX),
		    int(y + scrOffY),
		    int(x1 + destOffX),
		    int(y + destOffY),
		    int(x2 + destOffX + 1),
		    255);
	}

	ALLEGRO_BITMAP* dest;
	ALLEGRO_BITMAP* src;

	int scrOffX;
	int scrOffY;
	int destOffX;
	int destOffY;
};

static Sprite* testLight = 0;

void CViewport::setDestination(int width, int height)
{
	destroy_bitmap(fadeBuffer);
	fadeBuffer = create_bitmap_ex(8, width, height);
}

void CViewport::drawLight(IVec const& v)
{
	ALLEGRO_BITMAP* renderBitmap = testLight->m_bitmap;
	IVec off = getPos() * 2;
	IVec loff(v*2 - IVec(testLight->m_xPivot, testLight->m_yPivot));

	Rect r(0, 0, game.gameMap()->GetWidth()*2 - 1, game.gameMap()->GetHeight()*2 - 1);
	r &= Rect(renderBitmap) + loff;

	// we use drawSpriteLine_add which requires the same bit depths
	assert(renderBitmap->surf->format->BitsPerPixel == 8);
	TestCuller testCuller(fadeBuffer, renderBitmap, -off.x, -off.y, -loff.x, -loff.y, r);

	testCuller.cullOmni(v.x*2, v.y*2);
}

void CViewport::gusRender(const SmartPointer<SDL_Surface>& bmpDest)
{
	{
		int destw = Width*2;
		int desth = Height*2;
		bool needDestReset = false;
		if(!dest || !fadeBuffer || !testLight)
			needDestReset = true;
		else if(fadeBuffer->w != destw || fadeBuffer->h != desth)
			needDestReset = true;

		if(needDestReset)
			setDestination(destw, desth);

		destroy_bitmap(dest);
		dest = create_bitmap_from_sdl(bmpDest, Left/2, Top/2, Width*2, Height*2);
	}

	{
		int r = game.darkMode_wormLightRadius;
		if(r < 1) r = 1;
		if(r > 500) r = 500; // sane maximum. dont crash OLX

		bool needLightReset = false;
		if(!testLight)
			needLightReset = true;
		else if(testLight->m_xPivot != r * 2 /*doubleRes*/)
			needLightReset = true;

		if(needLightReset)
			testLight = genLight(r);
	}

	game.gameMap()->gusDraw(dest, WorldX, WorldY);

	if(game.gameMap()->bmpForeground.get()) {
		DrawImageAdv(bmpDest.get(), game.gameMap()->bmpForeground, WorldX*2, WorldY*2, 0, 0, Width*2, Height*2);
	}

	if ( game.isLevelDarkMode() && game.gameMap()->lightmap )
		blit( game.gameMap()->lightmap, fadeBuffer, WorldX*2, WorldY*2, 0, 0, fadeBuffer->w, fadeBuffer->h );

	if (game.state == Game::S_Playing)  {
		// update the drawing position
		for_each_iterator(CWorm*, w, game.aliveWorms())
			w->get()->UpdateDrawPos();

		if( tLXOptions->bShadows ) {
			// Draw the projectile shadows
			cClient->DrawProjectileShadows(bmpDest.get(), this);

			// Draw the worm shadows
			for_each_iterator(CWorm*, w, game.aliveWorms())
				w->get()->DrawShadow(bmpDest.get(), this);
		}

		// Draw the entities
		DrawEntities(bmpDest.get(), this);

		// Draw the projectiles
		cClient->DrawProjectiles(bmpDest.get(), this);

		// Draw the bonuses
		cClient->DrawBonuses(bmpDest.get(), this);

		// draw unattached flags and flag spawnpoints
		cClient->flagInfo()->draw(bmpDest.get(), this);

		// draw worms
		for_each_iterator(CWorm*, w, game.aliveWorms())
			w->get()->Draw(bmpDest.get(), this);
	}

	for ( Grid::iterator iter = game.objects.beginAll(); iter; ++iter)
		iter->draw(this);

	if(game.isLevelDarkMode() && pcTargetWorm) {
		if(pcTargetWorm->isActive())
			drawLight(pcTargetWorm->pos().get());
	}

	if(game.isLevelDarkMode())
		drawSprite_mult_8(dest, fadeBuffer, 0, 0);

	// only use the player/worm specific drawings in gus mods
	if(game.gameScript()->gusEngineUsed()) {
		CWormInputHandler* targetPlayer = pcTargetWorm ? pcTargetWorm->inputHandler() : NULL;

		// Note that we only process worms in the Lua callbacks which have a player set.
		// Most Lua code depends on this assumption so it would break otherwise.

		for(CWormInputHandler* player : game.players) {
			CWorm* worm = player->getWorm();
			if(!worm) continue;
			if(!worm->isActive()) continue;
			if(!worm->inputHandler()) continue;

			IVec renderPos( worm->getRenderPos() );
			int x = renderPos.x - WorldX;
			int y = renderPos.y - WorldY;
			LuaReferenceLazy ownerRef;
			if(targetPlayer)
				ownerRef = targetPlayer->getLuaReference();

			LUACALLBACK(wormRender).call()
				((lua_Number)x)
				((lua_Number)y)
				(worm->getLuaReference())
				(getLuaReference())
				(ownerRef)
				();
		}

		// draw viewport specific stuff only for human worms
		if(pcTargetWorm && dynamic_cast<CWormHumanInputHandler*>(pcTargetWorm->inputHandler()) != NULL) {
			LUACALLBACK(viewportRender).call()(getLuaReference())(pcTargetWorm->getLuaReference())();
		}
	}

	if(getTarget() && game.gameMode() && game.gameMode()->HaveTargetPos(getTarget())) {
		CVec wormPos = convertCoordsPrec(getTarget()->pos());
		CVec targetPos = convertCoordsPrec(game.gameMode()->TargetPos(getTarget()));
		CVec dir = targetPos - wormPos;

		if(dir.length() > 1) {
			CVec dirNormal = dir.normal();
			dir -= dirNormal * 50.f;

			static const int arrowW = 30;
			float f = 1.f;
			if(dir.x && (wormPos + dir * f).x - arrowW/2 < 0)
				f = CLAMP((arrowW/2 - wormPos.x) / dir.x, 0.f, f);
			if(dir.y && (wormPos + dir * f).y - arrowW/2 < 0)
				f = CLAMP((arrowW/2 - wormPos.y) / dir.y, 0.f, f);
			if(dir.x && (wormPos + dir * f).x + arrowW/2 > dest->w)
				f = CLAMP((dest->w - arrowW/2 - wormPos.x) / dir.x, 0.f, f);
			if(dir.y && (wormPos + dir * f).y + arrowW/2 > dest->h)
				f = CLAMP((dest->h - arrowW/2 - wormPos.y) / dir.y, 0.f, f);

			dir *= f;
			float diffToTarget = (float)(wormPos - targetPos).length();
			if(diffToTarget > 1) {
				CVec p = wormPos + dir;

				int alpha = 200;
				if(diffToTarget < 100)
					alpha = CLAMP(int(alpha * (diffToTarget - 50.f) / 50.f), 0, alpha);

				DrawArrow(dest->surf.get(), (int)p.x-arrowW/2, (int)p.y-arrowW/2, arrowW, arrowW, dirNormal.getAngle(), Color(0,255,30,alpha));
			}
		}
	}
}

#endif
<|endoftext|>


<commit_before>#include "binary_array.h"

namespace Lumix
{

	static const int BITS_IN_BYTE = 8;
	static const int BITMASK_7BIT = sizeof(int32_t) * BITS_IN_BYTE - 1;

	BinaryArray::StoreType BinaryArray::BINARY_MASK[32];
	BinaryArray::StoreType BinaryArray::INDEX_BIT[32];

	BinaryArray::Accessor::Accessor(BinaryArray& array, int index)
		: m_array(array)
		, m_index(index)
	{}

	BinaryArray::BinaryArray(IAllocator& allocator)
		: m_allocator(allocator)
		, m_data(NULL)
		, m_size(0)
		, m_capacity(0)
	{
		static bool init = false;
		if (!init)
		{
			init = true;
			for (int i = BITMASK_7BIT; i >= 0; --i)
			{
				BINARY_MASK[i] = i == BITMASK_7BIT ? 0xffffFFFF : BINARY_MASK[i + 1] << 1;
				INDEX_BIT[i] = 1 << (BITMASK_7BIT - i);
			}
		}
	}

	BinaryArray::~BinaryArray()
	{
		m_allocator.deallocate(m_data);
	}

	void BinaryArray::erase(int index)
	{
		if (0 <= index && index < m_size)
		{
			int major = index >> 5;
			const int last_major = (m_size - 1) >> 5;
			m_data[major] = ((index & BITMASK_7BIT) == 0 ? 0 : (m_data[major] & BINARY_MASK[(index & BITMASK_7BIT) - 1])) | ((m_data[major] & ~BINARY_MASK[index & BITMASK_7BIT]) << 1);
			if (major < last_major)
			{
				m_data[major] |= (m_data[major + 1] & 0x80000000) >> BITMASK_7BIT;
			}
			for (int i = major + 1; i <= last_major; ++i)
			{
				m_data[i] <<= 1;
				if (i < (m_size >> 5))
				{
					m_data[i] |= (m_data[i + 1] & 0x80000000) >> BITMASK_7BIT;
				}
			}
			m_data[last_major] <<= 1;
		}
	}

	void BinaryArray::clear()
	{
		m_size = 0;
	}

	void BinaryArray::push(bool value)
	{
		if (m_capacity == m_size)
		{
			grow(m_capacity > 0 ? (m_capacity << 1) : 32);
		}
		if (value)
		{
			m_data[m_size >> 5] |= INDEX_BIT[m_size & BITMASK_7BIT];
		}
		else
		{
			m_data[m_size >> 5] &= ~INDEX_BIT[m_size & BITMASK_7BIT];
		}
		++m_size;
	}

	void BinaryArray::pop()
	{
		ASSERT(m_size > 0);
		--m_size;
	}

	bool BinaryArray::operator[](int index) const
	{
		ASSERT(index < m_size);
		return (m_data[index >> 5] & INDEX_BIT[index & BITMASK_7BIT]) > 0;
	}

	BinaryArray::Accessor BinaryArray::operator[](int index)
	{
		return Accessor(*this, index);
	}

	bool BinaryArray::back() const
	{
		ASSERT(m_size > 0);
		return (*this)[m_size - 1];
	}

	BinaryArray::Accessor BinaryArray::back()
	{
		ASSERT(m_size > 0);
		return (*this)[m_size - 1];
	}

	int BinaryArray::size() const
	{
		return m_size;
	}

	void BinaryArray::reserve(int capacity)
	{
		if ((m_capacity >> 5) < (capacity >> 5))
		{
			grow(capacity);
		}
	}

	BinaryArray::StoreType* BinaryArray::getRaw()
	{
		return m_data;
	}

	int BinaryArray::getRawSize() const
	{
		return (m_size + BITMASK_7BIT) >> 5;
	}

	void BinaryArray::grow(int capacity)
	{
		StoreType* new_data = static_cast<StoreType*>(m_allocator.allocate(capacity >> 3));
		if (m_data)
		{
			memcpy(new_data, m_data, sizeof(StoreType) * (m_size + BITMASK_7BIT) >> 5);
			m_allocator.deallocate(m_data);
		}
		m_data = new_data;
		m_capacity = capacity;
	}
} // namespace Lumix<commit_msg>fixed erasing from binary array<commit_after>#include "binary_array.h"

namespace Lumix
{

	static const int BITS_IN_BYTE = 8;
	static const int BITMASK_7BIT = sizeof(int32_t) * BITS_IN_BYTE - 1;

	BinaryArray::StoreType BinaryArray::BINARY_MASK[32];
	BinaryArray::StoreType BinaryArray::INDEX_BIT[32];

	BinaryArray::Accessor::Accessor(BinaryArray& array, int index)
		: m_array(array)
		, m_index(index)
	{}

	BinaryArray::BinaryArray(IAllocator& allocator)
		: m_allocator(allocator)
		, m_data(NULL)
		, m_size(0)
		, m_capacity(0)
	{
		static bool init = false;
		if (!init)
		{
			init = true;
			for (int i = BITMASK_7BIT; i >= 0; --i)
			{
				BINARY_MASK[i] = i == BITMASK_7BIT ? 0xffffFFFF : BINARY_MASK[i + 1] << 1;
				INDEX_BIT[i] = 1 << (BITMASK_7BIT - i);
			}
		}
	}

	BinaryArray::~BinaryArray()
	{
		m_allocator.deallocate(m_data);
	}

	void BinaryArray::erase(int index)
	{
		if (0 <= index && index < m_size)
		{
			int major = index >> 5;
			const int last_major = (m_size - 1) >> 5;
			m_data[major] = ((index & BITMASK_7BIT) == 0 ? 0 : (m_data[major] & BINARY_MASK[(index & BITMASK_7BIT) - 1])) | ((m_data[major] & ~BINARY_MASK[index & BITMASK_7BIT]) << 1);
			if (major < last_major)
			{
				m_data[major] |= (m_data[major + 1] & 0x80000000) >> BITMASK_7BIT;
			}
			for (int i = major + 1; i <= last_major; ++i)
			{
				m_data[i] <<= 1;
				if (i < (m_size >> 5))
				{
					m_data[i] |= (m_data[i + 1] & 0x80000000) >> BITMASK_7BIT;
				}
			}
			if (major < last_major)
			{
				m_data[last_major] <<= 1;
			}
			--m_size;
		}
	}

	void BinaryArray::clear()
	{
		m_size = 0;
	}

	void BinaryArray::push(bool value)
	{
		if (m_capacity == m_size)
		{
			grow(m_capacity > 0 ? (m_capacity << 1) : 32);
		}
		if (value)
		{
			m_data[m_size >> 5] |= INDEX_BIT[m_size & BITMASK_7BIT];
		}
		else
		{
			m_data[m_size >> 5] &= ~INDEX_BIT[m_size & BITMASK_7BIT];
		}
		++m_size;
	}

	void BinaryArray::pop()
	{
		ASSERT(m_size > 0);
		--m_size;
	}

	bool BinaryArray::operator[](int index) const
	{
		ASSERT(index < m_size);
		return (m_data[index >> 5] & INDEX_BIT[index & BITMASK_7BIT]) > 0;
	}

	BinaryArray::Accessor BinaryArray::operator[](int index)
	{
		return Accessor(*this, index);
	}

	bool BinaryArray::back() const
	{
		ASSERT(m_size > 0);
		return (*this)[m_size - 1];
	}

	BinaryArray::Accessor BinaryArray::back()
	{
		ASSERT(m_size > 0);
		return (*this)[m_size - 1];
	}

	int BinaryArray::size() const
	{
		return m_size;
	}

	void BinaryArray::reserve(int capacity)
	{
		if ((m_capacity >> 5) < (capacity >> 5))
		{
			grow(capacity);
		}
	}

	BinaryArray::StoreType* BinaryArray::getRaw()
	{
		return m_data;
	}

	int BinaryArray::getRawSize() const
	{
		return (m_size + BITMASK_7BIT) >> 5;
	}

	void BinaryArray::grow(int capacity)
	{
		StoreType* new_data = static_cast<StoreType*>(m_allocator.allocate(capacity >> 3));
		if (m_data)
		{
			memcpy(new_data, m_data, sizeof(StoreType) * (m_size + BITMASK_7BIT) >> 5);
			m_allocator.deallocate(m_data);
		}
		m_data = new_data;
		m_capacity = capacity;
	}
} // namespace Lumix<|endoftext|>


<commit_before>/*******************************************************************************\
 * portable random api (based on clangs libcpp)                                *
 *                                               ___                           *
 *    /\/\   __ _  __ _ _ __  _   _ _ __ ___     /___\_ __  _   _ ___          *
 *   /    \ / _` |/ _` | '_ \| | | | '_ ` _ \   //  // '_ \| | | / __|         *
 *  / /\/\ \ (_| | (_| | | | | |_| | | | | | | / \_//| |_) | |_| \__ \         *
 *  \/    \/\__,_|\__, |_| |_|\__,_|_| |_| |_| \___/ | .__/ \__,_|___/         *
 *                |___/                              |_|                       *
 *                                                                             *
 * Copyright (c) 2014 Florian Oetke                                            *
 *                                                                             *
 *  This file is part of MagnumOpus and distributed under the MIT License      *
 *  See LICENSE file for details.                                              *
\*******************************************************************************/

#pragma once

#include <random>

namespace mo {
namespace util {

	namespace details {

		template <unsigned long long xp, size_t rp>
		struct log2_imp
		{
		    static const size_t value = xp & ((unsigned long long)(1) << rp) ? rp
		                                           : log2_imp<xp, rp - 1>::value;
		};

		template <unsigned long long xp>
		struct log2_imp<xp, 0>
		{
		    static const size_t value = 0;
		};

		template <size_t rp>
		struct log2_imp<0, rp>
		{
		    static const size_t value = rp + 1;
		};

		template <class U, U xp>
		struct log2
		{
		    static const size_t value = log2_imp<xp,
		                                         sizeof(U) * __CHAR_BIT__ - 1>::value;
		};

		template<class T, size_t bits, class Generator>
		auto generate_canonical(Generator& gen) -> T {
			constexpr auto dt = std::numeric_limits<T>::digits;
			constexpr auto b = dt < bits ? dt : bits;
			constexpr auto log_r = log2<uint64_t, Generator::max() - Generator::min() + uint64_t(1)>::value;
			constexpr auto k = b / log_r + (b % log_r != 0) + (b == 0);
			constexpr auto rp = Generator::max() - Generator::min() + T(1);
			auto base = rp;
			auto sp = gen() - Generator::min();
			for (size_t i = 1; i < k; ++i, base *= rp)
				sp += (gen() - Generator::min()) * base;
			return static_cast<T>(sp / base);
		}
	}

	using random_generator = std::mt19937;

	template<class T, class Generator>
	auto random_real(Generator& gen, T min, T max) -> T {
	    return (max - min)
	        * details::generate_canonical<T, std::numeric_limits<T>::digits>(gen)
	        + min;
	}

	template<class T, class Generator>
	auto random_int(Generator& gen, T min, T max) -> T	{
	    auto v = (max - min)
		        * details::generate_canonical<float, std::numeric_limits<T>::digits>(gen)
		        + min;

		return v;
	}

	/*bernoulli_distribution*/
	template<class Generator>
	auto random_bool(Generator& gen, float prop) {
		auto v = random_real(gen, 0.f, 1.f);
	    return v < prop;
	}

}
}
<commit_msg>changed rng to 64bit<commit_after>/*******************************************************************************\
 * portable random api (based on clangs libcpp)                                *
 *                                               ___                           *
 *    /\/\   __ _  __ _ _ __  _   _ _ __ ___     /___\_ __  _   _ ___          *
 *   /    \ / _` |/ _` | '_ \| | | | '_ ` _ \   //  // '_ \| | | / __|         *
 *  / /\/\ \ (_| | (_| | | | | |_| | | | | | | / \_//| |_) | |_| \__ \         *
 *  \/    \/\__,_|\__, |_| |_|\__,_|_| |_| |_| \___/ | .__/ \__,_|___/         *
 *                |___/                              |_|                       *
 *                                                                             *
 * Copyright (c) 2014 Florian Oetke                                            *
 *                                                                             *
 *  This file is part of MagnumOpus and distributed under the MIT License      *
 *  See LICENSE file for details.                                              *
\*******************************************************************************/

#pragma once

#include <random>

namespace mo {
namespace util {

	namespace details {

		template <unsigned long long xp, size_t rp>
		struct log2_imp
		{
		    static const size_t value = xp & ((unsigned long long)(1) << rp) ? rp
		                                           : log2_imp<xp, rp - 1>::value;
		};

		template <unsigned long long xp>
		struct log2_imp<xp, 0>
		{
		    static const size_t value = 0;
		};

		template <size_t rp>
		struct log2_imp<0, rp>
		{
		    static const size_t value = rp + 1;
		};

		template <class U, U xp>
		struct log2
		{
		    static const size_t value = log2_imp<xp,
		                                         sizeof(U) * __CHAR_BIT__ - 1>::value;
		};

		template<class T, size_t bits, class Generator>
		auto generate_canonical(Generator& gen) -> T {
			constexpr auto dt = std::numeric_limits<T>::digits;
			constexpr auto b = dt < bits ? dt : bits;
			constexpr auto log_r = log2<uint64_t, Generator::max() - Generator::min() + uint64_t(1)>::value;
			constexpr auto k = b / log_r + (b % log_r != 0) + (b == 0);
			constexpr auto rp = Generator::max() - Generator::min() + T(1);
			auto base = rp;
			auto sp = gen() - Generator::min();
			for (size_t i = 1; i < k; ++i, base *= rp)
				sp += (gen() - Generator::min()) * base;
			return static_cast<T>(sp / base);
		}
	}

	using random_generator = std::mt19937_64;

	template<class T, class Generator>
	auto random_real(Generator& gen, T min, T max) -> T {
	    return (max - min)
	        * details::generate_canonical<T, std::numeric_limits<T>::digits>(gen)
	        + min;
	}

	template<class T, class Generator>
	auto random_int(Generator& gen, T min, T max) -> T	{
	    auto v = (max - min)
		        * details::generate_canonical<float, std::numeric_limits<T>::digits>(gen)
		        + min;

		return v;
	}

	/*bernoulli_distribution*/
	template<class Generator>
	auto random_bool(Generator& gen, float prop) {
		auto v = random_real(gen, 0.f, 1.f);
	    return v < prop;
	}

}
}
<|endoftext|>


<commit_before>/*
 * MLPLM.cpp
 *
 *  Created on: 20.11.2013
 *      Author: cls
 */

#include "PLM.h"
#include <omp.h>
#include "../coarsening/PartitionCoarsening.h"
#include "../coarsening/ClusterContractor.h"
#include "../coarsening/ClusteringProjector.h"
#include "../auxiliary/Log.h"

#include <sstream>

namespace NetworKit {

PLM::PLM(bool refine, double gamma, std::string par, count maxIter) : parallelism(par), refine(refine), gamma(gamma), maxIter(maxIter) {

}

Partition PLM::run(const Graph& G) {
	DEBUG("calling run method on " , G.toString());

	count z = G.upperNodeIdBound();

	std::vector<bool> active(z); // record if node must be processed
	active.assign(z, true);

    std::vector<bool> satellitesV(z, false); //$$$$

	// DEBUG
	count modGainCalled = 0;
	// DEBUG

	// init communities to singletons
	Partition zeta(z);
    // init graph-dependent temporaries
	std::vector<double> volNode(z, 0.0);

	G.forNodes([&](node v) {
		zeta.toSingleton(v);

		// SATELLITE FOLLOWING: initially deactivate satellies
		if (G.degree(v) == 1) {     //$$$$updating satellite vector, deactivate satellites
			active[v] = false;
            satellitesV[v] = true;

            //$$$$ loop through neighbors, adding weights of satellites,
            G.forWeightedNeighborsOf(v, [&](node p, edgeweight weight) {
                volNode[p] += (2 * weight);

            });
		}
        // TODO: parallel

        if (G.degree(v) == 0) {     //$$$$ deactivate isolated nodes
			active[v] = false;
		}

	});
	index o = zeta.upperBound();

	// $\omega(E)$
	edgeweight total = G.totalEdgeWeight();
	DEBUG("total edge weight: " , total);
	edgeweight divisor = (2 * total * total); // needed in modularity calculation

	G.parallelForNodes([&](node u) { // calculate and store volume of each node
		volNode[u] += G.weightedDegree(u);
		volNode[u] += G.weight(u, u); // consider self-loop twice

    });

	// init community-dependent temporaries
	std::vector<double> volCommunity(o, 0.0);
	zeta.parallelForEntries([&](node u, index C) { 	// set volume for all communities
		volCommunity[C] = volNode[u];
	});

	// first move phase
	bool moved = false; // indicates whether any node has been moved in the last pass
	bool change = false; // indicates whether the communities have changed at all

	/*
	 * try to improve modularity by moving a node to neighboring clusters
	 */
	auto tryMove = [&](node u) {
		if (active[u]) { // only consider active nodes
			TRACE("trying to move node " , u);

			// collect edge weight to neighbor clusters
			std::map<index, edgeweight> affinity;
			G.forWeightedNeighborsOf(u, [&](node v, edgeweight weight) {
				if (u != v && !satellitesV[v]) {
					index C = zeta[v];
					affinity[C] += weight;
				}
			});

            //$$$$$ core nodes
            if (affinity.size() < 2) {
                active[u] = false;
                //$$$$ optional: return only if it is in the same community as all of its neighbors; in that case, the work that follows is unnecessary for such nodes
                //if (zeta[u] == C) {
                //    return;
                //}

            }

			// sub-functions

			// $\vol(C \ {x})$ - volume of cluster C excluding node x
			auto volCommunityMinusNode = [&](index C, node x) {
				double volC = 0.0;
				double volN = 0.0;
				volC = volCommunity[C];
				if (zeta[x] == C) {
					volN = volNode[x];
					return volC - volN;
				} else {
					return volC;
				}
			};

			auto modGain = [&](node u, index C, index D) {
				double volN = 0.0;
				volN = volNode[u];
				double delta = (affinity[D] - affinity[C]) / total + this->gamma * ((volCommunityMinusNode(C, u) - volCommunityMinusNode(D, u)) * volN) / divisor;
				TRACE("(" , affinity[D] , " - " , affinity[C] , ") / " , total , " + " , this->gamma , " * ((" , volCommunityMinusNode(C, u) , " - " , volCommunityMinusNode(D, u) , ") *" , volN , ") / 2 * " , (total * total));
				return delta;
			};

			index best = none;
			index C = none;
			index D = none;
			double deltaBest = -1;

			C = zeta[u];

			TRACE("Processing neighborhood of node " , u , ", which is in cluster " , C);
			//bool core = true;
			G.forNeighborsOf(u, [&](node v) {
				D = zeta[v];
                //$$$$ check if neighbor is non-satellite
				if (D != C && !satellitesV[v]) { // consider only nodes in other clusters (and implicitly only nodes other than u)
					double delta = modGain(u, C, D);
					// DEBUG
					//#pragma omp atomic update
					//∉ += 1;
					// DEBUG
					TRACE("mod gain: " , delta);
					if (delta > deltaBest) {
						deltaBest = delta;
						best = D;
					}
                    //$$$ delete code with core, not needed?
					//core = false;
				}
			});

			TRACE("deltaBest=" , deltaBest);
			if (deltaBest > 0) { // if modularity improvement possible
				assert (best != C && best != none);// do not "move" to original cluster

				zeta[u] = best; // move to best cluster
				TRACE("node " , u , " moved");

				// mod update
				double volN = 0.0;
				volN = volNode[u];
				// update the volume of the two clusters
				#pragma omp atomic update
				volCommunity[C] -= volN;
				#pragma omp atomic update
				volCommunity[best] += volN;

				moved = true; // change to clustering has been made

			} else {
				TRACE("node " , u , " not moved");
			}

			//$$$$ CORE NODE ACTIVATION: when u changes community, activate all neighbors
			if (moved) {
                G.forNeighborsOf(u, [&](node v){
                    if (!satellitesV[v]){
                        active[v] = true;
                    }
			 	});
            }

		} else {
			TRACE("node ", u, "inactive");
		}

	};

	// performs node moves
	auto movePhase = [&](){
		count iter = 0;
		do {
			moved = false;
			// apply node movement according to parallelization strategy
			if (this->parallelism == "none") {
				G.forNodes(tryMove);
			} else if (this->parallelism == "simple") {
				G.parallelForNodes(tryMove);
			} else if (this->parallelism == "balanced") {
				G.balancedParallelForNodes(tryMove);
			} else {
				ERROR("unknown parallelization strategy: " , this->parallelism);
				throw std::runtime_error("unknown parallelization strategy");
			}
			if (moved) change = true;

			if (iter == maxIter) {
				WARN("move phase aborted after ", maxIter, " iterations");
			}
			iter += 1;

			// DEBUG
			count nInactive = 0;
			G.forNodes([&](node v) {
				if (!active[v]) {
					nInactive += 1;
				}
			});
			INFO("number of inactive nodes: ", nInactive);
			INFO("modGain called: ", modGainCalled);
			// DEBUG

		} while (moved && (iter <= maxIter));
		DEBUG("iterations in move phase: ", iter);

        //$$$$ change community of satellite nodes
        G.parallelForNodes([&](node v) {
            if (satellitesV[v]) {
                G.forNeighborsOf(v, [&](node n) { //this is run only once since v is a satellite node
                    zeta[v] = zeta[n];
                });

            }
        });
	};

	// first move phase
	movePhase();

	if (change) {
		DEBUG("nodes moved, so begin coarsening and recursive call");
		std::pair<Graph, std::vector<node>> coarsened = coarsen(G, zeta);	// coarsen graph according to communitites
		Partition zetaCoarse = run(coarsened.first);

		zeta = prolong(coarsened.first, zetaCoarse, G, coarsened.second); // unpack communities in coarse graph onto fine graph
		// refinement phase
		if (refine) {
			DEBUG("refinement phase");
			// reinit community-dependent temporaries
			o = zeta.upperBound();
			volCommunity.clear();
			volCommunity.resize(o, 0.0);
			zeta.parallelForEntries([&](node u, index C) { 	// set volume for all communities
				edgeweight volN = volNode[u];
				#pragma omp atomic update
				volCommunity[C] += volN;
			});

			// second move phase
			movePhase();
		}
	}
	return zeta;
}

std::string NetworKit::PLM::toString() const {
	std::string refined;
	if (refine) {
		refined = "refinement";
	} else {
		refined = "";
	}

	std::stringstream stream;
	stream << "PLM(" << parallelism << "," << refined << ")";

	return stream.str();
}

std::pair<Graph, std::vector<node> > PLM::coarsen(const Graph& G, const Partition& zeta) {
	bool parallelCoarsening = false; // switch between parallel and sequential coarsening
	if (parallelCoarsening) {
		PartitionCoarsening parCoarsening;
		return parCoarsening.run(G, zeta);
	} else {
		ClusterContractor seqCoarsening;
		return seqCoarsening.run(G, zeta);
	}

}

Partition PLM::prolong(const Graph& Gcoarse, const Partition& zetaCoarse, const Graph& Gfine, std::vector<node> nodeToMetaNode) {
	Partition zetaFine(Gfine.upperNodeIdBound());
	zetaFine.setUpperBound(zetaCoarse.upperBound());

	Gfine.forNodes([&](node v) {
		node mv = nodeToMetaNode[v];
		index cv = zetaCoarse[mv];
		zetaFine[v] = cv;
	});

	return zetaFine;
}

} /* namespace NetworKit */
<commit_msg>original PLM code<commit_after>/*
 * MLPLM.cpp
 *
 *  Created on: 20.11.2013
 *      Author: cls
 */

#include "PLM.h"
#include <omp.h>
#include "../coarsening/PartitionCoarsening.h"
#include "../coarsening/ClusterContractor.h"
#include "../coarsening/ClusteringProjector.h"
#include "../auxiliary/Log.h"

#include <sstream>

namespace NetworKit {

PLM::PLM(bool refine, double gamma, std::string par, count maxIter) : parallelism(par), refine(refine), gamma(gamma), maxIter(maxIter) {

}

Partition PLM::run(Graph& G) {
	DEBUG("calling run method on " , G.toString());

	count z = G.upperNodeIdBound();

	// init communities to singletons
	Partition zeta(z);
	G.forNodes([&](node v) {
		zeta.toSingleton(v);
	});
	index o = zeta.upperBound();

	// init graph-dependent temporaries
	std::vector<double> volNode(z, 0.0);
	// $\omega(E)$
	edgeweight total = G.totalEdgeWeight();
	DEBUG("total edge weight: " , total);
	edgeweight divisor = (2 * total * total); // needed in modularity calculation

	G.parallelForNodes([&](node u) { // calculate and store volume of each node
		volNode[u] += G.weightedDegree(u);
		volNode[u] += G.weight(u, u); // consider self-loop twice
		// TRACE("init volNode[" , u , "] to " , volNode[u]);
	});

	// init community-dependent temporaries
	std::vector<double> volCommunity(o, 0.0);
	zeta.parallelForEntries([&](node u, index C) { 	// set volume for all communities
		volCommunity[C] = volNode[u];
	});

	// first move phase
	bool moved = false; // indicates whether any node has been moved in the last pass
	bool change = false; // indicates whether the communities have changed at all

	// try to improve modularity by moving a node to neighboring clusters
	auto tryMove = [&](node u) {
		// TRACE("trying to move node " , u);

		// collect edge weight to neighbor clusters
		std::map<index, edgeweight> affinity;
		G.forWeightedNeighborsOf(u, [&](node v, edgeweight weight) {
			if (u != v) {
				index C = zeta[v];
				affinity[C] += weight;
			}
		});

		// sub-functions

		// $\vol(C \ {x})$ - volume of cluster C excluding node x
		auto volCommunityMinusNode = [&](index C, node x) {
			double volC = 0.0;
			double volN = 0.0;
			volC = volCommunity[C];
			if (zeta[x] == C) {
				volN = volNode[x];
				return volC - volN;
			} else {
				return volC;
			}
		};

		// // $\omega(u | C \ u)$
		// auto omegaCut = [&](node u, index C) {
		// 	return affinity[C];
		// };

		auto modGain = [&](node u, index C, index D) {
			double volN = 0.0;
			volN = volNode[u];
			double delta = (affinity[D] - affinity[C]) / total + this->gamma * ((volCommunityMinusNode(C, u) - volCommunityMinusNode(D, u)) * volN) / divisor;
			//TRACE("(" , affinity[D] , " - " , affinity[C] , ") / " , total , " + " , this->gamma , " * ((" , volCommunityMinusNode(C, u) , " - " , volCommunityMinusNode(D, u) , ") *" , volN , ") / 2 * " , (total * total));
			return delta;
		};

		index best = none;
		index C = none;
		index D = none;
		double deltaBest = -1;

		C = zeta[u];

//			TRACE("Processing neighborhood of node " , u , ", which is in cluster " , C);
		G.forNeighborsOf(u, [&](node v) {
			D = zeta[v];
			if (D != C) { // consider only nodes in other clusters (and implicitly only nodes other than u)
				double delta = modGain(u, C, D);
				// TRACE("mod gain: " , delta); // FIXME: all mod gains are negative
				if (delta > deltaBest) {
					deltaBest = delta;
					best = D;
				}
			}
		});

		// TRACE("deltaBest=" , deltaBest); // FIXME: best mod gain is negative
		if (deltaBest > 0) { // if modularity improvement possible
			assert (best != C && best != none);// do not "move" to original cluster

			zeta[u] = best; // move to best cluster
			// TRACE("node " , u , " moved");

			// mod update
			double volN = 0.0;
			volN = volNode[u];
			// update the volume of the two clusters
			#pragma omp atomic update
			volCommunity[C] -= volN;
			#pragma omp atomic update
			volCommunity[best] += volN;

			moved = true; // change to clustering has been made

		} else {
			// TRACE("node " , u , " not moved");
		}
	};

	// performs node moves
	auto movePhase = [&](){
		count iter = 0;
		do {
			moved = false;
			// apply node movement according to parallelization strategy
			if (this->parallelism == "none") {
				G.forNodes(tryMove);
			} else if (this->parallelism == "simple") {
				G.parallelForNodes(tryMove);
			} else if (this->parallelism == "balanced") {
				G.balancedParallelForNodes(tryMove);
			} else {
				ERROR("unknown parallelization strategy: " , this->parallelism);
				throw std::runtime_error("unknown parallelization strategy");
			}
			if (moved) change = true;

			if (iter == maxIter) {
				WARN("move phase aborted after ", maxIter, " iterations");
			}
			iter += 1;
		} while (moved && (iter <= maxIter));
		DEBUG("iterations in move phase: ", iter);
	};

	// first move phase
	movePhase();

	if (change) {
		DEBUG("nodes moved, so begin coarsening and recursive call");
		std::pair<Graph, std::vector<node>> coarsened = coarsen(G, zeta);	// coarsen graph according to communitites
		Partition zetaCoarse = run(coarsened.first);

		zeta = prolong(coarsened.first, zetaCoarse, G, coarsened.second); // unpack communities in coarse graph onto fine graph
		// refinement phase
		if (refine) {
			DEBUG("refinement phase");
			// reinit community-dependent temporaries
			o = zeta.upperBound();
			volCommunity.clear();
			volCommunity.resize(o, 0.0);
			zeta.parallelForEntries([&](node u, index C) { 	// set volume for all communities
				edgeweight volN = volNode[u];
				#pragma omp atomic update
				volCommunity[C] += volN;
			});

			// second move phase
			movePhase();
		}
	}
	return zeta;
}

std::string NetworKit::PLM::toString() const {
	std::string refined;
	if (refine) {
		refined = "refinement";
	} else {
		refined = "";
	}

	std::stringstream stream;
	stream << "PLM(" << parallelism << "," << refined << ")";

	return stream.str();
}

std::pair<Graph, std::vector<node> > PLM::coarsen(const Graph& G, const Partition& zeta) {
	bool parallelCoarsening = false; // switch between parallel and sequential coarsening
	if (parallelCoarsening) {
		PartitionCoarsening parCoarsening;
		return parCoarsening.run(G, zeta);
	} else {
		ClusterContractor seqCoarsening;
		return seqCoarsening.run(G, zeta);
	}

}

Partition PLM::prolong(const Graph& Gcoarse, const Partition& zetaCoarse, const Graph& Gfine, std::vector<node> nodeToMetaNode) {
	Partition zetaFine(Gfine.upperNodeIdBound());
	zetaFine.setUpperBound(zetaCoarse.upperBound());

	Gfine.forNodes([&](node v) {
		node mv = nodeToMetaNode[v];
		index cv = zetaCoarse[mv];
		zetaFine[v] = cv;
	});

	return zetaFine;
}

} /* namespace NetworKit */

<|endoftext|>


<commit_before>/// HEADER
#include <csapex.h>

/// PROJECT
#include <csapex/core/csapex_core.h>
#include <csapex/core/settings/settings_local.h>
#include <csapex/msg/generic_vector_message.hpp>
#include <csapex/param/parameter_factory.h>
#include <csapex/utility/error_handling.h>
#include <csapex/utility/exceptions.h>
#include <csapex/utility/thread.h>
#include <csapex/view/csapex_view_core_local.h>
#include <csapex/view/csapex_view_core_remote.h>
#include <csapex/view/csapex_window.h>
#include <csapex/view/gui_exception_handler.h>
#include <csapex/io/server.h>
#include <csapex/model/graph_facade.h>

/// SYSTEM
#include <iostream>
#include <QtGui>
#include <QStatusBar>
#include <QMessageBox>
#include <boost/program_options.hpp>
#define BOOST_NO_CXX11_SCOPED_ENUMS
#include <boost/filesystem.hpp>
#undef BOOST_NO_CXX11_SCOPED_ENUMS
#include <boost/version.hpp>

#if (BOOST_VERSION / 100000) >= 1 && (BOOST_VERSION / 100 % 1000) >= 54
namespace bf3 = boost::filesystem;
#else
namespace bf3 = boost::filesystem3;
#endif

namespace po = boost::program_options;

using namespace csapex;

CsApexGuiApp::CsApexGuiApp(int& argc, char** argv, ExceptionHandler &handler)
    : QApplication(argc, argv), handler(handler)
{}

CsApexCoreApp::CsApexCoreApp(int& argc, char** argv, ExceptionHandler &handler)
    : QCoreApplication(argc, argv), handler(handler)
{}

bool CsApexCoreApp::notify(QObject* receiver, QEvent* event) {
    try {
        return QCoreApplication::notify(receiver, event);

    } catch(...) {
        std::exception_ptr eptr = std::current_exception();
        handler.handleException(eptr);
        return true;
    }
}

bool CsApexGuiApp::notify(QObject* receiver, QEvent* event) {
    try {
        return QApplication::notify(receiver, event);

    } catch(...) {
        std::exception_ptr eptr = std::current_exception();
        handler.handleException(eptr);
        return true;
    }
}

Main::Main(std::unique_ptr<QCoreApplication> &&a, Settings& settings, ExceptionHandler& handler)
    : app(std::move(a)), settings(settings), handler(handler), splash(nullptr), recover_needed(false)
{
    csapex::thread::set_name("cs::APEX main");
}

Main::~Main()
{
    delete splash;
}

int Main::runImpl()
{
    csapex::error_handling::init();

    int result = app->exec();

    return result;
}

int Main::runWithGui()
{
    app->processEvents();

//    CsApexViewCoreLocal view_core(core);
    CsApexViewCoreRemote view_core("localhost", 12345, core);

    CsApexWindow w(view_core);
    QObject::connect(&w, SIGNAL(statusChanged(QString)), this, SLOT(showMessage(QString)));

    app->connect(&w, &CsApexWindow::closed, app.get(), &QCoreApplication::quit);
    app->connect(app.get(), SIGNAL(lastWindowClosed()), app.get(), SLOT(quit()));

    csapex::error_handling::stop_request().connect([this](){
        static int request = 0;
        if(request == 0) {
            core->shutdown();
            std::cout << "shutdown request" << std::endl;
        } else if(request >= 3) {
            raise(SIGTERM);
        }

        ++request;
    });

    core->shutdown_requested.connect([this](){
        QCoreApplication::postEvent(app.get(), new QCloseEvent);
        app->quit();
    });

    checkRecoveryFile(view_core, w);

    w.start();
    core->startup();

    w.show();
    splash->finish(&w);

    core->startMainLoop();

    int res = runImpl();

    deleteRecoveryConfig();

    return res;
}

int Main::runHeadless()
{
    GraphFacadePtr root = core->getRoot();
    csapex::error_handling::stop_request().connect([this, root](){
        core->shutdown();
        app->quit();
    });
    core->startup();

    return runImpl();
}

int Main::run()
{
    bool headless = settings.get<bool>("headless");

    std::string config_to_load = settings.get<std::string>("config");

    if(!headless) {
        splash = new CsApexSplashScreen;
        splash->show();

        settings.set("config_recovery", false);
        askForRecoveryConfig(config_to_load);

        showMessage("loading libraries");
    }

    core = std::make_shared<CsApexCore>(settings, handler);

    try {
        server = std::make_shared<Server>(core);
        server->start();
    } catch (const boost::system::system_error& ex) {
        std::cerr << "Could not start command server: [" << ex.code() << "] " << ex.what() << std::endl;
    }

    if(headless) {
        return runHeadless();
    } else {
        return runWithGui();
    }
}

void Main::checkRecoveryFile(CsApexViewCore &view_core, CsApexWindow &w)
{
    QTimer *timer = new QTimer(this);
    QObject::connect(timer, &QTimer::timeout, [&](){
        if(recover_needed) {
            recover_needed = false;
            std::string temp_file_name = settings.get("config")->as<std::string>() + ".recover";
            core->saveAs(temp_file_name, true);
            w.statusBar()->showMessage(tr("Recovery file saved."));
        }
    });
    timer->start(settings.getPersistent("config_recovery_save_interval", 1000));
    observe(view_core.undo_state_changed, [&](){
        recover_needed = true;
    });
}

void Main::askForRecoveryConfig(const std::string& config_to_load)
{
    bf3::path temp_file = config_to_load + ".recover";
    if(bf3::exists(temp_file)) {
        showMessage("handling recovery file");

        std::time_t mod_time_t = bf3::last_write_time(temp_file);
        char mod_time[20];
        strftime(mod_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&mod_time_t));

        std::string question = "The application did not exit correctly. "
                               "Do you want to recover
" +
                temp_file.filename().string() +
                "?
(last modified: " + mod_time + ")";

        QMessageBox::StandardButton reply = QMessageBox::question(nullptr, "Configuration Recovery",
                                                                  QString::fromStdString(question),
                                                                  QMessageBox::Yes | QMessageBox::No);
        if (reply == QMessageBox::Yes) {
            settings.set("config_recovery", true);
            settings.set("config_recovery_file", temp_file.string());
            settings.set("config_recovery_original", config_to_load);
        }
    }
}

void Main::deleteRecoveryConfig()
{
    bool recovery = settings.getTemporary("config_recovery", false);
    if(!recovery) {
        bf3::path temp_file = settings.get("config")->as<std::string>() + ".recover";
        if(bf3::exists(temp_file)) {
            bf3::remove(temp_file);
        }
    }
}

void Main::showMessage(const QString& msg)
{
    if(splash->isVisible()) {
        splash->showMessage(msg);
    }
    app->processEvents();
}

int main(int argc, char** argv)
{
    SettingsLocal settings;

    int effective_argc = argc;
    std::string path_to_bin(argv[0]);

    po::options_description desc("Allowed options");
    desc.add_options()
            ("help", "show help message")
            ("debug", "enable debug output")
            ("dump", "show variables")
            ("paused", "start paused")
            ("headless", "run without gui")
            ("threadless", "run without threading")
            ("fatal_exceptions", "abort execution on exception")
            ("disable_thread_grouping", "by default create one thread per node")
            ("input", "config file to load")
            ;

    po::positional_options_description p;
    p.add("input", 1);

    // first check for --headless or --fatal_exceptions parameter
    // this has to be done before the qapp can be created, which
    // has to be done before parameters can be read.
    bool headless = false;
    bool fatal_exceptions = false;
    for(int i = 1; i < effective_argc; ++i) {
        std::string arg(argv[i]);
        if(arg == "--headless") {
            headless = true;
        } else if(arg == "--fatal_exceptions") {
            fatal_exceptions = true;
        }
    }

    if(!headless) {
        // if headless not requested, check if there is a display
        // if not, we enforce headless mode
#if WIN32
        if (false) {
#else
        if (!getenv("DISPLAY")) {
#endif
            headless = true;
            std::cout << "warning: enforcing headless mode because there is no display detected" << std::endl;
        }
    }

    std::shared_ptr<ExceptionHandler> handler;

    // filters all qt parameters from argv
    std::unique_ptr<QCoreApplication> app;
    if(headless) {
        handler.reset(new ExceptionHandler(fatal_exceptions));
        app.reset(new CsApexCoreApp(effective_argc, argv, *handler));
    } else {
        std::shared_ptr<GuiExceptionHandler> h(new GuiExceptionHandler(fatal_exceptions));

        handler = h;
        app.reset(new CsApexGuiApp(effective_argc, argv, *handler));

        h->moveToThread(app->thread());
    }

    // filters ros remappings
    std::vector<std::string> remapping_args;
    std::vector<std::string> rest_args;
    for(int i = 1; i < effective_argc; ++i) {
        std::string arg(argv[i]);
        if(arg.find(":=") != std::string::npos)  {
            remapping_args.push_back(arg);
        } else {
            rest_args.push_back(arg);
        }
    }

    // now check for remaining parameters
    po::variables_map vm;
    std::vector<std::string> additional_args;

    try {
        po::parsed_options parsed = po::command_line_parser(rest_args).options(desc).positional(p).run();

        po::store(parsed, vm);

        po::notify(vm);

        additional_args = po::collect_unrecognized(parsed.options, po::include_positional);

    } catch(const std::exception& e) {
        std::cerr << "cannot parse parameters: " << e.what() << std::endl;
        return 4;
    }

    // add ros remappings
    additional_args.insert(additional_args.end(), remapping_args.begin(), remapping_args.end());

    // display help?
    if(vm.count("help")) {
        std::cerr << desc << std::endl;
        return 1;
    }
    if(vm.count("dump")) {
        std::cout << "to be passed on:\n";
        for(std::size_t i = 0; i < additional_args.size(); ++i) {
            std::cout << additional_args[i] << '\n';
        }
        std::cout << std::flush;
        return 0;
    }

    // which file to use?
    if (vm.count("input")) {
        settings.set("config",vm["input"].as<std::string>());
    } else {
        settings.set("config",Settings::default_config);
    }

    if(!settings.knows("path_to_bin")) {
        settings.addTemporary(csapex::param::ParameterFactory::declareFileInputPath("path_to_bin", path_to_bin));
    } else {
        settings.set("path_to_bin", path_to_bin);
    }

    settings.set("debug", vm.count("debug") > 0);
    settings.set("headless", headless);
    settings.set("threadless", vm.count("threadless") > 0);
    settings.set("thread_grouping", vm.count("disable_thread_grouping") == 0);
    settings.set("additional_args", additional_args);
    settings.set("initially_paused", vm.count("paused") > 0);

    settings.set("access-test", std::string("access granted."));

    // start the app
    Main m(std::move(app), settings, *handler);
    try {
        return m.run();

    } catch(const csapex::Failure& af) {
        std::cerr << af.what() << std::endl;
        return 42;
    }
}

/// MOC
#include "moc_csapex.cpp"
<commit_msg>no remote classes by default<commit_after>/// HEADER
#include <csapex.h>

/// PROJECT
#include <csapex/core/csapex_core.h>
#include <csapex/core/settings/settings_local.h>
#include <csapex/msg/generic_vector_message.hpp>
#include <csapex/param/parameter_factory.h>
#include <csapex/utility/error_handling.h>
#include <csapex/utility/exceptions.h>
#include <csapex/utility/thread.h>
#include <csapex/view/csapex_view_core_local.h>
#include <csapex/view/csapex_view_core_remote.h>
#include <csapex/view/csapex_window.h>
#include <csapex/view/gui_exception_handler.h>
#include <csapex/io/server.h>
#include <csapex/model/graph_facade.h>

/// SYSTEM
#include <iostream>
#include <QtGui>
#include <QStatusBar>
#include <QMessageBox>
#include <boost/program_options.hpp>
#define BOOST_NO_CXX11_SCOPED_ENUMS
#include <boost/filesystem.hpp>
#undef BOOST_NO_CXX11_SCOPED_ENUMS
#include <boost/version.hpp>

#if (BOOST_VERSION / 100000) >= 1 && (BOOST_VERSION / 100 % 1000) >= 54
namespace bf3 = boost::filesystem;
#else
namespace bf3 = boost::filesystem3;
#endif

namespace po = boost::program_options;

using namespace csapex;

CsApexGuiApp::CsApexGuiApp(int& argc, char** argv, ExceptionHandler &handler)
    : QApplication(argc, argv), handler(handler)
{}

CsApexCoreApp::CsApexCoreApp(int& argc, char** argv, ExceptionHandler &handler)
    : QCoreApplication(argc, argv), handler(handler)
{}

bool CsApexCoreApp::notify(QObject* receiver, QEvent* event) {
    try {
        return QCoreApplication::notify(receiver, event);

    } catch(...) {
        std::exception_ptr eptr = std::current_exception();
        handler.handleException(eptr);
        return true;
    }
}

bool CsApexGuiApp::notify(QObject* receiver, QEvent* event) {
    try {
        return QApplication::notify(receiver, event);

    } catch(...) {
        std::exception_ptr eptr = std::current_exception();
        handler.handleException(eptr);
        return true;
    }
}

Main::Main(std::unique_ptr<QCoreApplication> &&a, Settings& settings, ExceptionHandler& handler)
    : app(std::move(a)), settings(settings), handler(handler), splash(nullptr), recover_needed(false)
{
    csapex::thread::set_name("cs::APEX main");
}

Main::~Main()
{
    delete splash;
}

int Main::runImpl()
{
    csapex::error_handling::init();

    int result = app->exec();

    return result;
}

int Main::runWithGui()
{
    app->processEvents();

    CsApexViewCoreLocal view_core(core);
//    CsApexViewCoreRemote view_core("localhost", 12345, core);

    CsApexWindow w(view_core);
    QObject::connect(&w, SIGNAL(statusChanged(QString)), this, SLOT(showMessage(QString)));

    app->connect(&w, &CsApexWindow::closed, app.get(), &QCoreApplication::quit);
    app->connect(app.get(), SIGNAL(lastWindowClosed()), app.get(), SLOT(quit()));

    csapex::error_handling::stop_request().connect([this](){
        static int request = 0;
        if(request == 0) {
            core->shutdown();
            std::cout << "shutdown request" << std::endl;
        } else if(request >= 3) {
            raise(SIGTERM);
        }

        ++request;
    });

    core->shutdown_requested.connect([this](){
        QCoreApplication::postEvent(app.get(), new QCloseEvent);
        app->quit();
    });

    checkRecoveryFile(view_core, w);

    w.start();
    core->startup();

    w.show();
    splash->finish(&w);

    core->startMainLoop();

    int res = runImpl();

    deleteRecoveryConfig();

    return res;
}

int Main::runHeadless()
{
    GraphFacadePtr root = core->getRoot();
    csapex::error_handling::stop_request().connect([this, root](){
        core->shutdown();
        app->quit();
    });
    core->startup();

    return runImpl();
}

int Main::run()
{
    bool headless = settings.get<bool>("headless");

    std::string config_to_load = settings.get<std::string>("config");

    if(!headless) {
        splash = new CsApexSplashScreen;
        splash->show();

        settings.set("config_recovery", false);
        askForRecoveryConfig(config_to_load);

        showMessage("loading libraries");
    }

    core = std::make_shared<CsApexCore>(settings, handler);

    try {
        server = std::make_shared<Server>(core);
        server->start();
    } catch (const boost::system::system_error& ex) {
        std::cerr << "Could not start command server: [" << ex.code() << "] " << ex.what() << std::endl;
    }

    if(headless) {
        return runHeadless();
    } else {
        return runWithGui();
    }
}

void Main::checkRecoveryFile(CsApexViewCore &view_core, CsApexWindow &w)
{
    QTimer *timer = new QTimer(this);
    QObject::connect(timer, &QTimer::timeout, [&](){
        if(recover_needed) {
            recover_needed = false;
            std::string temp_file_name = settings.get("config")->as<std::string>() + ".recover";
            core->saveAs(temp_file_name, true);
            w.statusBar()->showMessage(tr("Recovery file saved."));
        }
    });
    timer->start(settings.getPersistent("config_recovery_save_interval", 1000));
    observe(view_core.undo_state_changed, [&](){
        recover_needed = true;
    });
}

void Main::askForRecoveryConfig(const std::string& config_to_load)
{
    bf3::path temp_file = config_to_load + ".recover";
    if(bf3::exists(temp_file)) {
        showMessage("handling recovery file");

        std::time_t mod_time_t = bf3::last_write_time(temp_file);
        char mod_time[20];
        strftime(mod_time, 20, "%Y-%m-%d %H:%M:%S", localtime(&mod_time_t));

        std::string question = "The application did not exit correctly. "
                               "Do you want to recover
" +
                temp_file.filename().string() +
                "?
(last modified: " + mod_time + ")";

        QMessageBox::StandardButton reply = QMessageBox::question(nullptr, "Configuration Recovery",
                                                                  QString::fromStdString(question),
                                                                  QMessageBox::Yes | QMessageBox::No);
        if (reply == QMessageBox::Yes) {
            settings.set("config_recovery", true);
            settings.set("config_recovery_file", temp_file.string());
            settings.set("config_recovery_original", config_to_load);
        }
    }
}

void Main::deleteRecoveryConfig()
{
    bool recovery = settings.getTemporary("config_recovery", false);
    if(!recovery) {
        bf3::path temp_file = settings.get("config")->as<std::string>() + ".recover";
        if(bf3::exists(temp_file)) {
            bf3::remove(temp_file);
        }
    }
}

void Main::showMessage(const QString& msg)
{
    if(splash->isVisible()) {
        splash->showMessage(msg);
    }
    app->processEvents();
}

int main(int argc, char** argv)
{
    SettingsLocal settings;

    int effective_argc = argc;
    std::string path_to_bin(argv[0]);

    po::options_description desc("Allowed options");
    desc.add_options()
            ("help", "show help message")
            ("debug", "enable debug output")
            ("dump", "show variables")
            ("paused", "start paused")
            ("headless", "run without gui")
            ("threadless", "run without threading")
            ("fatal_exceptions", "abort execution on exception")
            ("disable_thread_grouping", "by default create one thread per node")
            ("input", "config file to load")
            ;

    po::positional_options_description p;
    p.add("input", 1);

    // first check for --headless or --fatal_exceptions parameter
    // this has to be done before the qapp can be created, which
    // has to be done before parameters can be read.
    bool headless = false;
    bool fatal_exceptions = false;
    for(int i = 1; i < effective_argc; ++i) {
        std::string arg(argv[i]);
        if(arg == "--headless") {
            headless = true;
        } else if(arg == "--fatal_exceptions") {
            fatal_exceptions = true;
        }
    }

    if(!headless) {
        // if headless not requested, check if there is a display
        // if not, we enforce headless mode
#if WIN32
        if (false) {
#else
        if (!getenv("DISPLAY")) {
#endif
            headless = true;
            std::cout << "warning: enforcing headless mode because there is no display detected" << std::endl;
        }
    }

    std::shared_ptr<ExceptionHandler> handler;

    // filters all qt parameters from argv
    std::unique_ptr<QCoreApplication> app;
    if(headless) {
        handler.reset(new ExceptionHandler(fatal_exceptions));
        app.reset(new CsApexCoreApp(effective_argc, argv, *handler));
    } else {
        std::shared_ptr<GuiExceptionHandler> h(new GuiExceptionHandler(fatal_exceptions));

        handler = h;
        app.reset(new CsApexGuiApp(effective_argc, argv, *handler));

        h->moveToThread(app->thread());
    }

    // filters ros remappings
    std::vector<std::string> remapping_args;
    std::vector<std::string> rest_args;
    for(int i = 1; i < effective_argc; ++i) {
        std::string arg(argv[i]);
        if(arg.find(":=") != std::string::npos)  {
            remapping_args.push_back(arg);
        } else {
            rest_args.push_back(arg);
        }
    }

    // now check for remaining parameters
    po::variables_map vm;
    std::vector<std::string> additional_args;

    try {
        po::parsed_options parsed = po::command_line_parser(rest_args).options(desc).positional(p).run();

        po::store(parsed, vm);

        po::notify(vm);

        additional_args = po::collect_unrecognized(parsed.options, po::include_positional);

    } catch(const std::exception& e) {
        std::cerr << "cannot parse parameters: " << e.what() << std::endl;
        return 4;
    }

    // add ros remappings
    additional_args.insert(additional_args.end(), remapping_args.begin(), remapping_args.end());

    // display help?
    if(vm.count("help")) {
        std::cerr << desc << std::endl;
        return 1;
    }
    if(vm.count("dump")) {
        std::cout << "to be passed on:\n";
        for(std::size_t i = 0; i < additional_args.size(); ++i) {
            std::cout << additional_args[i] << '\n';
        }
        std::cout << std::flush;
        return 0;
    }

    // which file to use?
    if (vm.count("input")) {
        settings.set("config",vm["input"].as<std::string>());
    } else {
        settings.set("config",Settings::default_config);
    }

    if(!settings.knows("path_to_bin")) {
        settings.addTemporary(csapex::param::ParameterFactory::declareFileInputPath("path_to_bin", path_to_bin));
    } else {
        settings.set("path_to_bin", path_to_bin);
    }

    settings.set("debug", vm.count("debug") > 0);
    settings.set("headless", headless);
    settings.set("threadless", vm.count("threadless") > 0);
    settings.set("thread_grouping", vm.count("disable_thread_grouping") == 0);
    settings.set("additional_args", additional_args);
    settings.set("initially_paused", vm.count("paused") > 0);

    settings.set("access-test", std::string("access granted."));

    // start the app
    Main m(std::move(app), settings, *handler);
    try {
        return m.run();

    } catch(const csapex::Failure& af) {
        std::cerr << af.what() << std::endl;
        return 42;
    }
}

/// MOC
#include "moc_csapex.cpp"
<|endoftext|>


<commit_before>#include <Arduino.h>
#include "Relay.h"

// Relay is active low, so you need a 0 to turn it on.
#define RELAY_ON 0
#define RELAY_OFF 1
#define MAX_TIME_ON 1000

#define MAD_RELAY_LOGGING 1

Relay::Relay( int whatPin )
{
  // initialize variables
  pin = whatPin;
  run = false;
  last_changed = millis();
  duration_on = 0;

  // initialize physical objects
  pinMode( pin, OUTPUT );

  // don't forget that we don't know the state of the pin
  // so give it one
  digitalWrite( pin, RELAY_OFF );

  off();
}

void Relay::on()
{
  if( ! run )
  {
    run = true;
    last_changed = millis();
  }
  digitalWrite( pin, RELAY_ON );

}

void Relay::off()
{
  if ( run ) {
    run = false;
    last_changed = millis();
  }
  duration_on = 0;
  digitalWrite( pin, RELAY_OFF );
}

unsigned long Relay::time_running() {
  if ( run ) {
    return millis() - last_changed;
  }
  return 0;
}

bool Relay::running()
{
  return run;
}

#pragma mark - Should be in Subclass for Fire Relay

void Relay::loop() {

  unsigned long now = millis();

  if ( run ) {

#if MAD_RELAY_LOGGING
  Serial.print(time_running());
  Serial.println("ms running");
#endif

  if ( duration_on && now > last_changed + duration_on ) {

#if MAD_RELAY_LOGGING
    Serial.println("Duration expired on Relay. Turning off now");
#endif
    off();

   } else if ( run && ( time_running() > MAX_TIME_ON ) ) {

#if MAD_RELAY_LOGGING
    Serial.println("Relay left on for too long. Turning off now");
#endif
    off();

  } else {

#if MAD_RELAY_LOGGING
    if ( duration_on ) {
      unsigned long time_remaining = last_changed + duration_on - now;
      Serial.print(time_remaining);
      Serial.println("ms remaining");
    }
#endif

    }
  }
}

void Relay::setOnForDuration( unsigned long duration ) {

  on();
  duration_on = duration;

  last_changed = millis();     // in case we were already on, we want a better value for last_changed

#if MAD_RELAY_LOGGING
  Serial.print("Relay on with a duration = ");
  Serial.print(duration);
  Serial.println(" ms");
#endif
}
<commit_msg>disable relay logging<commit_after>#include <Arduino.h>
#include "Relay.h"

// Relay is active low, so you need a 0 to turn it on.
#define RELAY_ON 0
#define RELAY_OFF 1
#define MAX_TIME_ON 1000

#define MAD_RELAY_LOGGING 0

Relay::Relay( int whatPin )
{
  // initialize variables
  pin = whatPin;
  run = false;
  last_changed = millis();
  duration_on = 0;

  // initialize physical objects
  pinMode( pin, OUTPUT );

  // don't forget that we don't know the state of the pin
  // so give it one
  digitalWrite( pin, RELAY_OFF );

  off();
}

void Relay::on()
{
  if( ! run )
  {
    run = true;
    last_changed = millis();
  }
  digitalWrite( pin, RELAY_ON );

}

void Relay::off()
{
  if ( run ) {
    run = false;
    last_changed = millis();
  }
  duration_on = 0;
  digitalWrite( pin, RELAY_OFF );
}

unsigned long Relay::time_running() {
  if ( run ) {
    return millis() - last_changed;
  }
  return 0;
}

bool Relay::running()
{
  return run;
}

#pragma mark - Should be in Subclass for Fire Relay

void Relay::loop() {

  unsigned long now = millis();

  if ( run ) {

#if MAD_RELAY_LOGGING
  Serial.print(time_running());
  Serial.println("ms running");
#endif

  if ( duration_on && now > last_changed + duration_on ) {

#if MAD_RELAY_LOGGING
    Serial.println("Duration expired on Relay. Turning off now");
#endif
    off();

   } else if ( run && ( time_running() > MAX_TIME_ON ) ) {

#if MAD_RELAY_LOGGING
    Serial.println("Relay left on for too long. Turning off now");
#endif
    off();

  } else {

#if MAD_RELAY_LOGGING
    if ( duration_on ) {
      unsigned long time_remaining = last_changed + duration_on - now;
      Serial.print(time_remaining);
      Serial.println("ms remaining");
    }
#endif

    }
  }
}

void Relay::setOnForDuration( unsigned long duration ) {

  on();
  duration_on = duration;

  last_changed = millis();     // in case we were already on, we want a better value for last_changed

#if MAD_RELAY_LOGGING
  Serial.print("Relay on with a duration = ");
  Serial.print(duration);
  Serial.println(" ms");
#endif
}
<|endoftext|>