<commit_before>// Copyright 2016-2019 Chris Conway (Koderz). All Rights Reserved.

#include "RuntimeMeshProviderPlane.h"

FRuntimeMeshProviderPlaneProxy::FRuntimeMeshProviderPlaneProxy(TWeakObjectPtr<URuntimeMeshProvider> InParent)
	: FRuntimeMeshProviderProxy(InParent)
{

}

FRuntimeMeshProviderPlaneProxy::~FRuntimeMeshProviderPlaneProxy()
{

}

void FRuntimeMeshProviderPlaneProxy::UpdateProxyParameters(URuntimeMeshProvider* ParentProvider, bool bIsInitialSetup)
{
	URuntimeMeshProviderPlane* PlaneProvider = Cast<URuntimeMeshProviderPlane>(ParentProvider);
	MarkCollisionDirty();
	if (LocationA != PlaneProvider->LocationA || LocationB != PlaneProvider->LocationB || LocationC != PlaneProvider->LocationC)
	{
		LocationA = PlaneProvider->LocationA;
		LocationB = PlaneProvider->LocationB;
		LocationC = PlaneProvider->LocationC;
		MarkSectionDirty(INDEX_NONE, 0); //Mark all LODs dirty
	}
	bool bHasParameterChanged = false;
	TArray<int32> VertsABBefore = VertsAB, VertsACBefore = VertsAC;
	if (VertsAB != PlaneProvider->VertsAB)
	{
		bHasParameterChanged = true;
		VertsAB = PlaneProvider->VertsAB;
	}
	if (VertsAC != PlaneProvider->VertsAC)
	{
		bHasParameterChanged = true;
		VertsAC = PlaneProvider->VertsAC;
	}
	if (ScreenSize != PlaneProvider->ScreenSize)
	{
		bHasParameterChanged = true;
		ScreenSize = PlaneProvider->ScreenSize;
	}
	Material = PlaneProvider->Material;
	int32 MaxLODBefore = MaxLOD;
	MaxLOD = GetMaximumPossibleLOD();
	if (!bIsInitialSetup && bHasParameterChanged)
	{
		for (int32 LODIndex = 0; LODIndex <= MaxLOD; LODIndex++)
		{
			FRuntimeMeshLODProperties LODProperties;
			LODProperties.ScreenSize = LODIndex >= ScreenSize.Num() ? 0.0 : ScreenSize[LODIndex];
			ConfigureLOD(LODIndex, LODProperties);

			if (LODIndex >= MaxLODBefore) //Section is new
			{
				FRuntimeMeshSectionProperties Properties;
				Properties.bCastsShadow = true;
				Properties.bIsVisible = true;
				Properties.MaterialSlot = 0;
				Properties.UpdateFrequency = ERuntimeMeshUpdateFrequency::Infrequent;
				CreateSection(LODIndex, 0, Properties);
			}
			else if(VertsAB[LODIndex] != VertsABBefore[LODIndex] || VertsAC[LODIndex] != VertsACBefore[LODIndex])
			{
				MarkSectionDirty(LODIndex, 0);
			}
		}
		for (int32 LODIndex = MaxLOD; LODIndex < MaxLODBefore; LODIndex++)
		{
			RemoveSection(LODIndex, 0);
		}
	}

}

void FRuntimeMeshProviderPlaneProxy::Initialize()
{
	for (int32 LODIndex = 0; LODIndex <= MaxLOD; LODIndex++)
	{
		FRuntimeMeshLODProperties LODProperties;
		LODProperties.ScreenSize = LODIndex >= ScreenSize.Num() ? 0.0 : ScreenSize[LODIndex];
		ConfigureLOD(LODIndex, LODProperties);

		FRuntimeMeshSectionProperties Properties;
		Properties.bCastsShadow = true;
		Properties.bIsVisible = true;
		Properties.MaterialSlot = 0;
		Properties.UpdateFrequency = ERuntimeMeshUpdateFrequency::Infrequent;
		CreateSection(LODIndex, 0, Properties);

	}
	SetupMaterialSlot(0, FName("Plane Base"), Material.Get());
}

bool FRuntimeMeshProviderPlaneProxy::GetSectionMeshForLOD(int32 LODIndex, int32 SectionId, FRuntimeMeshRenderableMeshData& MeshData)
{
	// We should only ever be queried for section 0
	check(SectionId == 0 && LODIndex <= MaxLOD);
	//UE_LOG(LogTemp, Log, TEXT("Asking for LOD index %i, VertsAB len = %i, VertsAC len = %i"), LODIndex, VertsAB.Num(), VertsAC.Num());
	//return true;
	int32 NumVertsAB = VertsAB[LODIndex], NumVertsAC = VertsAC[LODIndex];
	FVector ABDirection = (LocationB - LocationA) / (NumVertsAB - 1);
	FVector ACDirection = (LocationC - LocationA) / (NumVertsAB - 1);
	FVector Normal = (ACDirection ^ ABDirection).GetUnsafeNormal();
	FVector Tangent = ABDirection.GetUnsafeNormal();
	FColor Color = FColor::White;
	for (int32 ACIndex = 0; ACIndex < NumVertsAC; ACIndex++)
	{
		for (int32 ABIndex = 0; ABIndex < NumVertsAB; ABIndex++)
		{
			FVector Location = LocationA + ABDirection * ABIndex + ACDirection * ACIndex;
			FVector2D TexCoord = FVector2D(ABIndex / NumVertsAB, ACIndex / NumVertsAC);
			MeshData.Positions.Add(Location);
			MeshData.Tangents.Add(Normal, Tangent);
			MeshData.Colors.Add(Color);
			MeshData.TexCoords.Add(TexCoord);
			if (ABIndex != NumVertsAB - 1 && ACIndex != NumVertsAC - 1)
			{
				int32 AIndex = ABIndex + ACIndex * NumVertsAB;
				int32 BIndex = AIndex + 1;
				int32 CIndex = AIndex + NumVertsAB;
				int32 DIndex = CIndex + 1;
				MeshData.Triangles.AddTriangle(AIndex, CIndex, BIndex);
				MeshData.Triangles.AddTriangle(BIndex, CIndex, DIndex);
			}
		}
	}

	return true;
}

FRuntimeMeshCollisionSettings FRuntimeMeshProviderPlaneProxy::GetCollisionSettings()
{
	FRuntimeMeshCollisionSettings Settings;
	Settings.bUseAsyncCooking = false;
	Settings.bUseComplexAsSimple = true;

	return Settings;
}

bool FRuntimeMeshProviderPlaneProxy::HasCollisionMesh()
{
	return false;
}

bool FRuntimeMeshProviderPlaneProxy::GetCollisionMesh(FRuntimeMeshCollisionData& CollisionData)
{
	return false;
}

URuntimeMeshProviderPlane::URuntimeMeshProviderPlane()
{
	LocationA = FVector(100, -100, 0);
	LocationB = FVector(100, 100, 0);
	LocationC = FVector(-100, -100, 0);
	VertsAB = TArray<int32>({100,10,1});
	VertsAC = TArray<int32>({100,10,1});
	ScreenSize = TArray<float>({ 0.1,0.01 });
}<commit_msg>Plane provider now automatically switches to 32bit indices<commit_after>// Copyright 2016-2019 Chris Conway (Koderz). All Rights Reserved.

#include "RuntimeMeshProviderPlane.h"

FRuntimeMeshProviderPlaneProxy::FRuntimeMeshProviderPlaneProxy(TWeakObjectPtr<URuntimeMeshProvider> InParent)
	: FRuntimeMeshProviderProxy(InParent)
{

}

FRuntimeMeshProviderPlaneProxy::~FRuntimeMeshProviderPlaneProxy()
{

}

void FRuntimeMeshProviderPlaneProxy::UpdateProxyParameters(URuntimeMeshProvider* ParentProvider, bool bIsInitialSetup)
{
	URuntimeMeshProviderPlane* PlaneProvider = Cast<URuntimeMeshProviderPlane>(ParentProvider);
	MarkCollisionDirty();
	if (LocationA != PlaneProvider->LocationA || LocationB != PlaneProvider->LocationB || LocationC != PlaneProvider->LocationC)
	{
		LocationA = PlaneProvider->LocationA;
		LocationB = PlaneProvider->LocationB;
		LocationC = PlaneProvider->LocationC;
		MarkSectionDirty(INDEX_NONE, 0); //Mark all LODs dirty
	}
	bool bHasParameterChanged = false;
	TArray<int32> VertsABBefore = VertsAB, VertsACBefore = VertsAC;
	if (VertsAB != PlaneProvider->VertsAB)
	{
		bHasParameterChanged = true;
		VertsAB = PlaneProvider->VertsAB;
	}
	if (VertsAC != PlaneProvider->VertsAC)
	{
		bHasParameterChanged = true;
		VertsAC = PlaneProvider->VertsAC;
	}
	if (ScreenSize != PlaneProvider->ScreenSize)
	{
		bHasParameterChanged = true;
		ScreenSize = PlaneProvider->ScreenSize;
	}
	Material = PlaneProvider->Material;
	int32 MaxLODBefore = MaxLOD;
	MaxLOD = GetMaximumPossibleLOD();
	if (!bIsInitialSetup && bHasParameterChanged)
	{
		for (int32 LODIndex = 0; LODIndex <= MaxLOD; LODIndex++)
		{
			FRuntimeMeshLODProperties LODProperties;
			LODProperties.ScreenSize = LODIndex >= ScreenSize.Num() ? 0.0 : ScreenSize[LODIndex];
			ConfigureLOD(LODIndex, LODProperties);

			if (LODIndex >= MaxLODBefore) //Section is new
			{
				FRuntimeMeshSectionProperties Properties;
				Properties.bCastsShadow = true;
				Properties.bIsVisible = true;
				Properties.MaterialSlot = 0;
				Properties.UpdateFrequency = ERuntimeMeshUpdateFrequency::Infrequent;
				Properties.bWants32BitIndices = VertsAB[LODIndex] * VertsAC[LODIndex] >= 1 << 16; //Use 32 bit indices if more than 2^16 verts are needed

				CreateSection(LODIndex, 0, Properties);
			}
			else if(VertsAB[LODIndex] != VertsABBefore[LODIndex] || VertsAC[LODIndex] != VertsACBefore[LODIndex])
			{
				MarkSectionDirty(LODIndex, 0);
			}
		}
		for (int32 LODIndex = MaxLOD; LODIndex < MaxLODBefore; LODIndex++)
		{
			RemoveSection(LODIndex, 0);
		}
	}

}

void FRuntimeMeshProviderPlaneProxy::Initialize()
{
	for (int32 LODIndex = 0; LODIndex <= MaxLOD; LODIndex++)
	{
		FRuntimeMeshLODProperties LODProperties;
		LODProperties.ScreenSize = LODIndex >= ScreenSize.Num() ? 0.0 : ScreenSize[LODIndex];
		ConfigureLOD(LODIndex, LODProperties);

		FRuntimeMeshSectionProperties Properties;
		Properties.bCastsShadow = true;
		Properties.bIsVisible = true;
		Properties.MaterialSlot = 0;
		Properties.UpdateFrequency = ERuntimeMeshUpdateFrequency::Infrequent;
		CreateSection(LODIndex, 0, Properties);

	}
	SetupMaterialSlot(0, FName("Plane Base"), Material.Get());
}

bool FRuntimeMeshProviderPlaneProxy::GetSectionMeshForLOD(int32 LODIndex, int32 SectionId, FRuntimeMeshRenderableMeshData& MeshData)
{
	// We should only ever be queried for section 0
	check(SectionId == 0 && LODIndex <= MaxLOD);
	//UE_LOG(LogTemp, Log, TEXT("Asking for LOD index %i, VertsAB len = %i, VertsAC len = %i"), LODIndex, VertsAB.Num(), VertsAC.Num());
	//return true;
	int32 NumVertsAB = VertsAB[LODIndex], NumVertsAC = VertsAC[LODIndex];
	FVector ABDirection = (LocationB - LocationA) / (NumVertsAB - 1);
	FVector ACDirection = (LocationC - LocationA) / (NumVertsAB - 1);
	FVector Normal = (ACDirection ^ ABDirection).GetUnsafeNormal();
	FVector Tangent = ABDirection.GetUnsafeNormal();
	FColor Color = FColor::White;
	for (int32 ACIndex = 0; ACIndex < NumVertsAC; ACIndex++)
	{
		for (int32 ABIndex = 0; ABIndex < NumVertsAB; ABIndex++)
		{
			FVector Location = LocationA + ABDirection * ABIndex + ACDirection * ACIndex;
			FVector2D TexCoord = FVector2D(ABIndex / NumVertsAB, ACIndex / NumVertsAC);
			MeshData.Positions.Add(Location);
			MeshData.Tangents.Add(Normal, Tangent);
			MeshData.Colors.Add(Color);
			MeshData.TexCoords.Add(TexCoord);
			if (ABIndex != NumVertsAB - 1 && ACIndex != NumVertsAC - 1)
			{
				int32 AIndex = ABIndex + ACIndex * NumVertsAB;
				int32 BIndex = AIndex + 1;
				int32 CIndex = AIndex + NumVertsAB;
				int32 DIndex = CIndex + 1;
				MeshData.Triangles.AddTriangle(AIndex, CIndex, BIndex);
				MeshData.Triangles.AddTriangle(BIndex, CIndex, DIndex);
			}
		}
	}

	return true;
}

FRuntimeMeshCollisionSettings FRuntimeMeshProviderPlaneProxy::GetCollisionSettings()
{
	FRuntimeMeshCollisionSettings Settings;
	Settings.bUseAsyncCooking = false;
	Settings.bUseComplexAsSimple = true;

	return Settings;
}

bool FRuntimeMeshProviderPlaneProxy::HasCollisionMesh()
{
	return false;
}

bool FRuntimeMeshProviderPlaneProxy::GetCollisionMesh(FRuntimeMeshCollisionData& CollisionData)
{
	return false;
}

URuntimeMeshProviderPlane::URuntimeMeshProviderPlane()
{
	LocationA = FVector(100, -100, 0);
	LocationB = FVector(100, 100, 0);
	LocationC = FVector(-100, -100, 0);
	VertsAB = TArray<int32>({100,10,1});
	VertsAC = TArray<int32>({100,10,1});
	ScreenSize = TArray<float>({ 0.1,0.01 });
}<|endoftext|>


<commit_before>// (C) 2014 Arek Olek

#pragma once

#include <iostream>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

struct graph_writer {
  bool labels;
  graph_writer(bool l) : labels(l) {}
  virtual void operator()(std::ostream& out) const {
    if(labels) {
      out << "node [shape=circle color=burlywood style=filled]" << std::endl;
      out << "edge [style=dashed color=burlywood penwidth=4 weight=0.3]" << std::endl;
    } else {
      out << "node [shape=point color=burlywood style=filled label=\"\" width=0.05]" << std::endl;
      out << "edge [style=dashed color=burlywood]" << std::endl;
    }
  }
};

template <class Graph>
class node_writer {
public:
  node_writer(Graph const& t) : T(t) {}
  template <class V>
  void operator()(std::ostream& out, const V& v) const {
    if(out_degree(v, T) == 1)
      out << "[shape=square color=forestgreen]";
    if(out_degree(v, T) > 2)
      out << "[color=brown1]";
  }
private:
  Graph const& T;
};

template <class Graph>
node_writer<Graph> make_node_writer(Graph t) {
  return node_writer<Graph>(t);
}

template<class Graph, class Tree>
class edge_writer {
public:
  edge_writer(Graph const& g, Tree const& t) : G(g), T(t) {}
  template <class E>
  void operator()(std::ostream& out, const E& e) const {
    if(edge(source(e, G), target(e, G), T).second)
      out << "[style=solid]";
  }
private:
  Graph const& G;
  Tree const& T;
};

template<class Graph, class Tree>
edge_writer<Graph, Tree> make_edge_writer(Graph g, Tree t) {
  return edge_writer<Graph, Tree>(g, t);
}

template<class Graph, class Tree>
void show(std::string file, Graph const & g, Tree const & t) {
  std::ofstream f(file);
  write_graphviz(f, g,
    make_node_writer(t),
    make_edge_writer(g, t),
    graph_writer(num_vertices(g) < 30));
  f.close();
}
<commit_msg>draw graph without spanning tree<commit_after>// (C) 2014 Arek Olek

#pragma once

#include <iostream>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

struct graph_writer {
  bool labels;
  graph_writer(bool l) : labels(l) {}
  virtual void operator()(std::ostream& out) const {
    if(labels) {
      out << "node [shape=circle color=burlywood style=filled]" << std::endl;
      out << "edge [style=dashed color=burlywood penwidth=4 weight=0.3]" << std::endl;
    } else {
      out << "node [shape=point color=burlywood style=filled label=\"\" width=0.05]" << std::endl;
      out << "edge [style=dashed color=burlywood]" << std::endl;
    }
  }
};

template <class Graph>
class node_writer {
public:
  node_writer(Graph const& t) : T(t) {}
  template <class V>
  void operator()(std::ostream& out, const V& v) const {
    if(out_degree(v, T) == 1)
      out << "[shape=square color=forestgreen]";
    if(out_degree(v, T) > 2)
      out << "[color=brown1]";
  }
private:
  Graph const& T;
};

template <class Graph>
node_writer<Graph> make_node_writer(Graph t) {
  return node_writer<Graph>(t);
}

template<class Graph, class Tree>
class edge_writer {
public:
  edge_writer(Graph const& g, Tree const& t) : G(g), T(t) {}
  template <class E>
  void operator()(std::ostream& out, const E& e) const {
    if(edge(source(e, G), target(e, G), T).second)
      out << "[style=solid]";
  }
private:
  Graph const& G;
  Tree const& T;
};

template<class Graph, class Tree>
edge_writer<Graph, Tree> make_edge_writer(Graph g, Tree t) {
  return edge_writer<Graph, Tree>(g, t);
}

template<class Graph, class Tree>
void show(std::string file, Graph const & g, Tree const & t) {
  std::ofstream f(file);
  write_graphviz(f, g,
    make_node_writer(t),
    make_edge_writer(g, t),
    graph_writer(num_vertices(g) < 30));
  f.close();
}

template<class Graph>
void show(std::string file, Graph const & g) {
  std::ofstream f(file);
  write_graphviz(f, g,
    boost::default_writer(),
    boost::default_writer(),
    graph_writer(false));
  f.close();
}
<|endoftext|>


<commit_before>#include "DerivativeBaseMaterial.h"

template<>
InputParameters validParams<DerivativeBaseMaterial>()
{
  InputParameters params = validParams<Material>();
  params.addClassDescription("KKS model helper material to provide the free energy and its first and second derivatives");
  params.addParam<std::string>("f_name", "F", "Base name of the free energy function (used to name the material properties)");
  params.addRequiredCoupledVar("args", "Arguments of F() - use vector coupling");
  params.addParam<bool>("third_derivatives", true, "Calculate third derivatoves of the free energy");
  return params;
}

DerivativeBaseMaterial::DerivativeBaseMaterial(const std::string & name,
                                               InputParameters parameters) :
    DerivativeMaterialInterface<Material>(name, parameters),
    _F_name(getParam<std::string>("f_name")),
    _nargs(coupledComponents("args")),
    _third_derivatives(getParam<bool>("third_derivatives")),
    _prop_F(&declareProperty<Real>(_F_name))
{
  // loop counters
  unsigned int i, j, k;

  // coupled variables
  _args.resize(_nargs);

  // reserve space for material properties
  _prop_dF.resize(_nargs);
  _prop_d2F.resize(_nargs);
  _prop_d3F.resize(_nargs);
  for (i = 0; i < _nargs; ++i)
  {
    _prop_d2F[i].resize(_nargs);

    // TODO: maybe we should reserve and initialize to NULL...
    if (_third_derivatives) {
      _prop_d3F[i].resize(_nargs);

      for (unsigned int j = 0; j < _nargs; ++j)
        _prop_d3F[i][j].resize(_nargs);
    }
  }

  // fetch names of variables in args
  _arg_names.resize(_nargs);
  for (i = 0; i < _nargs; ++i)
    _arg_names[i] = getVar("args", i)->name();

  // initialize derivatives
  for (i = 0; i < _nargs; ++i)
  {
    // get the coupled variable to use as function arguments
    _args[i] = &coupledValue("args", i);

    // first derivatives
    _prop_dF[i] = &declareProperty<Real>(propertyNameFirst(_F_name, _arg_names[i]));

    // second derivatives
    for (j = i; j < _nargs; ++j)
    {
      _prop_d2F[i][j] =
      _prop_d2F[j][i] =
        &declareProperty<Real>(
          propertyNameSecond(_F_name, _arg_names[i], _arg_names[j])
        );

      // third derivatives
      if (_third_derivatives)
      {
        for (k = j; k < _nargs; ++k)
        {
          // filling all permutations does not cost us much and simplifies access
          // (no need to check i<=j<=k)
          _prop_d3F[i][j][k] =
          _prop_d3F[k][i][j] =
          _prop_d3F[j][k][i] =
          _prop_d3F[k][j][i] =
          _prop_d3F[j][i][k] =
          _prop_d3F[i][k][j] =
            &declareProperty<Real>(
              propertyNameThird(_F_name, _arg_names[i], _arg_names[j], _arg_names[k])
            );
        }
      }
    }
  }
}

void
DerivativeBaseMaterial::initialSetup()
{
  if (_nargs != expectedNumArgs()) {
    mooseError("Wrong number of arguments supplied for DerivativeBaseMaterial " + _F_name);
  }

  // set the _prop_* pointers of all material poroperties that are not beeing used back to NULL
  unsigned int i, j, k;
  bool needs_third_derivatives = false;

  if (!_fe_problem.isMatPropRequested(_F_name))
    _prop_F = NULL;

  for (i = 0; i < _nargs; ++i)
  {
    if (!_fe_problem.isMatPropRequested(propertyNameFirst(_F_name, _arg_names[i])))
      _prop_dF[i] = NULL;

    // second derivatives
    for (j = i; j < _nargs; ++j)
    {
      if (!_fe_problem.isMatPropRequested(propertyNameSecond(_F_name, _arg_names[i], _arg_names[j])))
        _prop_d2F[i][j] =
        _prop_d2F[j][i] = NULL;

      // third derivatives
      if (_third_derivatives)
      {
        for (k = j; k < _nargs; ++k)
        {
          if (!_fe_problem.isMatPropRequested(propertyNameThird(_F_name, _arg_names[i], _arg_names[j], _arg_names[k])))
            _prop_d3F[i][j][k] =
            _prop_d3F[k][i][j] =
            _prop_d3F[j][k][i] =
            _prop_d3F[k][j][i] =
            _prop_d3F[j][i][k] =
            _prop_d3F[i][k][j] = NULL;
          else
            needs_third_derivatives = true;
        }

        if (!needs_third_derivatives)
          mooseWarning("This simulation does not actually need the third derivatives of DerivativeBaseMaterial " + _name);
      }
    }
  }
}

// implementing this in the derived class is optional (not really, but we'l have to check what is needed for the residuals!)
Real
DerivativeBaseMaterial::computeD3F(unsigned int /*arg1*/, unsigned int /*arg2*/, unsigned int /*arg3*/)
{
  return 0.0;
}

void
DerivativeBaseMaterial::computeProperties()
{
  unsigned int i, j, k;

  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
  {
    // set function value
    if (_prop_F)
      (*_prop_F)[_qp] = computeF();

    for (i = 0; i < _nargs; ++i)
    {
      // set first derivatives
      if (_prop_dF[i])
        (*_prop_dF[i])[_qp] = computeDF(i);

      // second derivatives
      for (j = i; j < _nargs; ++j)
      {
        if (_prop_d2F[i][j])
          (*_prop_d2F[i][j])[_qp] = computeD2F(i, j);

        // third derivatives
        if (_third_derivatives)
        {
          for (k = j; k < _nargs; ++k)
            if (_prop_d3F[i][j][k])
              (*_prop_d3F[i][j][k])[_qp] = computeD3F(i, j, k);
        }
      }
    }
  }
}
<commit_msg>Use declarePropertyDerivative in DerivativeBaseMaterial (#4300)<commit_after>#include "DerivativeBaseMaterial.h"

template<>
InputParameters validParams<DerivativeBaseMaterial>()
{
  InputParameters params = validParams<Material>();
  params.addClassDescription("KKS model helper material to provide the free energy and its first and second derivatives");
  params.addParam<std::string>("f_name", "F", "Base name of the free energy function (used to name the material properties)");
  params.addRequiredCoupledVar("args", "Arguments of F() - use vector coupling");
  params.addParam<bool>("third_derivatives", true, "Calculate third derivatoves of the free energy");
  return params;
}

DerivativeBaseMaterial::DerivativeBaseMaterial(const std::string & name,
                                               InputParameters parameters) :
    DerivativeMaterialInterface<Material>(name, parameters),
    _F_name(getParam<std::string>("f_name")),
    _nargs(coupledComponents("args")),
    _third_derivatives(getParam<bool>("third_derivatives")),
    _prop_F(&declareProperty<Real>(_F_name))
{
  // loop counters
  unsigned int i, j, k;

  // coupled variables
  _args.resize(_nargs);

  // reserve space for material properties
  _prop_dF.resize(_nargs);
  _prop_d2F.resize(_nargs);
  _prop_d3F.resize(_nargs);
  for (i = 0; i < _nargs; ++i)
  {
    _prop_d2F[i].resize(_nargs);

    // TODO: maybe we should reserve and initialize to NULL...
    if (_third_derivatives) {
      _prop_d3F[i].resize(_nargs);

      for (unsigned int j = 0; j < _nargs; ++j)
        _prop_d3F[i][j].resize(_nargs);
    }
  }

  // fetch names of variables in args
  _arg_names.resize(_nargs);
  for (i = 0; i < _nargs; ++i)
    _arg_names[i] = getVar("args", i)->name();

  // initialize derivatives
  for (i = 0; i < _nargs; ++i)
  {
    // get the coupled variable to use as function arguments
    _args[i] = &coupledValue("args", i);

    // first derivatives
    _prop_dF[i] = &declarePropertyDerivative<Real>(_F_name, _arg_names[i]);

    // second derivatives
    for (j = i; j < _nargs; ++j)
    {
      _prop_d2F[i][j] =
      _prop_d2F[j][i] = &declarePropertyDerivative<Real>(_F_name, _arg_names[i], _arg_names[j]);

      // third derivatives
      if (_third_derivatives)
      {
        for (k = j; k < _nargs; ++k)
        {
          // filling all permutations does not cost us much and simplifies access
          // (no need to check i<=j<=k)
          _prop_d3F[i][j][k] =
          _prop_d3F[k][i][j] =
          _prop_d3F[j][k][i] =
          _prop_d3F[k][j][i] =
          _prop_d3F[j][i][k] =
          _prop_d3F[i][k][j] = &declarePropertyDerivative<Real>(_F_name, _arg_names[i], _arg_names[j], _arg_names[k]);
        }
      }
    }
  }
}

void
DerivativeBaseMaterial::initialSetup()
{
  if (_nargs != expectedNumArgs()) {
    mooseError("Wrong number of arguments supplied for DerivativeBaseMaterial " + _F_name);
  }

  // set the _prop_* pointers of all material poroperties that are not beeing used back to NULL
  unsigned int i, j, k;
  bool needs_third_derivatives = false;

  if (!_fe_problem.isMatPropRequested(_F_name))
    _prop_F = NULL;

  for (i = 0; i < _nargs; ++i)
  {
    if (!_fe_problem.isMatPropRequested(propertyNameFirst(_F_name, _arg_names[i])))
      _prop_dF[i] = NULL;

    // second derivatives
    for (j = i; j < _nargs; ++j)
    {
      if (!_fe_problem.isMatPropRequested(propertyNameSecond(_F_name, _arg_names[i], _arg_names[j])))
        _prop_d2F[i][j] =
        _prop_d2F[j][i] = NULL;

      // third derivatives
      if (_third_derivatives)
      {
        for (k = j; k < _nargs; ++k)
        {
          if (!_fe_problem.isMatPropRequested(propertyNameThird(_F_name, _arg_names[i], _arg_names[j], _arg_names[k])))
            _prop_d3F[i][j][k] =
            _prop_d3F[k][i][j] =
            _prop_d3F[j][k][i] =
            _prop_d3F[k][j][i] =
            _prop_d3F[j][i][k] =
            _prop_d3F[i][k][j] = NULL;
          else
            needs_third_derivatives = true;
        }

        if (!needs_third_derivatives)
          mooseWarning("This simulation does not actually need the third derivatives of DerivativeBaseMaterial " + _name);
      }
    }
  }
}

// implementing this in the derived class is optional (not really, but we'l have to check what is needed for the residuals!)
Real
DerivativeBaseMaterial::computeD3F(unsigned int /*arg1*/, unsigned int /*arg2*/, unsigned int /*arg3*/)
{
  return 0.0;
}

void
DerivativeBaseMaterial::computeProperties()
{
  unsigned int i, j, k;

  for (_qp = 0; _qp < _qrule->n_points(); _qp++)
  {
    // set function value
    if (_prop_F)
      (*_prop_F)[_qp] = computeF();

    for (i = 0; i < _nargs; ++i)
    {
      // set first derivatives
      if (_prop_dF[i])
        (*_prop_dF[i])[_qp] = computeDF(i);

      // second derivatives
      for (j = i; j < _nargs; ++j)
      {
        if (_prop_d2F[i][j])
          (*_prop_d2F[i][j])[_qp] = computeD2F(i, j);

        // third derivatives
        if (_third_derivatives)
        {
          for (k = j; k < _nargs; ++k)
            if (_prop_d3F[i][j][k])
              (*_prop_d3F[i][j][k])[_qp] = computeD3F(i, j, k);
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file
 **/

#include "modules/planning/scenarios/side_pass/side_pass_scenario.h"

#include <fstream>
#include <limits>
#include <utility>

#include "cyber/common/log.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/time/time.h"
#include "modules/common/util/file.h"
#include "modules/common/util/string_tokenizer.h"
#include "modules/common/util/string_util.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/map/hdmap/hdmap.h"
#include "modules/map/hdmap/hdmap_common.h"
#include "modules/planning/common/ego_info.h"
#include "modules/planning/common/frame.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/constraint_checker/constraint_checker.h"
#include "modules/planning/toolkits/optimizers/dp_poly_path/dp_poly_path_optimizer.h"
#include "modules/planning/toolkits/optimizers/dp_st_speed/dp_st_speed_optimizer.h"
#include "modules/planning/toolkits/optimizers/path_decider/path_decider.h"
#include "modules/planning/toolkits/optimizers/poly_st_speed/poly_st_speed_optimizer.h"
#include "modules/planning/toolkits/optimizers/qp_spline_path/qp_spline_path_optimizer.h"
#include "modules/planning/toolkits/optimizers/qp_spline_st_speed/qp_spline_st_speed_optimizer.h"
#include "modules/planning/toolkits/optimizers/speed_decider/speed_decider.h"

namespace apollo {
namespace planning {

using common::ErrorCode;
using common::SLPoint;
using common::SpeedPoint;
using common::TrajectoryPoint;
using common::math::Vec2d;
using common::time::Clock;

namespace {
constexpr double kPathOptimizationFallbackCost = 2e4;
constexpr double kSpeedOptimizationFallbackCost = 2e4;
constexpr double kStraightForwardLineCost = 10.0;
}  // namespace

void SidePassScenario::Init() {
  if (init_) {
    return;
  }

  Scenario::Init();

  init_ = true;
}

apollo::common::util::Factory<
    ScenarioConfig::StageType, Stage,
    Stage* (*)(const ScenarioConfig::StageConfig& stage_config)>
    SidePassScenario::s_stage_factory_;

void SidePassScenario::RegisterStages() {
  s_stage_factory_.Clear();
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_APPROACH_OBSTACLE,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassApproachObstacle(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_DETECT_SAFETY,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassDetectSafety(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_GENERATE_PATH,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassGeneratePath(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_STOP_ON_WAITPOINT,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassStopOnWaitPoint(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_PASS_OBSTACLE,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassPassObstacle(config);
      });
}

std::unique_ptr<Stage> SidePassScenario::CreateStage(
    const ScenarioConfig::StageConfig& stage_config) {
  if (s_stage_factory_.Empty()) {
    RegisterStages();
  }
  auto ptr = s_stage_factory_.CreateObjectOrNull(stage_config.stage_type(),
                                                 stage_config);
  ptr->SetContext(&side_pass_context_);
  return ptr;
}

bool SidePassScenario::IsTransferable(const Scenario& current_scenario,
                                      const common::TrajectoryPoint& ego_point,
                                      const Frame& frame) const {
  if (frame.reference_line_info().size() > 1) {
    return false;
  }
  if (current_scenario.scenario_type() == ScenarioConfig::SIDE_PASS) {
    return (current_scenario.GetStatus() !=
            Scenario::ScenarioStatus::STATUS_DONE);
  } else if (current_scenario.scenario_type() != ScenarioConfig::LANE_FOLLOW) {
    return false;
  } else {
    return IsSidePassScenario(ego_point, frame);
  }
}

Stage::StageStatus SidePassApproachObstacle::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  bool plan_ok = PlanningOnReferenceLine(planning_start_point, frame);
  if (!plan_ok) {
    return Stage::ERROR;
  }
  if (frame->vehicle_state().linear_velocity() < 1.0e-5) {
    next_stage_ = ScenarioConfig::SIDE_PASS_GENERATE_PATH;
    return Stage::FINISHED;
  }
  return Stage::RUNNING;
}

Stage::StageStatus SidePassGeneratePath::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  if (PlanningOnReferenceLine(planning_start_point, frame)) {
    next_stage_ = ScenarioConfig::SIDE_PASS_STOP_ON_WAITPOINT;
    return Stage::FINISHED;
  } else {
    return Stage::ERROR;
  }
}

Stage::StageStatus SidePassStopOnWaitPoint::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  bool all_far_away = false;
  const PathDecision& path_decision =
      frame->reference_line_info().front().path_decision();
  for (const auto* path_obstacle : path_decision.path_obstacles().Items()) {
    if (path_obstacle->obstacle()->IsVirtual()) {
      continue;
    }
    // TODO(All): check all ST boundaries are far away.
  }
  if (!all_far_away) {
    // wait here, do nothing this cycle.
    return Stage::RUNNING;
  }
  double move_forward_distance = 5.0;
  for (const auto& path_point :
       GetContext()->path_data_.discretized_path().path_points()) {
    // TODO(All):
    // (1) check if the ego car on path_point will partially go into the
    // neighbor
    // lane.
    // (2) update move_forward_distance
    CHECK_GE(path_point.s(), 0.0);
    CHECK_GE(move_forward_distance, 0.0);
  }
  // TODO(All):
  // (1) call proceed with cautious
  // (2) combine path and speed.

  next_stage_ = ScenarioConfig::SIDE_PASS_DETECT_SAFETY;
  return Stage::FINISHED;
}

Stage::StageStatus SidePassDetectSafety::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  if (PlanningOnReferenceLine(planning_start_point, frame)) {
    return Stage::ERROR;
  }
  bool is_safe = true;
  const PathDecision& path_decision =
      frame->reference_line_info().front().path_decision();
  for (const auto* path_obstacle : path_decision.path_obstacles().Items()) {
    if (path_obstacle->obstacle()->IsVirtual()) {
      is_safe = false;
      break;
    }
  }
  if (is_safe) {
    next_stage_ = ScenarioConfig::SIDE_PASS_PASS_OBSTACLE;
    return Stage::FINISHED;
  }
  return Stage::RUNNING;
}

Stage::StageStatus SidePassPassObstacle::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  bool plan_ok = PlanningOnReferenceLine(planning_start_point, frame);
  if (!plan_ok) {
    return Stage::ERROR;
  }
  const SLBoundary& adc_sl_boundary =
      frame->reference_line_info().front().AdcSlBoundary();
  const auto& frenet_frame_path =
      frame->reference_line_info().front().path_data().frenet_frame_path();
  const auto& frenet_frame_point =
      frenet_frame_path.PointAt(frenet_frame_path.NumOfPoints() - 1);
  int adc_start_s = adc_sl_boundary.start_s();
  int path_end_s = frenet_frame_point.s();
  if ((path_end_s - adc_start_s) > 20.0) {
    next_stage_ = ScenarioConfig::NO_STAGE;
    return Stage::FINISHED;
  }
  return Stage::RUNNING;
}

bool SidePassScenario::IsSidePassScenario(
    const common::TrajectoryPoint& planning_start_point,
    const Frame& frame) const {
  const SLBoundary& adc_sl_boundary =
      frame.reference_line_info().front().AdcSlBoundary();
  const PathDecision& path_decision =
      frame.reference_line_info().front().path_decision();
  // TODO(lianglia-apollo)

  return HasBlockingObstacle(adc_sl_boundary, path_decision);
}

bool SidePassScenario::IsFarFromIntersection(const Frame& frame) {
  if (frame.reference_line_info().size() > 1) {
    return false;
  }
  const SLBoundary& adc_sl_boundary =
      frame.reference_line_info().front().AdcSlBoundary();
  const auto& first_encounters =
      frame.reference_line_info().front().FirstEncounteredOverlaps();
  const double kClearDistance = 15.0;  // in meters
  for (const auto& encounter : first_encounters) {
    if (encounter.first != ReferenceLineInfo::SIGNAL ||
        encounter.first != ReferenceLineInfo::STOP_SIGN) {
      continue;
    }
    if (encounter.second.start_s - adc_sl_boundary.end_s() < kClearDistance) {
      return false;
    }
  }
  return true;
}

bool SidePassScenario::HasBlockingObstacle(
    const SLBoundary& adc_sl_boundary,
    const PathDecision& path_decision) const {
  // a blocking obstacle is an obstacle blocks the road when it is not blocked
  // (by other obstacles or traffic rules)
  for (const auto* path_obstacle : path_decision.path_obstacles().Items()) {
    if (path_obstacle->obstacle()->IsVirtual() ||
        !path_obstacle->obstacle()->IsStatic()) {
      continue;
    }
    CHECK(path_obstacle->obstacle()->IsStatic());

    if (path_obstacle->PerceptionSLBoundary().start_s() <=
        adc_sl_boundary.end_s()) {  // such vehicles are behind the adc.
      continue;
    }
    constexpr double kAdcDistanceThreshold = 15.0;  // unit: m
    if (path_obstacle->PerceptionSLBoundary().start_s() >
        adc_sl_boundary.end_s() +
            kAdcDistanceThreshold) {  // vehicles are far away
      continue;
    }
    if (path_obstacle->PerceptionSLBoundary().start_l() > 1.0 ||
        path_obstacle->PerceptionSLBoundary().end_l() < -1.0) {
      continue;
    }

    bool is_blocked_by_others = false;
    for (const auto* other_obstacle : path_decision.path_obstacles().Items()) {
      if (other_obstacle->Id() == path_obstacle->Id()) {
        continue;
      }
      if (other_obstacle->PerceptionSLBoundary().start_l() >
              path_obstacle->PerceptionSLBoundary().end_l() ||
          other_obstacle->PerceptionSLBoundary().end_l() <
              path_obstacle->PerceptionSLBoundary().start_l()) {
        // not blocking the backside vehicle
        continue;
      }

      double delta_s = other_obstacle->PerceptionSLBoundary().start_s() -
                       path_obstacle->PerceptionSLBoundary().end_s();
      if (delta_s < 0.0 || delta_s > kAdcDistanceThreshold) {
        continue;
      } else {
        // TODO(All): fixed the segmentation bug for large vehicles, otherwise
        // the follow line will be problematic.
        // is_blocked_by_others = true; break;
      }
    }
    if (!is_blocked_by_others) {
      return true;
    }
  }
  return false;
}

}  // namespace planning
}  // namespace apollo
<commit_msg>planning: updated side pass scenario exit condition.<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file
 **/

#include "modules/planning/scenarios/side_pass/side_pass_scenario.h"

#include <fstream>
#include <limits>
#include <utility>

#include "cyber/common/log.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/time/time.h"
#include "modules/common/util/file.h"
#include "modules/common/util/string_tokenizer.h"
#include "modules/common/util/string_util.h"
#include "modules/common/vehicle_state/vehicle_state_provider.h"
#include "modules/map/hdmap/hdmap.h"
#include "modules/map/hdmap/hdmap_common.h"
#include "modules/planning/common/ego_info.h"
#include "modules/planning/common/frame.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/constraint_checker/constraint_checker.h"
#include "modules/planning/toolkits/optimizers/dp_poly_path/dp_poly_path_optimizer.h"
#include "modules/planning/toolkits/optimizers/dp_st_speed/dp_st_speed_optimizer.h"
#include "modules/planning/toolkits/optimizers/path_decider/path_decider.h"
#include "modules/planning/toolkits/optimizers/poly_st_speed/poly_st_speed_optimizer.h"
#include "modules/planning/toolkits/optimizers/qp_spline_path/qp_spline_path_optimizer.h"
#include "modules/planning/toolkits/optimizers/qp_spline_st_speed/qp_spline_st_speed_optimizer.h"
#include "modules/planning/toolkits/optimizers/speed_decider/speed_decider.h"

namespace apollo {
namespace planning {

using common::ErrorCode;
using common::SLPoint;
using common::SpeedPoint;
using common::TrajectoryPoint;
using common::math::Vec2d;
using common::time::Clock;

namespace {
constexpr double kPathOptimizationFallbackCost = 2e4;
constexpr double kSpeedOptimizationFallbackCost = 2e4;
constexpr double kStraightForwardLineCost = 10.0;
}  // namespace

void SidePassScenario::Init() {
  if (init_) {
    return;
  }

  Scenario::Init();

  init_ = true;
}

apollo::common::util::Factory<
    ScenarioConfig::StageType, Stage,
    Stage* (*)(const ScenarioConfig::StageConfig& stage_config)>
    SidePassScenario::s_stage_factory_;

void SidePassScenario::RegisterStages() {
  s_stage_factory_.Clear();
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_APPROACH_OBSTACLE,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassApproachObstacle(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_DETECT_SAFETY,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassDetectSafety(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_GENERATE_PATH,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassGeneratePath(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_STOP_ON_WAITPOINT,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassStopOnWaitPoint(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_PASS_OBSTACLE,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassPassObstacle(config);
      });
}

std::unique_ptr<Stage> SidePassScenario::CreateStage(
    const ScenarioConfig::StageConfig& stage_config) {
  if (s_stage_factory_.Empty()) {
    RegisterStages();
  }
  auto ptr = s_stage_factory_.CreateObjectOrNull(stage_config.stage_type(),
                                                 stage_config);
  ptr->SetContext(&side_pass_context_);
  return ptr;
}

bool SidePassScenario::IsTransferable(const Scenario& current_scenario,
                                      const common::TrajectoryPoint& ego_point,
                                      const Frame& frame) const {
  if (frame.reference_line_info().size() > 1) {
    return false;
  }
  if (current_scenario.scenario_type() == ScenarioConfig::SIDE_PASS) {
    return (current_scenario.GetStatus() !=
            Scenario::ScenarioStatus::STATUS_DONE);
  } else if (current_scenario.scenario_type() != ScenarioConfig::LANE_FOLLOW) {
    return false;
  } else {
    return IsSidePassScenario(ego_point, frame);
  }
}

Stage::StageStatus SidePassApproachObstacle::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  bool plan_ok = PlanningOnReferenceLine(planning_start_point, frame);
  if (!plan_ok) {
    return Stage::ERROR;
  }
  if (frame->vehicle_state().linear_velocity() < 1.0e-5) {
    next_stage_ = ScenarioConfig::SIDE_PASS_GENERATE_PATH;
    return Stage::FINISHED;
  }
  return Stage::RUNNING;
}

Stage::StageStatus SidePassGeneratePath::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  if (PlanningOnReferenceLine(planning_start_point, frame)) {
    next_stage_ = ScenarioConfig::SIDE_PASS_STOP_ON_WAITPOINT;
    return Stage::FINISHED;
  } else {
    return Stage::ERROR;
  }
}

Stage::StageStatus SidePassStopOnWaitPoint::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  bool all_far_away = false;
  const PathDecision& path_decision =
      frame->reference_line_info().front().path_decision();
  for (const auto* path_obstacle : path_decision.path_obstacles().Items()) {
    if (path_obstacle->obstacle()->IsVirtual()) {
      continue;
    }
    // TODO(All): check all ST boundaries are far away.
  }
  if (!all_far_away) {
    // wait here, do nothing this cycle.
    return Stage::RUNNING;
  }
  double move_forward_distance = 5.0;
  for (const auto& path_point :
       GetContext()->path_data_.discretized_path().path_points()) {
    // TODO(All):
    // (1) check if the ego car on path_point will partially go into the
    // neighbor
    // lane.
    // (2) update move_forward_distance
    CHECK_GE(path_point.s(), 0.0);
    CHECK_GE(move_forward_distance, 0.0);
  }
  // TODO(All):
  // (1) call proceed with cautious
  // (2) combine path and speed.

  next_stage_ = ScenarioConfig::SIDE_PASS_DETECT_SAFETY;
  return Stage::FINISHED;
}

Stage::StageStatus SidePassDetectSafety::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  if (PlanningOnReferenceLine(planning_start_point, frame)) {
    return Stage::ERROR;
  }
  bool is_safe = true;
  const PathDecision& path_decision =
      frame->reference_line_info().front().path_decision();
  for (const auto* path_obstacle : path_decision.path_obstacles().Items()) {
    if (path_obstacle->obstacle()->IsVirtual()) {
      is_safe = false;
      break;
    }
  }
  if (is_safe) {
    next_stage_ = ScenarioConfig::SIDE_PASS_PASS_OBSTACLE;
    return Stage::FINISHED;
  }
  return Stage::RUNNING;
}

Stage::StageStatus SidePassPassObstacle::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
  bool plan_ok = PlanningOnReferenceLine(planning_start_point, frame);
  if (!plan_ok) {
    return Stage::ERROR;
  }
  const auto& reference_line_info = frame->reference_line_info().front();
  const SLBoundary& adc_sl_boundary = reference_line_info.AdcSlBoundary();
  const auto& end_point =
      reference_line_info.path_data().discretized_path().EndPoint();
  Vec2d last_xy_point(end_point.x(), end_point.y());
  // get s of last point on path
  SLPoint sl_point;
  if (!reference_line_info.reference_line().XYToSL(last_xy_point, &sl_point)) {
    AERROR << "Fail to transfer cartesian point to frenet point.";
    return Stage::ERROR;
  }

  if (adc_sl_boundary.end_s() > sl_point.s() - 1.0) {
    next_stage_ = ScenarioConfig::NO_STAGE;
    return Stage::FINISHED;
  }

  return Stage::RUNNING;
}

bool SidePassScenario::IsSidePassScenario(
    const common::TrajectoryPoint& planning_start_point,
    const Frame& frame) const {
  const SLBoundary& adc_sl_boundary =
      frame.reference_line_info().front().AdcSlBoundary();
  const PathDecision& path_decision =
      frame.reference_line_info().front().path_decision();
  // TODO(lianglia-apollo)

  return HasBlockingObstacle(adc_sl_boundary, path_decision);
}

bool SidePassScenario::IsFarFromIntersection(const Frame& frame) {
  if (frame.reference_line_info().size() > 1) {
    return false;
  }
  const SLBoundary& adc_sl_boundary =
      frame.reference_line_info().front().AdcSlBoundary();
  const auto& first_encounters =
      frame.reference_line_info().front().FirstEncounteredOverlaps();
  const double kClearDistance = 15.0;  // in meters
  for (const auto& encounter : first_encounters) {
    if (encounter.first != ReferenceLineInfo::SIGNAL ||
        encounter.first != ReferenceLineInfo::STOP_SIGN) {
      continue;
    }
    if (encounter.second.start_s - adc_sl_boundary.end_s() < kClearDistance) {
      return false;
    }
  }
  return true;
}

bool SidePassScenario::HasBlockingObstacle(
    const SLBoundary& adc_sl_boundary,
    const PathDecision& path_decision) const {
  // a blocking obstacle is an obstacle blocks the road when it is not blocked
  // (by other obstacles or traffic rules)
  for (const auto* path_obstacle : path_decision.path_obstacles().Items()) {
    if (path_obstacle->obstacle()->IsVirtual() ||
        !path_obstacle->obstacle()->IsStatic()) {
      continue;
    }
    CHECK(path_obstacle->obstacle()->IsStatic());

    if (path_obstacle->PerceptionSLBoundary().start_s() <=
        adc_sl_boundary.end_s()) {  // such vehicles are behind the adc.
      continue;
    }
    constexpr double kAdcDistanceThreshold = 15.0;  // unit: m
    if (path_obstacle->PerceptionSLBoundary().start_s() >
        adc_sl_boundary.end_s() +
            kAdcDistanceThreshold) {  // vehicles are far away
      continue;
    }
    if (path_obstacle->PerceptionSLBoundary().start_l() > 1.0 ||
        path_obstacle->PerceptionSLBoundary().end_l() < -1.0) {
      continue;
    }

    bool is_blocked_by_others = false;
    for (const auto* other_obstacle : path_decision.path_obstacles().Items()) {
      if (other_obstacle->Id() == path_obstacle->Id()) {
        continue;
      }
      if (other_obstacle->PerceptionSLBoundary().start_l() >
              path_obstacle->PerceptionSLBoundary().end_l() ||
          other_obstacle->PerceptionSLBoundary().end_l() <
              path_obstacle->PerceptionSLBoundary().start_l()) {
        // not blocking the backside vehicle
        continue;
      }

      double delta_s = other_obstacle->PerceptionSLBoundary().start_s() -
                       path_obstacle->PerceptionSLBoundary().end_s();
      if (delta_s < 0.0 || delta_s > kAdcDistanceThreshold) {
        continue;
      } else {
        // TODO(All): fixed the segmentation bug for large vehicles, otherwise
        // the follow line will be problematic.
        // is_blocked_by_others = true; break;
      }
    }
    if (!is_blocked_by_others) {
      return true;
    }
  }
  return false;
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>#include "MaterialTensorAux.h"

#include "SymmTensor.h"

template<>
InputParameters validParams<MaterialTensorAux>()
{
  MooseEnum quantities("VonMises=1, PlasticStrainMag, Hydrostatic, Hoop, FirstInvariant, SecondInvariant, ThirdInvariant, TriAxiality");

  InputParameters params = validParams<AuxKernel>();
  params.addRequiredParam<std::string>("tensor", "The material tensor name.");
  params.addParam<int>("index", -1, "The index into the tensor, from 0 to 5 (xx, yy, zz, xy, yz, zx).");
  params.addParam<MooseEnum>("quantity", quantities, "A scalar quantity to compute: " + quantities.getRawNames());

  params.addParam<RealVectorValue>("point1", RealVectorValue(3, 0, 0), "Point one for defining an axis");
  params.addParam<RealVectorValue>("point2", RealVectorValue(3, 1, 0), "Point two for defining an axis");
  return params;
}

MaterialTensorAux::MaterialTensorAux( const std::string & name, InputParameters parameters ) :
    AuxKernel( name, parameters ),
    _tensor( getMaterialProperty<SymmTensor>( getParam<std::string>("tensor") ) ),
    _index( getParam<int>("index") ),
    _quantity_moose_enum( getParam<MooseEnum>("quantity") ),
    _p1( getParam<RealVectorValue>("point1") ),
    _p2( getParam<RealVectorValue>("point2") )
{
  if (_quantity_moose_enum.isValid())
  {
    if ( _index > 0 )
      mooseError("Cannot define an index and a quantity in " + _name);
    else
      _quantity = MTA_ENUM(int(_quantity_moose_enum));
  }
  else
  {
    if ( _index < 0 )
      mooseError("Neither an index nor a quantity listed for " + _name);
    else
      _quantity = MTA_COMPONENT; // default
  }

  if (_index > -1 && _index > 5)
  {
    mooseError("MaterialTensorAux requires the index to be >= 0 and <= 5 OR < 0 (off).");
  }
}

Real
MaterialTensorAux::computeValue()
{
  Real value(0);
  const SymmTensor & tensor( _tensor[_qp] );
  if (_quantity == MTA_COMPONENT)
  {
    value = tensor.component(_index);
  }
  else if ( _quantity == MTA_VONMISES )
  {
    value = std::sqrt(0.5*(
                           std::pow(tensor.xx() - tensor.yy(), 2) +
                           std::pow(tensor.yy() - tensor.zz(), 2) +
                           std::pow(tensor.zz() - tensor.xx(), 2) + 6 * (
                           std::pow(tensor.xy(), 2) +
                           std::pow(tensor.yz(), 2) +
                           std::pow(tensor.zx(), 2))));
  }
  else if ( _quantity == MTA_PLASTICSTRAINMAG )
  {
    value = std::sqrt(2.0/3.0 * tensor.doubleContraction(tensor));
  }
  else if ( _quantity == MTA_HYDROSTATIC )
  {
    value = tensor.trace()/3.0;
  }
  else if ( _quantity == MTA_HOOP )
  {
    if (LIBMESH_DIM == 2)
    {
      value = tensor.zz();
    }
    else
    {
      // This is the location of the stress.  A vector from the cylindrical axis to this point will define the x' axis.
      Point p0( _q_point[_qp] );

      // The vector _p1 + t*(_p2-_p1) defines the cylindrical axis.  The point along this
      // axis closest to p0 is found by the following for t:
      const Point p2p1( _p2 - _p1 );
      const Point p2p0( _p2 - p0 );
      const Point p1p0( _p1 - p0 );
      const Real t( -(p1p0*p2p1)/p2p1.size_sq() );
      // The nearest point on the cylindrical axis to p0 is p.
      const Point p( _p1 + t * p2p1 );
      Point xp( p0 - p );
      xp /= xp.size();
      Point yp( p2p1/p2p1.size() );
      Point zp( xp.cross( yp ));
      //
      // The following works but does more than we need
      //
//      // Rotation matrix R
//      ColumnMajorMatrix R(3,3);
//      // Fill with direction cosines
//      R(0,0) = xp(0);
//      R(1,0) = xp(1);
//      R(2,0) = xp(2);
//      R(0,1) = yp(0);
//      R(1,1) = yp(1);
//      R(2,1) = yp(2);
//      R(0,2) = zp(0);
//      R(1,2) = zp(1);
//      R(2,2) = zp(2);
//      // Rotate
//      ColumnMajorMatrix tensor( _tensor[_qp].columnMajorMatrix() );
//      ColumnMajorMatrix tensorp( R.transpose() * ( tensor * R ));
//      // Hoop stress is the zz stress
//      value = tensorp(2,2);
      //
      // Instead, tensorp(2,2) = R^T(2,:)*tensor*R(:,2)
      //
      const Real zp0( zp(0) );
      const Real zp1( zp(1) );
      const Real zp2( zp(2) );
      value = (zp0*tensor(0,0)+zp1*tensor(1,0)+zp2*tensor(2,0))*zp0 +
              (zp0*tensor(0,1)+zp1*tensor(1,1)+zp2*tensor(2,1))*zp1 +
              (zp0*tensor(0,2)+zp1*tensor(1,2)+zp2*tensor(2,2))*zp2;
    }
  }
  else if ( _quantity == MTA_FIRSTINVARIANT )
  {
    value = tensor.trace();
  }
  else if ( _quantity == MTA_SECONDINVARIANT )
  {
    value =
      tensor.xx()*tensor.yy() +
      tensor.yy()*tensor.zz() +
      tensor.zz()*tensor.xx() -
      tensor.xy()*tensor.xy() -
      tensor.yz()*tensor.yz() -
      tensor.zx()*tensor.zx();
  }
  else if ( _quantity == MTA_THIRDINVARIANT )
  {
    value =
      tensor.xx()*tensor.yy()*tensor.zz() -
      tensor.xx()*tensor.yz()*tensor.yz() +
      tensor.xy()*tensor.zx()*tensor.yz() -
      tensor.xy()*tensor.xy()*tensor.zz() +
      tensor.zx()*tensor.xy()*tensor.yz() -
      tensor.zx()*tensor.zx()*tensor.yy();
  }
  else if ( _quantity == MTA_TRIAXIALITY )
  {
    Real hydrostatic = tensor.trace()/3.0;
    Real von_mises = std::sqrt(0.5*(
                                 std::pow(tensor.xx() - tensor.yy(), 2) +
                                 std::pow(tensor.yy() - tensor.zz(), 2) +
                                 std::pow(tensor.zz() - tensor.xx(), 2) + 6 * (
                                   std::pow(tensor.xy(), 2) +
                                   std::pow(tensor.yz(), 2) +
                                   std::pow(tensor.zx(), 2))));

    value = std::abs(hydrostatic / von_mises);
  }
  else
  {
    mooseError("Internal logic error from " + name());
  }
  return value;
}

<commit_msg>pf cp<commit_after>#include "MaterialTensorAux.h"

#include "SymmTensor.h"

template<>
InputParameters validParams<MaterialTensorAux>()
{
  MooseEnum quantities("VonMises=1, PlasticStrainMag, Hydrostatic, Hoop, FirstInvariant, SecondInvariant, ThirdInvariant, TriAxiality");

  InputParameters params = validParams<AuxKernel>();
  params.addRequiredParam<std::string>("tensor", "The material tensor name.");
  params.addParam<int>("index", -1, "The index into the tensor, from 0 to 5 (xx, yy, zz, xy, yz, zx).");
  params.addParam<MooseEnum>("quantity", quantities, "A scalar quantity to compute: " + quantities.getRawNames());

  params.addParam<RealVectorValue>("point1", RealVectorValue(3, 0, 0), "Point one for defining an axis");
  params.addParam<RealVectorValue>("point2", RealVectorValue(3, 1, 0), "Point two for defining an axis");
  return params;
}

MaterialTensorAux::MaterialTensorAux( const std::string & name, InputParameters parameters ) :
    AuxKernel( name, parameters ),
    _tensor( getMaterialProperty<SymmTensor>( getParam<std::string>("tensor") ) ),
    _index( getParam<int>("index") ),
    _quantity_moose_enum( getParam<MooseEnum>("quantity") ),
    _p1( getParam<RealVectorValue>("point1") ),
    _p2( getParam<RealVectorValue>("point2") )
{
  if (_quantity_moose_enum.isValid())
  {
    if ( _index > 0 )
      mooseError("Cannot define an index and a quantity in " + _name);
    else
      _quantity = MTA_ENUM(int(_quantity_moose_enum));
  }
  else
  {
    if ( _index < 0 )
      mooseError("Neither an index nor a quantity listed for " + _name);
    else
      _quantity = MTA_COMPONENT; // default
  }

  if (_index > -1 && _index > 5)
  {
    mooseError("MaterialTensorAux requires the index to be >= 0 and <= 5 OR < 0 (off).");
  }

}

Real
MaterialTensorAux::computeValue()
{
  Real value(0);
  const SymmTensor & tensor( _tensor[_qp] );
  if (_quantity == MTA_COMPONENT)
  {
    value = tensor.component(_index);
  }
  else if ( _quantity == MTA_VONMISES )
  {
    value = std::sqrt(0.5*(
                           std::pow(tensor.xx() - tensor.yy(), 2) +
                           std::pow(tensor.yy() - tensor.zz(), 2) +
                           std::pow(tensor.zz() - tensor.xx(), 2) + 6 * (
                           std::pow(tensor.xy(), 2) +
                           std::pow(tensor.yz(), 2) +
                           std::pow(tensor.zx(), 2))));
  }
  else if ( _quantity == MTA_PLASTICSTRAINMAG )
  {
    value = std::sqrt(2.0/3.0 * tensor.doubleContraction(tensor));
  }
  else if ( _quantity == MTA_HYDROSTATIC )
  {
    value = tensor.trace()/3.0;
  }
  else if ( _quantity == MTA_HOOP )
  {
    if (LIBMESH_DIM == 2)
    {
      value = tensor.zz();
    }
    else
    {
      // This is the location of the stress.  A vector from the cylindrical axis to this point will define the x' axis.
      Point p0( _q_point[_qp] );

      // The vector _p1 + t*(_p2-_p1) defines the cylindrical axis.  The point along this
      // axis closest to p0 is found by the following for t:
      const Point p2p1( _p2 - _p1 );
      const Point p2p0( _p2 - p0 );
      const Point p1p0( _p1 - p0 );
      const Real t( -(p1p0*p2p1)/p2p1.size_sq() );
      // The nearest point on the cylindrical axis to p0 is p.
      const Point p( _p1 + t * p2p1 );
      Point xp( p0 - p );
      xp /= xp.size();
      Point yp( p2p1/p2p1.size() );
      Point zp( xp.cross( yp ));
      //
      // The following works but does more than we need
      //
//      // Rotation matrix R
//      ColumnMajorMatrix R(3,3);
//      // Fill with direction cosines
//      R(0,0) = xp(0);
//      R(1,0) = xp(1);
//      R(2,0) = xp(2);
//      R(0,1) = yp(0);
//      R(1,1) = yp(1);
//      R(2,1) = yp(2);
//      R(0,2) = zp(0);
//      R(1,2) = zp(1);
//      R(2,2) = zp(2);
//      // Rotate
//      ColumnMajorMatrix tensor( _tensor[_qp].columnMajorMatrix() );
//      ColumnMajorMatrix tensorp( R.transpose() * ( tensor * R ));
//      // Hoop stress is the zz stress
//      value = tensorp(2,2);
      //
      // Instead, tensorp(2,2) = R^T(2,:)*tensor*R(:,2)
      //
      const Real zp0( zp(0) );
      const Real zp1( zp(1) );
      const Real zp2( zp(2) );
      value = (zp0*tensor(0,0)+zp1*tensor(1,0)+zp2*tensor(2,0))*zp0 +
              (zp0*tensor(0,1)+zp1*tensor(1,1)+zp2*tensor(2,1))*zp1 +
              (zp0*tensor(0,2)+zp1*tensor(1,2)+zp2*tensor(2,2))*zp2;
    }
  }
  else if ( _quantity == MTA_FIRSTINVARIANT )
  {
    value = tensor.trace();
  }
  else if ( _quantity == MTA_SECONDINVARIANT )
  {
    value =
      tensor.xx()*tensor.yy() +
      tensor.yy()*tensor.zz() +
      tensor.zz()*tensor.xx() -
      tensor.xy()*tensor.xy() -
      tensor.yz()*tensor.yz() -
      tensor.zx()*tensor.zx();
  }
  else if ( _quantity == MTA_THIRDINVARIANT )
  {
    value =
      tensor.xx()*tensor.yy()*tensor.zz() -
      tensor.xx()*tensor.yz()*tensor.yz() +
      tensor.xy()*tensor.zx()*tensor.yz() -
      tensor.xy()*tensor.xy()*tensor.zz() +
      tensor.zx()*tensor.xy()*tensor.yz() -
      tensor.zx()*tensor.zx()*tensor.yy();
  }
  else if ( _quantity == MTA_TRIAXIALITY )
  {
    Real hydrostatic = tensor.trace()/3.0;
    Real von_mises = std::sqrt(0.5*(
                                 std::pow(tensor.xx() - tensor.yy(), 2) +
                                 std::pow(tensor.yy() - tensor.zz(), 2) +
                                 std::pow(tensor.zz() - tensor.xx(), 2) + 6 * (
                                   std::pow(tensor.xy(), 2) +
                                   std::pow(tensor.yz(), 2) +
                                   std::pow(tensor.zx(), 2))));

    value = std::abs(hydrostatic / von_mises);
  }
  else
  {
    mooseError("Internal logic error from " + name());
  }
  return value;
}

<|endoftext|>


<commit_before>/*! @file
 *
 *  @brief Do I need a Parker
 *
 *  This module contains the routines that drive the dinapd daemon.
 *
 *  @author APope
 *  @date 20-02-2016
 */
/*!
**  @addtogroup DINAP_module DINAP module documentation
**  @{
*/
/* MODULE DINAP */
#include <syslog.h>
#include <stdlib.h>
#include <unistd.h>
#include <glib.h>
#include <libnotify/notify.h>
#include "DINAP.h"

DINAP::DINAP(TSTATE location=STATE_NSW, int parker_temp=18, int shorts_temp=25)
{
  DINAP::location = location;
  DINAP::parker_temp = parker_temp;
  DINAP::shorts_temp = shorts_temp;
}

void DINAP::CheckWeatherInfo(void)
{
  bool scrapeSucceeded;
  //TODO: expand functionality
  syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_NOTICE), "Checking the Weather... ");

  //TODO: Scrape weather information using location
  scrapeSucceeded = DINAP::scrapeWeatherData();
}

bool DINAP::scrapeWeatherData(void)
{
  DINAP::notifyUser("Weather is 17 degs", "Brrr it's chilly! Time for a coat.");    //TEST MESSAGE
  return true;
}

void DINAP::notifyUser(const char * summary, const char * message)
{
  //Initialise the lib-notify handle
  notify_init("Do I need A Parker?");

  //Create the notification
  NotifyNotification * weatherUpdate;
  weatherUpdate = notify_notification_new(summary, message, NULL);

  //Set timeout - 3 seconds
  notify_notification_set_timeout(weatherUpdate, 3000);

  //Set the urgency level
  notify_notification_set_urgency(weatherUpdate, NOTIFY_URGENCY_CRITICAL);

  //Show the notification
  if (!notify_notification_show(weatherUpdate, NULL))
  {
    syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "Failed to send notification.");
  }

  //Unitialise lib-notify
  notify_uninit();
}

void DINAP::compareUserTemp(int scrapedTemp)
{

}
/* END DINAP */
/*!
** @}
*/
<commit_msg>Dinap.cpp: - Expanded basic functionality in calling to the bomparser module to get 'real-time' temperature information<commit_after>/*! @file
 *
 *  @brief Do I need a Parker
 *
 *  This module contains the routines that drive the dinapd daemon.
 *
 *  @author APope
 *  @date 20-02-2016
 */
/*!
**  @addtogroup DINAP_module DINAP module documentation
**  @{
*/
/* MODULE DINAP */
#include <syslog.h>
#include <stdlib.h>
#include <unistd.h>
#include <glib.h>
#include <libnotify/notify.h>
#include "DINAP.h"
#include "bomparser.h"

DINAP::DINAP(TSTATE location=STATE_NSW, int parker_temp=18, int shorts_temp=25)
{
  DINAP::location = location;
  DINAP::parker_temp = parker_temp;
  DINAP::shorts_temp = shorts_temp;
}

void DINAP::CheckWeatherInfo(void)
{
  bool scrapeSucceeded;

  //TODO: expand functionality
  syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_NOTICE), "Checking the Weather... ");
  scrapeSucceeded = DINAP::scrapeWeatherData();
}

bool DINAP::scrapeWeatherData(void)
{
  bool scrapeOK = false;

  BomParser bomSpider = BomParser();

  std::string scrapedTemp = bomSpider.GetWeatherInfo(STATE_NSW, INFO_Temp); //TEST CODE

  if (!scrapedTemp.empty())
  {
    syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_INFO), scrapedTemp.c_str());
    compareUserTemp(32);
    scrapeOK = true;
  }
  else
  {
    syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "Unable to obtain weather information.");
  }

  return scrapeOK;
}

void DINAP::notifyUser(const char * summary, const char * message)
{
  //Initialise the lib-notify handle
  notify_init("Do I need A Parker?");

  //Create the notification
  NotifyNotification * weatherUpdate;
  weatherUpdate = notify_notification_new(summary, message, NULL);

  //Set timeout - 3 seconds
  notify_notification_set_timeout(weatherUpdate, 3000);

  //Set the urgency level
  notify_notification_set_urgency(weatherUpdate, NOTIFY_URGENCY_CRITICAL);

  //Show the notification
  if (!notify_notification_show(weatherUpdate, NULL))
  {
    syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "Failed to send notification.");
  }

  //Unitialise lib-notify
  notify_uninit();
}

void DINAP::compareUserTemp(int scrapedTemp)
{
  DINAP::notifyUser("Weather is 17 degs", "Brrr it's chilly! Time for a coat.");    //TEST MESSAGE
}
/* END DINAP */
/*!
** @}
*/
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/test/test_server.h"

#include <poll.h>

#include <vector>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/process_util.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/test/test_timeouts.h"

namespace {

// Helper class used to detect and kill orphaned python test server processes.
// Checks if the command line of a process contains |path_string| (the path
// from which the test server was launched) and |port_string| (the port used by
// the test server), and if the parent pid of the process is 1 (indicating that
// it is an orphaned process).
class OrphanedTestServerFilter : public base::ProcessFilter {
 public:
  OrphanedTestServerFilter(
      const std::string& path_string, const std::string& port_string)
      : path_string_(path_string),
        port_string_(port_string) {}

  virtual bool Includes(const base::ProcessEntry& entry) const {
    if (entry.parent_pid() != 1)
      return false;
    bool found_path_string = false;
    bool found_port_string = false;
    for (std::vector<std::string>::const_iterator it =
         entry.cmd_line_args().begin();
         it != entry.cmd_line_args().end();
         ++it) {
      if (it->find(path_string_) != std::string::npos)
        found_path_string = true;
      if (it->find(port_string_) != std::string::npos)
        found_port_string = true;
    }
    return found_path_string && found_port_string;
  }

 private:
  std::string path_string_;
  std::string port_string_;
  DISALLOW_COPY_AND_ASSIGN(OrphanedTestServerFilter);
};

// Given a file descriptor, reads into |buffer| until |bytes_max|
// bytes has been read or an error has been encountered.  Returns true
// if the read was successful.  |remaining_time| is used as a timeout.
bool ReadData(int fd, ssize_t bytes_max, uint8* buffer,
              base::TimeDelta* remaining_time) {
  ssize_t bytes_read = 0;
  base::Time previous_time = base::Time::Now();
  while (bytes_read < bytes_max) {
    struct pollfd poll_fds[1];

    poll_fds[0].fd = fd;
    poll_fds[0].events = POLLIN | POLLPRI;
    poll_fds[0].revents = 0;

    int rv = HANDLE_EINTR(poll(poll_fds, 1,
                               remaining_time->InMilliseconds()));
    if (rv != 1) {
      LOG(ERROR) << "Failed to poll for the child file descriptor.";
      return false;
    }

    base::Time current_time = base::Time::Now();
    base::TimeDelta elapsed_time_cycle = current_time - previous_time;
    DCHECK(elapsed_time_cycle.InMilliseconds() >= 0);
    *remaining_time -= elapsed_time_cycle;
    previous_time = current_time;

    ssize_t num_bytes = HANDLE_EINTR(read(fd, buffer + bytes_read,
                                          bytes_max - bytes_read));
    if (num_bytes <= 0)
      return false;
    bytes_read += num_bytes;
  }
  return true;
}

}  // namespace

namespace net {

bool TestServer::LaunchPython(const FilePath& testserver_path) {
  CommandLine python_command(FilePath(FILE_PATH_LITERAL("python")));
  python_command.AppendArgPath(testserver_path);
  if (!AddCommandLineArguments(&python_command))
    return false;

  int pipefd[2];
  if (pipe(pipefd) != 0) {
    PLOG(ERROR) << "Could not create pipe.";
    return false;
  }

  // Save the read half. The write half is sent to the child.
  child_fd_ = pipefd[0];
  child_fd_closer_.reset(&child_fd_);
  file_util::ScopedFD write_closer(&pipefd[1]);
  base::file_handle_mapping_vector map_write_fd;
  map_write_fd.push_back(std::make_pair(pipefd[1], pipefd[1]));

  python_command.AppendArg("--startup-pipe=" + base::IntToString(pipefd[1]));

  // Try to kill any orphaned testserver processes that may be running.
  OrphanedTestServerFilter filter(testserver_path.value(),
                                  base::IntToString(host_port_pair_.port()));
  if (!base::KillProcesses("python", -1, &filter)) {
    LOG(WARNING) << "Failed to clean up older orphaned testserver instances.";
  }

  // Launch a new testserver process.
  base::LaunchOptions options;
  options.fds_to_remap = &map_write_fd;
  if (!base::LaunchProcess(python_command, options, &process_handle_)) {
    LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString();
    return false;
  }

  return true;
}

bool TestServer::WaitToStart() {
  file_util::ScopedFD child_fd_closer(child_fd_closer_.release());

  base::TimeDelta remaining_time = base::TimeDelta::FromMilliseconds(
      TestTimeouts::action_timeout_ms());

  uint32 server_data_len = 0;
  if (!ReadData(child_fd_, sizeof(server_data_len),
                reinterpret_cast<uint8*>(&server_data_len),
                &remaining_time)) {
    LOG(ERROR) << "Could not read server_data_len";
    return false;
  }
  std::string server_data(server_data_len, '\0');
  if (!ReadData(child_fd_, server_data_len,
                reinterpret_cast<uint8*>(&server_data[0]),
                &remaining_time)) {
    LOG(ERROR) << "Could not read server_data (" << server_data_len
               << " bytes)";
    return false;
  }

  if (!ParseServerData(server_data)) {
    LOG(ERROR) << "Could not parse server_data: " << server_data;
    return false;
  }

  return true;
}

}  // namespace net
<commit_msg>test_server: include errno in failed poll()<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/test/test_server.h"

#include <poll.h>

#include <vector>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/process_util.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/test/test_timeouts.h"

namespace {

// Helper class used to detect and kill orphaned python test server processes.
// Checks if the command line of a process contains |path_string| (the path
// from which the test server was launched) and |port_string| (the port used by
// the test server), and if the parent pid of the process is 1 (indicating that
// it is an orphaned process).
class OrphanedTestServerFilter : public base::ProcessFilter {
 public:
  OrphanedTestServerFilter(
      const std::string& path_string, const std::string& port_string)
      : path_string_(path_string),
        port_string_(port_string) {}

  virtual bool Includes(const base::ProcessEntry& entry) const {
    if (entry.parent_pid() != 1)
      return false;
    bool found_path_string = false;
    bool found_port_string = false;
    for (std::vector<std::string>::const_iterator it =
         entry.cmd_line_args().begin();
         it != entry.cmd_line_args().end();
         ++it) {
      if (it->find(path_string_) != std::string::npos)
        found_path_string = true;
      if (it->find(port_string_) != std::string::npos)
        found_port_string = true;
    }
    return found_path_string && found_port_string;
  }

 private:
  std::string path_string_;
  std::string port_string_;
  DISALLOW_COPY_AND_ASSIGN(OrphanedTestServerFilter);
};

// Given a file descriptor, reads into |buffer| until |bytes_max|
// bytes has been read or an error has been encountered.  Returns true
// if the read was successful.  |remaining_time| is used as a timeout.
bool ReadData(int fd, ssize_t bytes_max, uint8* buffer,
              base::TimeDelta* remaining_time) {
  ssize_t bytes_read = 0;
  base::Time previous_time = base::Time::Now();
  while (bytes_read < bytes_max) {
    struct pollfd poll_fds[1];

    poll_fds[0].fd = fd;
    poll_fds[0].events = POLLIN | POLLPRI;
    poll_fds[0].revents = 0;

    int rv = HANDLE_EINTR(poll(poll_fds, 1,
                               remaining_time->InMilliseconds()));
    if (rv != 1) {
      PLOG(ERROR) << "poll() failed for child file descriptor";
      return false;
    }

    base::Time current_time = base::Time::Now();
    base::TimeDelta elapsed_time_cycle = current_time - previous_time;
    DCHECK(elapsed_time_cycle.InMilliseconds() >= 0);
    *remaining_time -= elapsed_time_cycle;
    previous_time = current_time;

    ssize_t num_bytes = HANDLE_EINTR(read(fd, buffer + bytes_read,
                                          bytes_max - bytes_read));
    if (num_bytes <= 0)
      return false;
    bytes_read += num_bytes;
  }
  return true;
}

}  // namespace

namespace net {

bool TestServer::LaunchPython(const FilePath& testserver_path) {
  CommandLine python_command(FilePath(FILE_PATH_LITERAL("python")));
  python_command.AppendArgPath(testserver_path);
  if (!AddCommandLineArguments(&python_command))
    return false;

  int pipefd[2];
  if (pipe(pipefd) != 0) {
    PLOG(ERROR) << "Could not create pipe.";
    return false;
  }

  // Save the read half. The write half is sent to the child.
  child_fd_ = pipefd[0];
  child_fd_closer_.reset(&child_fd_);
  file_util::ScopedFD write_closer(&pipefd[1]);
  base::file_handle_mapping_vector map_write_fd;
  map_write_fd.push_back(std::make_pair(pipefd[1], pipefd[1]));

  python_command.AppendArg("--startup-pipe=" + base::IntToString(pipefd[1]));

  // Try to kill any orphaned testserver processes that may be running.
  OrphanedTestServerFilter filter(testserver_path.value(),
                                  base::IntToString(host_port_pair_.port()));
  if (!base::KillProcesses("python", -1, &filter)) {
    LOG(WARNING) << "Failed to clean up older orphaned testserver instances.";
  }

  // Launch a new testserver process.
  base::LaunchOptions options;
  options.fds_to_remap = &map_write_fd;
  if (!base::LaunchProcess(python_command, options, &process_handle_)) {
    LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString();
    return false;
  }

  return true;
}

bool TestServer::WaitToStart() {
  file_util::ScopedFD child_fd_closer(child_fd_closer_.release());

  base::TimeDelta remaining_time = base::TimeDelta::FromMilliseconds(
      TestTimeouts::action_timeout_ms());

  uint32 server_data_len = 0;
  if (!ReadData(child_fd_, sizeof(server_data_len),
                reinterpret_cast<uint8*>(&server_data_len),
                &remaining_time)) {
    LOG(ERROR) << "Could not read server_data_len";
    return false;
  }
  std::string server_data(server_data_len, '\0');
  if (!ReadData(child_fd_, server_data_len,
                reinterpret_cast<uint8*>(&server_data[0]),
                &remaining_time)) {
    LOG(ERROR) << "Could not read server_data (" << server_data_len
               << " bytes)";
    return false;
  }

  if (!ParseServerData(server_data)) {
    LOG(ERROR) << "Could not parse server_data: " << server_data;
    return false;
  }

  return true;
}

}  // namespace net
<|endoftext|>


<commit_before>#include "VSLapp.h"
#include <QLockFile>
#include <QDir>
#include <QApplication>
#include <QSettings>
#include <QDateTime>
#include <QMessageBox>
#include <QMainWindow>
#include <QTextStream>
#ifdef __unix
#include <unistd.h>
#include <sys/types.h>
#endif

void VSLapp::applicationSetup(const char *organizationName)
{
    // set up application name
    QFileInfo applicationFile(QApplication::applicationFilePath());

    // These allow us to simply construct a "QSettings" object without arguments
    qApp->setOrganizationDomain("mil.army.arl");
    qApp->setApplicationName(applicationFile.baseName());
    qApp->setOrganizationName(organizationName);
    qApp->setApplicationVersion(__DATE__ __TIME__);

    // Look up the last directory where the user opened files.
    // set it if it hasn't been set.
    QSettings settings;
    if (!settings.allKeys().contains("app/currentDirectory"))
        settings.setValue("app/currentDirectory", applicationFile.absoluteDir().absolutePath());

    // log this launch of the program to track usage.
    logApplicationLaunch(applicationFile); // comes after settingsRead so we can set a preference
}

void VSLapp::logApplicationLaunch(QFileInfo appFile)
{
    QSettings settings;

    settings.value("logUsage", QVariant(true));

    qApp->applicationDirPath();

    // obtain the string we will log to the file
    QString message =
	QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
#ifdef __unix
    message.append(getuid());
#endif
    message.append("\\n");

    QString nameOfLogFile = QString("%1%2").arg(appFile.absoluteFilePath()).arg(".log");

    QString nameOfLockFile = QString("%1%2").arg(nameOfLogFile).arg(".lck");
    QLockFile lockFile(nameOfLockFile);

    if (lockFile.tryLock(1000)) {
        // got the lock write the data
        QFile usageLogFile(nameOfLogFile);
        if (usageLogFile.open(QIODevice::Append)) {
            usageLogFile.write(message.toStdString().c_str());
            usageLogFile.close();
        }
        lockFile.unlock();
    }
}

QString VSLapp::getApplicationDir()
{
    QDir applicationDir(qApp->applicationDirPath());

#if defined(Q_OS_WIN)
    if (applicationDir.dirName().toLower() == "debug" ||
            applicationDir.dirName().toLower() == "release"
        #  ifdef CMAKE_INTDIR
            || applicationDir.dirName() == CMAKE_INTDIR
        #  endif
            )
        applicationDir.cdUp();
#elif defined(Q_OS_MAC)
    if (applicationDir.dirName() == "MacOS") {
        applicationDir.cdUp();
        applicationDir.cdUp();
        applicationDir.cdUp();
    }
#endif

    return applicationDir.absolutePath();
}

#include <QTextEdit>
class QMessageBoxResize: public QMessageBox
  {
  public:
    QMessageBoxResize(QWidget *parent = 0) : QMessageBox(parent) {
      setMouseTracking(true);
      setSizeGripEnabled(true);
    }
  private:
    virtual bool event(QEvent *e) {
      bool res = QMessageBox::event(e);
      switch (e->type()) {
      case QEvent::MouseMove:
      case QEvent::MouseButtonPress:
          setSizeGripEnabled(true);
        setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
        if (QWidget *textEdit = findChild<QTextEdit *>()) {
          textEdit->setMaximumHeight(QWIDGETSIZE_MAX);
        }
      }
      return res;
    }
  };
void VSLapp::showAboutDialog(QWidget *parent)
{

    QMessageBoxResize msgBox(parent);
    QString message;
    QTextStream stream(&message);
    stream <<  "Built "  __DATE__ " " __TIME__ << endl
           << "By " BUILT_BY_USER " on " BUILT_ON_MACHINE << endl;

    msgBox.setInformativeText(message);    msgBox.setDetailedText(QString("Binary:%1").arg(VSLapp::getApplicationDir()));
    msgBox.setWindowTitle(QString("About %1").arg(qApp->applicationName()));
    msgBox.setText(QString("This is %1 from
%2")
                   .arg(qApp->applicationName())
                   .arg(qApp->organizationName()));
    msgBox.setDefaultButton(QMessageBox::Ok);
    msgBox.exec();

}

#define MainWindowGeometry "MainWindow/geometry"
#define MainWindowDoRestore "MainWindow/restore"
#define UI_VERSION 1
void VSLapp::mainWindowSetup(QMainWindow *mw)
{
    mw->setWindowTitle(qApp->applicationName());

    // set the geometry
    QSettings settings;
    if (settings.allKeys().contains(MainWindowGeometry)) {
        mw->setGeometry(settings.value(MainWindowGeometry).toRect());
    }
}

void VSLapp::mainWindowSave(QMainWindow *mw)
{
    // stash things that we will want on startup.
    QSettings settings;
    settings.setValue(MainWindowGeometry, mw->geometry());
}

<commit_msg>add default clause to event handler switch<commit_after>#include "VSLapp.h"
#include <QLockFile>
#include <QDir>
#include <QApplication>
#include <QSettings>
#include <QDateTime>
#include <QMessageBox>
#include <QMainWindow>
#include <QTextStream>
#ifdef __unix
#include <unistd.h>
#include <sys/types.h>
#endif

void VSLapp::applicationSetup(const char *organizationName)
{
    // set up application name
    QFileInfo applicationFile(QApplication::applicationFilePath());

    // These allow us to simply construct a "QSettings" object without arguments
    qApp->setOrganizationDomain("mil.army.arl");
    qApp->setApplicationName(applicationFile.baseName());
    qApp->setOrganizationName(organizationName);
    qApp->setApplicationVersion(__DATE__ __TIME__);

    // Look up the last directory where the user opened files.
    // set it if it hasn't been set.
    QSettings settings;
    if (!settings.allKeys().contains("app/currentDirectory"))
        settings.setValue("app/currentDirectory", applicationFile.absoluteDir().absolutePath());

    // log this launch of the program to track usage.
    logApplicationLaunch(applicationFile); // comes after settingsRead so we can set a preference
}

void VSLapp::logApplicationLaunch(QFileInfo appFile)
{
    QSettings settings;

    settings.value("logUsage", QVariant(true));

    qApp->applicationDirPath();

    // obtain the string we will log to the file
    QString message =
	QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
#ifdef __unix
    message.append(getuid());
#endif
    message.append("\\n");

    QString nameOfLogFile = QString("%1%2").arg(appFile.absoluteFilePath()).arg(".log");

    QString nameOfLockFile = QString("%1%2").arg(nameOfLogFile).arg(".lck");
    QLockFile lockFile(nameOfLockFile);

    if (lockFile.tryLock(1000)) {
        // got the lock write the data
        QFile usageLogFile(nameOfLogFile);
        if (usageLogFile.open(QIODevice::Append)) {
            usageLogFile.write(message.toStdString().c_str());
            usageLogFile.close();
        }
        lockFile.unlock();
    }
}

QString VSLapp::getApplicationDir()
{
    QDir applicationDir(qApp->applicationDirPath());

#if defined(Q_OS_WIN)
    if (applicationDir.dirName().toLower() == "debug" ||
            applicationDir.dirName().toLower() == "release"
        #  ifdef CMAKE_INTDIR
            || applicationDir.dirName() == CMAKE_INTDIR
        #  endif
            )
        applicationDir.cdUp();
#elif defined(Q_OS_MAC)
    if (applicationDir.dirName() == "MacOS") {
        applicationDir.cdUp();
        applicationDir.cdUp();
        applicationDir.cdUp();
    }
#endif

    return applicationDir.absolutePath();
}

#include <QTextEdit>
class QMessageBoxResize: public QMessageBox
  {
  public:
    QMessageBoxResize(QWidget *parent = 0) : QMessageBox(parent) {
      setMouseTracking(true);
      setSizeGripEnabled(true);
    }
  private:
    virtual bool event(QEvent *e) {
      bool res = QMessageBox::event(e);
      switch (e->type()) {
      case QEvent::MouseMove:
      case QEvent::MouseButtonPress:
          setSizeGripEnabled(true);
        setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
        if (QWidget *textEdit = findChild<QTextEdit *>()) {
          textEdit->setMaximumHeight(QWIDGETSIZE_MAX);
        }
      default:
	break;
      }
      return res;
    }
  };
void VSLapp::showAboutDialog(QWidget *parent)
{

    QMessageBoxResize msgBox(parent);
    QString message;
    QTextStream stream(&message);
    stream <<  "Built "  __DATE__ " " __TIME__ << endl
           << "By " BUILT_BY_USER " on " BUILT_ON_MACHINE << endl;

    msgBox.setInformativeText(message);    msgBox.setDetailedText(QString("Binary:%1").arg(VSLapp::getApplicationDir()));
    msgBox.setWindowTitle(QString("About %1").arg(qApp->applicationName()));
    msgBox.setText(QString("This is %1 from
%2")
                   .arg(qApp->applicationName())
                   .arg(qApp->organizationName()));
    msgBox.setDefaultButton(QMessageBox::Ok);
    msgBox.exec();

}

#define MainWindowGeometry "MainWindow/geometry"
#define MainWindowDoRestore "MainWindow/restore"
#define UI_VERSION 1
void VSLapp::mainWindowSetup(QMainWindow *mw)
{
    mw->setWindowTitle(qApp->applicationName());

    // set the geometry
    QSettings settings;
    if (settings.allKeys().contains(MainWindowGeometry)) {
        mw->setGeometry(settings.value(MainWindowGeometry).toRect());
    }
}

void VSLapp::mainWindowSave(QMainWindow *mw)
{
    // stash things that we will want on startup.
    QSettings settings;
    settings.setValue(MainWindowGeometry, mw->geometry());
}

<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "nacl_io/socket/udp_node.h"

#include <errno.h>
#include <string.h>

#include <algorithm>

#include "nacl_io/log.h"
#include "nacl_io/pepper_interface.h"
#include "nacl_io/socket/packet.h"
#include "nacl_io/socket/udp_event_emitter.h"
#include "nacl_io/stream/stream_fs.h"

namespace {
const size_t kMaxPacketSize = 65536;
const size_t kDefaultFifoSize = kMaxPacketSize * 8;
}

namespace nacl_io {

class UdpWork : public StreamFs::Work {
 public:
  explicit UdpWork(const ScopedUdpEventEmitter& emitter)
      : StreamFs::Work(emitter->stream()->stream()),
        emitter_(emitter),
        packet_(NULL) {}

  ~UdpWork() { delete packet_; }

  UDPSocketInterface* UDPInterface() {
    return filesystem()->ppapi()->GetUDPSocketInterface();
  }

 protected:
  ScopedUdpEventEmitter emitter_;
  Packet* packet_;
};

class UdpSendWork : public UdpWork {
 public:
  explicit UdpSendWork(const ScopedUdpEventEmitter& emitter,
                       const ScopedSocketNode& node)
      : UdpWork(emitter), node_(node) {}

  virtual bool Start(int32_t val) {
    AUTO_LOCK(emitter_->GetLock());

    // Does the stream exist, and can it send?
    if (!node_->TestStreamFlags(SSF_CAN_SEND))
      return false;

    packet_ = emitter_->ReadTXPacket_Locked();
    if (NULL == packet_)
      return false;

    int err = UDPInterface()->SendTo(node_->socket_resource(),
                                     packet_->buffer(),
                                     packet_->len(),
                                     packet_->addr(),
                                     filesystem()->GetRunCompletion(this));
    if (err != PP_OK_COMPLETIONPENDING) {
      // Anything else, we should assume the socket has gone bad.
      node_->SetError_Locked(err);
      return false;
    }

    node_->SetStreamFlags(SSF_SENDING);
    return true;
  }

  virtual void Run(int32_t length_error) {
    AUTO_LOCK(emitter_->GetLock());

    if (length_error < 0) {
      node_->SetError_Locked(length_error);
      return;
    }

    // If we did send, then Q more work.
    node_->ClearStreamFlags(SSF_SENDING);
    node_->QueueOutput();
  }

 private:
  // We assume that transmits will always complete.  If the upstream
  // actually back pressures, enough to prevent the Send callback
  // from triggering, this resource may never go away.
  ScopedSocketNode node_;
};

class UdpRecvWork : public UdpWork {
 public:
  explicit UdpRecvWork(const ScopedUdpEventEmitter& emitter)
      : UdpWork(emitter) {
  }

  virtual bool Start(int32_t val) {
    AUTO_LOCK(emitter_->GetLock());
    UdpNode* stream = static_cast<UdpNode*>(emitter_->stream());

    // Does the stream exist, and can it recv?
    if (NULL == stream || !stream->TestStreamFlags(SSF_CAN_RECV))
      return false;

    // Check if we are already receiving.
    if (stream->TestStreamFlags(SSF_RECVING))
      return false;

    stream->SetStreamFlags(SSF_RECVING);
    int err = UDPInterface()->RecvFrom(stream->socket_resource(),
                                       data_,
                                       kMaxPacketSize,
                                       &addr_,
                                       filesystem()->GetRunCompletion(this));
    if (err != PP_OK_COMPLETIONPENDING) {
      stream->SetError_Locked(err);
      return false;
    }

    return true;
  }

  virtual void Run(int32_t length_error) {
    AUTO_LOCK(emitter_->GetLock());
    UdpNode* stream = static_cast<UdpNode*>(emitter_->stream());
    if (NULL == stream)
      return;

    // On successful receive we queue more input
    if (length_error > 0) {
      Packet* packet = new Packet(filesystem()->ppapi());
      packet->Copy(data_, length_error, addr_);
      emitter_->WriteRXPacket_Locked(packet);
      stream->ClearStreamFlags(SSF_RECVING);
      stream->QueueInput();
    } else {
      stream->SetError_Locked(length_error);
    }
  }

 private:
  char data_[kMaxPacketSize];
  PP_Resource addr_;
};

UdpNode::UdpNode(Filesystem* filesystem)
    : SocketNode(filesystem),
      emitter_(new UdpEventEmitter(kDefaultFifoSize, kDefaultFifoSize)) {
  emitter_->AttachStream(this);
}

void UdpNode::Destroy() {
  emitter_->DetachStream();
  SocketNode::Destroy();
}

UdpEventEmitter* UdpNode::GetEventEmitter() {
  return emitter_.get();
}

Error UdpNode::Init(int open_flags) {
  Error err = SocketNode::Init(open_flags);
  if (err != 0)
    return err;

  if (UDPInterface() == NULL) {
    LOG_ERROR("Got NULL interface: UDP");
    return EACCES;
  }

  socket_resource_ =
      UDPInterface()->Create(filesystem_->ppapi()->GetInstance());
  if (0 == socket_resource_) {
    LOG_ERROR("Unable to create UDP resource.");
    return EACCES;
  }

  return 0;
}

void UdpNode::QueueInput() {
  UdpRecvWork* work = new UdpRecvWork(emitter_);
  stream()->EnqueueWork(work);
}

void UdpNode::QueueOutput() {
  if (!TestStreamFlags(SSF_CAN_SEND))
    return;

  if (TestStreamFlags(SSF_SENDING))
    return;

  UdpSendWork* work = new UdpSendWork(emitter_, ScopedSocketNode(this));
  stream()->EnqueueWork(work);
}

Error UdpNode::Bind(const struct sockaddr* addr, socklen_t len) {
  if (0 == socket_resource_)
    return EBADF;

  /* Only bind once. */
  if (IsBound())
    return EINVAL;

  PP_Resource out_addr = SockAddrToResource(addr, len);
  if (0 == out_addr)
    return EINVAL;

  int err =
      UDPInterface()->Bind(socket_resource_, out_addr, PP_BlockUntilComplete());
  filesystem_->ppapi()->ReleaseResource(out_addr);
  if (err != 0)
    return PPErrorToErrno(err);

  // Get the address that was actually bound (in case addr was 0.0.0.0:0).
  out_addr = UDPInterface()->GetBoundAddress(socket_resource_);
  if (out_addr == 0)
    return EINVAL;

  // Now that we are bound, we can start sending and receiving.
  SetStreamFlags(SSF_CAN_SEND | SSF_CAN_RECV);
  QueueInput();

  local_addr_ = out_addr;
  return 0;
}

Error UdpNode::Connect(const HandleAttr& attr,
                       const struct sockaddr* addr,
                       socklen_t len) {
  if (0 == socket_resource_)
    return EBADF;

  /* Connect for UDP is the default dest, it's legal to change it. */
  if (remote_addr_ != 0) {
    filesystem_->ppapi()->ReleaseResource(remote_addr_);
    remote_addr_ = 0;
  }

  remote_addr_ = SockAddrToResource(addr, len);
  if (0 == remote_addr_)
    return EINVAL;

  return 0;
}

Error UdpNode::Recv_Locked(void* buf,
                           size_t len,
                           PP_Resource* out_addr,
                           int* out_len) {
  Packet* packet = emitter_->ReadRXPacket_Locked();
  *out_len = 0;
  *out_addr = 0;

  if (packet) {
    int capped_len = static_cast<int32_t>(std::min<int>(len, packet->len()));
    memcpy(buf, packet->buffer(), capped_len);

    if (packet->addr() != 0) {
      filesystem_->ppapi()->AddRefResource(packet->addr());
      *out_addr = packet->addr();
    }

    *out_len = capped_len;
    delete packet;
    return 0;
  }

  // Should never happen, Recv_Locked should not be called
  // unless already in a POLLIN state.
  return EBADF;
}

Error UdpNode::Send_Locked(const void* buf,
                           size_t len,
                           PP_Resource addr,
                           int* out_len) {
  if (!IsBound()) {
    // Pepper requires a socket to be bound before it can send.
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = 0;
    memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
    Error err =
        Bind(reinterpret_cast<const struct sockaddr*>(&addr), sizeof(addr));
    if (err != 0)
      return err;
  }

  *out_len = 0;
  int capped_len = static_cast<int32_t>(std::min<int>(len, kMaxPacketSize));
  Packet* packet = new Packet(filesystem_->ppapi());
  packet->Copy(buf, capped_len, addr);

  emitter_->WriteTXPacket_Locked(packet);
  *out_len = capped_len;
  return 0;
}

}  // namespace nacl_io
<commit_msg>[NaCl SDK] nacl_io: Fix leak when recv'ing from udp socket.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "nacl_io/socket/udp_node.h"

#include <errno.h>
#include <string.h>

#include <algorithm>

#include "nacl_io/log.h"
#include "nacl_io/pepper_interface.h"
#include "nacl_io/socket/packet.h"
#include "nacl_io/socket/udp_event_emitter.h"
#include "nacl_io/stream/stream_fs.h"

namespace {
const size_t kMaxPacketSize = 65536;
const size_t kDefaultFifoSize = kMaxPacketSize * 8;
}

namespace nacl_io {

class UdpWork : public StreamFs::Work {
 public:
  explicit UdpWork(const ScopedUdpEventEmitter& emitter)
      : StreamFs::Work(emitter->stream()->stream()),
        emitter_(emitter),
        packet_(NULL) {}

  ~UdpWork() { delete packet_; }

  UDPSocketInterface* UDPInterface() {
    return filesystem()->ppapi()->GetUDPSocketInterface();
  }

 protected:
  ScopedUdpEventEmitter emitter_;
  Packet* packet_;
};

class UdpSendWork : public UdpWork {
 public:
  explicit UdpSendWork(const ScopedUdpEventEmitter& emitter,
                       const ScopedSocketNode& node)
      : UdpWork(emitter), node_(node) {}

  virtual bool Start(int32_t val) {
    AUTO_LOCK(emitter_->GetLock());

    // Does the stream exist, and can it send?
    if (!node_->TestStreamFlags(SSF_CAN_SEND))
      return false;

    packet_ = emitter_->ReadTXPacket_Locked();
    if (NULL == packet_)
      return false;

    int err = UDPInterface()->SendTo(node_->socket_resource(),
                                     packet_->buffer(),
                                     packet_->len(),
                                     packet_->addr(),
                                     filesystem()->GetRunCompletion(this));
    if (err != PP_OK_COMPLETIONPENDING) {
      // Anything else, we should assume the socket has gone bad.
      node_->SetError_Locked(err);
      return false;
    }

    node_->SetStreamFlags(SSF_SENDING);
    return true;
  }

  virtual void Run(int32_t length_error) {
    AUTO_LOCK(emitter_->GetLock());

    if (length_error < 0) {
      node_->SetError_Locked(length_error);
      return;
    }

    // If we did send, then Q more work.
    node_->ClearStreamFlags(SSF_SENDING);
    node_->QueueOutput();
  }

 private:
  // We assume that transmits will always complete.  If the upstream
  // actually back pressures, enough to prevent the Send callback
  // from triggering, this resource may never go away.
  ScopedSocketNode node_;
};

class UdpRecvWork : public UdpWork {
 public:
  explicit UdpRecvWork(const ScopedUdpEventEmitter& emitter)
      : UdpWork(emitter) {
  }

  virtual bool Start(int32_t val) {
    AUTO_LOCK(emitter_->GetLock());
    UdpNode* stream = static_cast<UdpNode*>(emitter_->stream());

    // Does the stream exist, and can it recv?
    if (NULL == stream || !stream->TestStreamFlags(SSF_CAN_RECV))
      return false;

    // Check if we are already receiving.
    if (stream->TestStreamFlags(SSF_RECVING))
      return false;

    stream->SetStreamFlags(SSF_RECVING);
    int err = UDPInterface()->RecvFrom(stream->socket_resource(),
                                       data_,
                                       kMaxPacketSize,
                                       &addr_,
                                       filesystem()->GetRunCompletion(this));
    if (err != PP_OK_COMPLETIONPENDING) {
      stream->SetError_Locked(err);
      return false;
    }

    return true;
  }

  virtual void Run(int32_t length_error) {
    AUTO_LOCK(emitter_->GetLock());
    UdpNode* stream = static_cast<UdpNode*>(emitter_->stream());
    if (NULL == stream)
      return;

    // On successful receive we queue more input
    if (length_error > 0) {
      Packet* packet = new Packet(filesystem()->ppapi());
      packet->Copy(data_, length_error, addr_);
      filesystem()->ppapi()->ReleaseResource(addr_);
      emitter_->WriteRXPacket_Locked(packet);
      stream->ClearStreamFlags(SSF_RECVING);
      stream->QueueInput();
    } else {
      stream->SetError_Locked(length_error);
    }
  }

 private:
  char data_[kMaxPacketSize];
  PP_Resource addr_;
};

UdpNode::UdpNode(Filesystem* filesystem)
    : SocketNode(filesystem),
      emitter_(new UdpEventEmitter(kDefaultFifoSize, kDefaultFifoSize)) {
  emitter_->AttachStream(this);
}

void UdpNode::Destroy() {
  emitter_->DetachStream();
  SocketNode::Destroy();
}

UdpEventEmitter* UdpNode::GetEventEmitter() {
  return emitter_.get();
}

Error UdpNode::Init(int open_flags) {
  Error err = SocketNode::Init(open_flags);
  if (err != 0)
    return err;

  if (UDPInterface() == NULL) {
    LOG_ERROR("Got NULL interface: UDP");
    return EACCES;
  }

  socket_resource_ =
      UDPInterface()->Create(filesystem_->ppapi()->GetInstance());
  if (0 == socket_resource_) {
    LOG_ERROR("Unable to create UDP resource.");
    return EACCES;
  }

  return 0;
}

void UdpNode::QueueInput() {
  UdpRecvWork* work = new UdpRecvWork(emitter_);
  stream()->EnqueueWork(work);
}

void UdpNode::QueueOutput() {
  if (!TestStreamFlags(SSF_CAN_SEND))
    return;

  if (TestStreamFlags(SSF_SENDING))
    return;

  UdpSendWork* work = new UdpSendWork(emitter_, ScopedSocketNode(this));
  stream()->EnqueueWork(work);
}

Error UdpNode::Bind(const struct sockaddr* addr, socklen_t len) {
  if (0 == socket_resource_)
    return EBADF;

  /* Only bind once. */
  if (IsBound())
    return EINVAL;

  PP_Resource out_addr = SockAddrToResource(addr, len);
  if (0 == out_addr)
    return EINVAL;

  int err =
      UDPInterface()->Bind(socket_resource_, out_addr, PP_BlockUntilComplete());
  filesystem_->ppapi()->ReleaseResource(out_addr);
  if (err != 0)
    return PPErrorToErrno(err);

  // Get the address that was actually bound (in case addr was 0.0.0.0:0).
  out_addr = UDPInterface()->GetBoundAddress(socket_resource_);
  if (out_addr == 0)
    return EINVAL;

  // Now that we are bound, we can start sending and receiving.
  SetStreamFlags(SSF_CAN_SEND | SSF_CAN_RECV);
  QueueInput();

  local_addr_ = out_addr;
  return 0;
}

Error UdpNode::Connect(const HandleAttr& attr,
                       const struct sockaddr* addr,
                       socklen_t len) {
  if (0 == socket_resource_)
    return EBADF;

  /* Connect for UDP is the default dest, it's legal to change it. */
  if (remote_addr_ != 0) {
    filesystem_->ppapi()->ReleaseResource(remote_addr_);
    remote_addr_ = 0;
  }

  remote_addr_ = SockAddrToResource(addr, len);
  if (0 == remote_addr_)
    return EINVAL;

  return 0;
}

Error UdpNode::Recv_Locked(void* buf,
                           size_t len,
                           PP_Resource* out_addr,
                           int* out_len) {
  Packet* packet = emitter_->ReadRXPacket_Locked();
  *out_len = 0;
  *out_addr = 0;

  if (packet) {
    int capped_len = static_cast<int32_t>(std::min<int>(len, packet->len()));
    memcpy(buf, packet->buffer(), capped_len);

    if (packet->addr() != 0) {
      filesystem_->ppapi()->AddRefResource(packet->addr());
      *out_addr = packet->addr();
    }

    *out_len = capped_len;
    delete packet;
    return 0;
  }

  // Should never happen, Recv_Locked should not be called
  // unless already in a POLLIN state.
  return EBADF;
}

Error UdpNode::Send_Locked(const void* buf,
                           size_t len,
                           PP_Resource addr,
                           int* out_len) {
  if (!IsBound()) {
    // Pepper requires a socket to be bound before it can send.
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = 0;
    memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
    Error err =
        Bind(reinterpret_cast<const struct sockaddr*>(&addr), sizeof(addr));
    if (err != 0)
      return err;
  }

  *out_len = 0;
  int capped_len = static_cast<int32_t>(std::min<int>(len, kMaxPacketSize));
  Packet* packet = new Packet(filesystem_->ppapi());
  packet->Copy(buf, capped_len, addr);

  emitter_->WriteTXPacket_Locked(packet);
  *out_len = capped_len;
  return 0;
}

}  // namespace nacl_io
<|endoftext|>