<commit_before>//
//  GlExtras.cpp
//  Kepler
//
//  Created by Robert Hodgin on 4/7/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#include "BloomGl.h"

using namespace ci;

namespace bloom { namespace gl {
//	void drawBillboard( const Vec3f &pos, const Vec2f &scale, float rotationDegrees, const Vec3f &bbRight, const Vec3f &bbUp )
//	{
//		glEnableClientState( GL_VERTEX_ARRAY );
//		Vec3f verts[4];
//		glVertexPointer( 3, GL_FLOAT, 0, &verts[0].x );
//		glEnableClientState( GL_TEXTURE_COORD_ARRAY );
//		GLfloat texCoords[8] = { 0, 0, 0, 1, 1, 0, 1, 1 };
//		glTexCoordPointer( 2, GL_FLOAT, 0, texCoords );
//
//		float sinA = math<float>::sin( toRadians( rotationDegrees ) );
//		float cosA = math<float>::cos( toRadians( rotationDegrees ) );
//
//		verts[0] = pos + bbRight * ( -0.5f * scale.x * cosA - 0.5f * sinA * scale.y ) + bbUp * ( -0.5f * scale.x * sinA + 0.5f * cosA * scale.y );
//		verts[1] = pos + bbRight * ( -0.5f * scale.x * cosA - -0.5f * sinA * scale.y ) + bbUp * ( -0.5f * scale.x * sinA + -0.5f * cosA * scale.y );
//		verts[2] = pos + bbRight * ( 0.5f * scale.x * cosA - 0.5f * sinA * scale.y ) + bbUp * ( 0.5f * scale.x * sinA + 0.5f * cosA * scale.y );
//		verts[3] = pos + bbRight * ( 0.5f * scale.x * cosA - -0.5f * sinA * scale.y ) + bbUp * ( 0.5f * scale.x * sinA + -0.5f * cosA * scale.y );
//
//		glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
//
//		glDisableClientState( GL_VERTEX_ARRAY );
//		glDisableClientState( GL_TEXTURE_COORD_ARRAY );
//	}

	void drawBillboard( const Vec3f &pos, const Vec2f &scale, float rotInRadians, const Vec3f &bbRight, const Vec3f &bbUp )
	{
		glEnableClientState( GL_VERTEX_ARRAY );
		Vec3f verts[4];
		glVertexPointer( 3, GL_FLOAT, 0, &verts[0].x );
		glEnableClientState( GL_TEXTURE_COORD_ARRAY );
		GLfloat texCoords[8] = { 0, 0, 0, 1, 1, 0, 1, 1 };
		glTexCoordPointer( 2, GL_FLOAT, 0, texCoords );

		float sinA = math<float>::sin( rotInRadians );
		float cosA = math<float>::cos( rotInRadians );

		float scaleXCosA = 0.5f * scale.x * cosA;
		float scaleXSinA = 0.5f * scale.x * sinA;
		float scaleYSinA = 0.5f * scale.y * sinA;
		float scaleYCosA = 0.5f * scale.y * cosA;
		verts[0] = pos + bbRight * ( -scaleXCosA - scaleYSinA ) + bbUp * ( -scaleXSinA + scaleYCosA );
		verts[1] = pos + bbRight * ( -scaleXCosA + scaleYSinA ) + bbUp * ( -scaleXSinA - scaleYCosA );
		verts[2] = pos + bbRight * (  scaleXCosA - scaleYSinA ) + bbUp * (  scaleXSinA + scaleYCosA );
		verts[3] = pos + bbRight * (  scaleXCosA + scaleYSinA ) + bbUp * (  scaleXSinA - scaleYCosA );

		glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );

		glDisableClientState( GL_VERTEX_ARRAY );
		glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	}

	void drawSphericalBillboard( const Vec3f &camEye, const Vec3f &objPos, const Vec2f &scale, float rotInRadians )
	{
		glPushMatrix();
		glTranslatef( objPos.x, objPos.y, objPos.z );

		Vec3f lookAt = Vec3f::zAxis();
		Vec3f upAux;
		float angleCosine;

		Vec3f objToCam = ( camEye - objPos ).normalized();
		Vec3f objToCamProj = Vec3f( objToCam.x, 0.0f, objToCam.z );
		objToCamProj.normalize();

		upAux = lookAt.cross( objToCamProj );

// Cylindrical billboarding
		angleCosine = constrain( lookAt.dot( objToCamProj ), -1.0f, 1.0f );
		glRotatef( toDegrees( acos(angleCosine) ), upAux.x, upAux.y, upAux.z );

// Spherical billboarding
		angleCosine = constrain( objToCamProj.dot( objToCam ), -1.0f, 1.0f );
		if( objToCam.y < 0 )	glRotatef( toDegrees( acos(angleCosine) ), 1.0f, 0.0f, 0.0f );
		else					glRotatef( toDegrees( acos(angleCosine) ),-1.0f, 0.0f, 0.0f );

		Vec3f verts[4];
		GLfloat texCoords[8] = { 0, 0, 0, 1, 1, 0, 1, 1 };

		glEnableClientState( GL_VERTEX_ARRAY );
		glEnableClientState( GL_TEXTURE_COORD_ARRAY );
		glVertexPointer( 3, GL_FLOAT, 0, &verts[0].x );
		glTexCoordPointer( 2, GL_FLOAT, 0, texCoords );

		float sinA = math<float>::sin( rotInRadians );
		float cosA = math<float>::cos( rotInRadians );

		float scaleXCosA = 0.5f * scale.x * cosA;
		float scaleXSinA = 0.5f * scale.x * sinA;
		float scaleYSinA = 0.5f * scale.y * sinA;
		float scaleYCosA = 0.5f * scale.y * cosA;

		verts[0] = Vec3f( ( -scaleXCosA - scaleYSinA ), ( -scaleXSinA + scaleYCosA ), 0.0f );
		verts[1] = Vec3f( ( -scaleXCosA + scaleYSinA ), ( -scaleXSinA - scaleYCosA ), 0.0f );
		verts[2] = Vec3f( (  scaleXCosA - scaleYSinA ), (  scaleXSinA + scaleYCosA ), 0.0f );
		verts[3] = Vec3f( (  scaleXCosA + scaleYSinA ), (  scaleXSinA - scaleYCosA ), 0.0f );

		glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );

		glDisableClientState( GL_VERTEX_ARRAY );
		glDisableClientState( GL_TEXTURE_COORD_ARRAY );

//		glDisable( GL_TEXTURE_2D );
//		ci::gl::color( Color( 1.0f, 1.0f, 1.0f ) );
//		ci::gl::drawLine( Vec3f::zero(), objToCam );
//		glEnable( GL_TEXTURE_2D );

		glPopMatrix();
	}

	void drawButton( const ci::Rectf &rect, float u1, float v1, float u2, float v2 )
	{
		glEnableClientState( GL_VERTEX_ARRAY );
		GLfloat verts[8];
		glVertexPointer( 2, GL_FLOAT, 0, verts );
		glEnableClientState( GL_TEXTURE_COORD_ARRAY );
		GLfloat texCoords[8];
		glTexCoordPointer( 2, GL_FLOAT, 0, texCoords );
		int vi = 0;
		int ti = 0;
		verts[vi++] = rect.getX2(); texCoords[ti++] = u2;
		verts[vi++] = rect.getY1(); texCoords[ti++] = v1;
		verts[vi++] = rect.getX1(); texCoords[ti++] = u1;
		verts[vi++] = rect.getY1(); texCoords[ti++] = v1;
		verts[vi++] = rect.getX2(); texCoords[ti++] = u2;
		verts[vi++] = rect.getY2(); texCoords[ti++] = v2;
		verts[vi++] = rect.getX1(); texCoords[ti++] = u1;
		verts[vi++] = rect.getY2(); texCoords[ti++] = v2;

		glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );

		glDisableClientState( GL_VERTEX_ARRAY );
		glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	}

    BatchMap batchMap;

    void beginBatch()
    {
        batchMap.clear();
    }

    void batchRect( const ci::gl::Texture &texture, const ci::Rectf &srcRect, const ci::Rectf &dstRect )
    {
        GLuint texId = texture.getId();
        Batch *batch = &batchMap[texId];
        int verts = batch->vertices.size();
        if (verts == 0) {
            batch->texture = texture;
        }
        batch->vertices.resize(verts + 6);
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x1, dstRect.y1);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x1, srcRect.y1);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x2, dstRect.y1);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x2, srcRect.y1);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x2, dstRect.y2);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x2, srcRect.y2);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x1, dstRect.y1);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x1, srcRect.y1);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x1, dstRect.y2);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x1, srcRect.y2);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x2, dstRect.y2);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x2, srcRect.y2);
        //verts++;
    }

    void batchRect( const ci::gl::Texture &texture, const ci::Area &srcArea, const ci::Rectf &dstRect )
    {
        batchRect( texture, texture.getAreaTexCoords( srcArea ), dstRect );
    }

    void batchRect( const ci::gl::Texture &texture, const ci::Vec2f &pos )
    {
        batchRect( texture, texture.getCleanBounds(), ci::Rectf(pos.x, pos.y, pos.x + texture.getWidth(), pos.y + texture.getHeight()) );
    }

    void endBatch()
    {
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        for (BatchMap::iterator it = batchMap.begin(); it != batchMap.end(); ++it) {
            Batch *batch = &it->second;
            batch->texture.enableAndBind();
            glVertexPointer(2, GL_FLOAT, sizeof(VertexData), &batch->vertices[0].vertex);
            glTexCoordPointer(2, GL_FLOAT, sizeof(VertexData), &batch->vertices[0].texture);
            glDrawArrays(GL_TRIANGLES, 0, batch->vertices.size());
            batch->texture.disable();
        }
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    }

} }<commit_msg>remove drawButton (unused now)<commit_after>//
//  GlExtras.cpp
//  Kepler
//
//  Created by Robert Hodgin on 4/7/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#include "BloomGl.h"

using namespace ci;

namespace bloom { namespace gl {

//	void drawBillboard( const Vec3f &pos, const Vec2f &scale, float rotationDegrees, const Vec3f &bbRight, const Vec3f &bbUp )
//	{
//		glEnableClientState( GL_VERTEX_ARRAY );
//		Vec3f verts[4];
//		glVertexPointer( 3, GL_FLOAT, 0, &verts[0].x );
//		glEnableClientState( GL_TEXTURE_COORD_ARRAY );
//		GLfloat texCoords[8] = { 0, 0, 0, 1, 1, 0, 1, 1 };
//		glTexCoordPointer( 2, GL_FLOAT, 0, texCoords );
//
//		float sinA = math<float>::sin( toRadians( rotationDegrees ) );
//		float cosA = math<float>::cos( toRadians( rotationDegrees ) );
//
//		verts[0] = pos + bbRight * ( -0.5f * scale.x * cosA - 0.5f * sinA * scale.y ) + bbUp * ( -0.5f * scale.x * sinA + 0.5f * cosA * scale.y );
//		verts[1] = pos + bbRight * ( -0.5f * scale.x * cosA - -0.5f * sinA * scale.y ) + bbUp * ( -0.5f * scale.x * sinA + -0.5f * cosA * scale.y );
//		verts[2] = pos + bbRight * ( 0.5f * scale.x * cosA - 0.5f * sinA * scale.y ) + bbUp * ( 0.5f * scale.x * sinA + 0.5f * cosA * scale.y );
//		verts[3] = pos + bbRight * ( 0.5f * scale.x * cosA - -0.5f * sinA * scale.y ) + bbUp * ( 0.5f * scale.x * sinA + -0.5f * cosA * scale.y );
//
//		glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
//
//		glDisableClientState( GL_VERTEX_ARRAY );
//		glDisableClientState( GL_TEXTURE_COORD_ARRAY );
//	}

	void drawBillboard( const Vec3f &pos, const Vec2f &scale, float rotInRadians, const Vec3f &bbRight, const Vec3f &bbUp )
	{
		glEnableClientState( GL_VERTEX_ARRAY );
		Vec3f verts[4];
		glVertexPointer( 3, GL_FLOAT, 0, &verts[0].x );
		glEnableClientState( GL_TEXTURE_COORD_ARRAY );
		GLfloat texCoords[8] = { 0, 0, 0, 1, 1, 0, 1, 1 };
		glTexCoordPointer( 2, GL_FLOAT, 0, texCoords );

		float sinA = math<float>::sin( rotInRadians );
		float cosA = math<float>::cos( rotInRadians );

		float scaleXCosA = 0.5f * scale.x * cosA;
		float scaleXSinA = 0.5f * scale.x * sinA;
		float scaleYSinA = 0.5f * scale.y * sinA;
		float scaleYCosA = 0.5f * scale.y * cosA;
		verts[0] = pos + bbRight * ( -scaleXCosA - scaleYSinA ) + bbUp * ( -scaleXSinA + scaleYCosA );
		verts[1] = pos + bbRight * ( -scaleXCosA + scaleYSinA ) + bbUp * ( -scaleXSinA - scaleYCosA );
		verts[2] = pos + bbRight * (  scaleXCosA - scaleYSinA ) + bbUp * (  scaleXSinA + scaleYCosA );
		verts[3] = pos + bbRight * (  scaleXCosA + scaleYSinA ) + bbUp * (  scaleXSinA - scaleYCosA );

		glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );

		glDisableClientState( GL_VERTEX_ARRAY );
		glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	}

	void drawSphericalBillboard( const Vec3f &camEye, const Vec3f &objPos, const Vec2f &scale, float rotInRadians )
	{
		glPushMatrix();
		glTranslatef( objPos.x, objPos.y, objPos.z );

		Vec3f lookAt = Vec3f::zAxis();
		Vec3f upAux;
		float angleCosine;

		Vec3f objToCam = ( camEye - objPos ).normalized();
		Vec3f objToCamProj = Vec3f( objToCam.x, 0.0f, objToCam.z );
		objToCamProj.normalize();

		upAux = lookAt.cross( objToCamProj );

// Cylindrical billboarding
		angleCosine = constrain( lookAt.dot( objToCamProj ), -1.0f, 1.0f );
		glRotatef( toDegrees( acos(angleCosine) ), upAux.x, upAux.y, upAux.z );

// Spherical billboarding
		angleCosine = constrain( objToCamProj.dot( objToCam ), -1.0f, 1.0f );
		if( objToCam.y < 0 )	glRotatef( toDegrees( acos(angleCosine) ), 1.0f, 0.0f, 0.0f );
		else					glRotatef( toDegrees( acos(angleCosine) ),-1.0f, 0.0f, 0.0f );

		Vec3f verts[4];
		GLfloat texCoords[8] = { 0, 0, 0, 1, 1, 0, 1, 1 };

		glEnableClientState( GL_VERTEX_ARRAY );
		glEnableClientState( GL_TEXTURE_COORD_ARRAY );
		glVertexPointer( 3, GL_FLOAT, 0, &verts[0].x );
		glTexCoordPointer( 2, GL_FLOAT, 0, texCoords );

		float sinA = math<float>::sin( rotInRadians );
		float cosA = math<float>::cos( rotInRadians );

		float scaleXCosA = 0.5f * scale.x * cosA;
		float scaleXSinA = 0.5f * scale.x * sinA;
		float scaleYSinA = 0.5f * scale.y * sinA;
		float scaleYCosA = 0.5f * scale.y * cosA;

		verts[0] = Vec3f( ( -scaleXCosA - scaleYSinA ), ( -scaleXSinA + scaleYCosA ), 0.0f );
		verts[1] = Vec3f( ( -scaleXCosA + scaleYSinA ), ( -scaleXSinA - scaleYCosA ), 0.0f );
		verts[2] = Vec3f( (  scaleXCosA - scaleYSinA ), (  scaleXSinA + scaleYCosA ), 0.0f );
		verts[3] = Vec3f( (  scaleXCosA + scaleYSinA ), (  scaleXSinA - scaleYCosA ), 0.0f );

		glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );

		glDisableClientState( GL_VERTEX_ARRAY );
		glDisableClientState( GL_TEXTURE_COORD_ARRAY );

//		glDisable( GL_TEXTURE_2D );
//		ci::gl::color( Color( 1.0f, 1.0f, 1.0f ) );
//		ci::gl::drawLine( Vec3f::zero(), objToCam );
//		glEnable( GL_TEXTURE_2D );

		glPopMatrix();
	}

    /////////////////////////////////////////////////////////

    BatchMap batchMap;

    void beginBatch()
    {
        batchMap.clear();
    }

    void batchRect( const ci::gl::Texture &texture, const ci::Rectf &srcRect, const ci::Rectf &dstRect )
    {
        GLuint texId = texture.getId();
        Batch *batch = &batchMap[texId];
        int verts = batch->vertices.size();
        if (verts == 0) {
            batch->texture = texture;
        }
        batch->vertices.resize(verts + 6);
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x1, dstRect.y1);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x1, srcRect.y1);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x2, dstRect.y1);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x2, srcRect.y1);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x2, dstRect.y2);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x2, srcRect.y2);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x1, dstRect.y1);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x1, srcRect.y1);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x1, dstRect.y2);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x1, srcRect.y2);
        verts++;
        batch->vertices[verts].vertex  = ci::Vec2f(dstRect.x2, dstRect.y2);
        batch->vertices[verts].texture = ci::Vec2f(srcRect.x2, srcRect.y2);
        //verts++;
    }

    void batchRect( const ci::gl::Texture &texture, const ci::Area &srcArea, const ci::Rectf &dstRect )
    {
        batchRect( texture, texture.getAreaTexCoords( srcArea ), dstRect );
    }

    void batchRect( const ci::gl::Texture &texture, const ci::Vec2f &pos )
    {
        batchRect( texture, texture.getCleanBounds(), ci::Rectf(pos.x, pos.y, pos.x + texture.getWidth(), pos.y + texture.getHeight()) );
    }

    void endBatch()
    {
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        for (BatchMap::iterator it = batchMap.begin(); it != batchMap.end(); ++it) {
            Batch *batch = &it->second;
            batch->texture.enableAndBind();
            glVertexPointer(2, GL_FLOAT, sizeof(VertexData), &batch->vertices[0].vertex);
            glTexCoordPointer(2, GL_FLOAT, sizeof(VertexData), &batch->vertices[0].texture);
            glDrawArrays(GL_TRIANGLES, 0, batch->vertices.size());
            batch->texture.disable();
        }
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    }

} }<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <stdio.h>
#include <algorithm>
#include <string>

#include "media/base/streamparams.h"
#include "media/engine/constants.h"
#include "media/engine/simulcast.h"
#include "modules/video_coding/utility/simulcast_rate_allocator.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/field_trial.h"

namespace cricket {

namespace {

constexpr int kScreenshareDefaultTl0BitrateKbps = 200;
constexpr int kScreenshareDefaultTl1BitrateKbps = 1000;

static const char* kSimulcastScreenshareFieldTrialName =
    "WebRTC-SimulcastScreenshare";

}  // namespace

struct SimulcastFormat {
  int width;
  int height;
  // The maximum number of simulcast layers can be used for
  // resolutions at |widthxheigh|.
  size_t max_layers;
  // The maximum bitrate for encoding stream at |widthxheight|, when we are
  // not sending the next higher spatial stream.
  int max_bitrate_kbps;
  // The target bitrate for encoding stream at |widthxheight|, when this layer
  // is not the highest layer (i.e., when we are sending another higher spatial
  // stream).
  int target_bitrate_kbps;
  // The minimum bitrate needed for encoding stream at |widthxheight|.
  int min_bitrate_kbps;
};

// These tables describe from which resolution we can use how many
// simulcast layers at what bitrates (maximum, target, and minimum).
// Important!! Keep this table from high resolution to low resolution.
// clang-format off
const SimulcastFormat kSimulcastFormats[] = {
  {1920, 1080, 3, 5000, 4000, 800},
  {1280, 720, 3,  2500, 2500, 600},
  {960, 540, 3, 900, 900, 450},
  {640, 360, 2, 700, 500, 150},
  {480, 270, 2, 450, 350, 150},
  {320, 180, 1, 200, 150, 30},
  {0, 0, 1, 200, 150, 30}
};
// clang-format on

const int kMaxScreenshareSimulcastLayers = 2;

// Multiway: Number of temporal layers for each simulcast stream.
int DefaultNumberOfTemporalLayers(int simulcast_id) {
  RTC_CHECK_GE(simulcast_id, 0);
  RTC_CHECK_LT(simulcast_id, webrtc::kMaxSimulcastStreams);

  const int kDefaultNumTemporalLayers = 3;

  const std::string group_name =
      webrtc::field_trial::FindFullName("WebRTC-VP8ConferenceTemporalLayers");
  if (group_name.empty())
    return kDefaultNumTemporalLayers;

  int num_temporal_layers = kDefaultNumTemporalLayers;
  if (sscanf(group_name.c_str(), "%d", &num_temporal_layers) == 1 &&
      num_temporal_layers > 0 &&
      num_temporal_layers <= webrtc::kMaxTemporalStreams) {
    return num_temporal_layers;
  }

  RTC_LOG(LS_WARNING) << "Attempt to set number of temporal layers to "
                         "incorrect value: "
                      << group_name;

  return kDefaultNumTemporalLayers;
}

int FindSimulcastFormatIndex(int width, int height) {
  RTC_DCHECK_GE(width, 0);
  RTC_DCHECK_GE(height, 0);
  for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) {
    if (width * height >=
        kSimulcastFormats[i].width * kSimulcastFormats[i].height) {
      return i;
    }
  }
  RTC_NOTREACHED();
  return -1;
}

int FindSimulcastFormatIndex(int width, int height, size_t max_layers) {
  RTC_DCHECK_GE(width, 0);
  RTC_DCHECK_GE(height, 0);
  RTC_DCHECK_GT(max_layers, 0);
  for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) {
    if (width * height >=
            kSimulcastFormats[i].width * kSimulcastFormats[i].height &&
        max_layers == kSimulcastFormats[i].max_layers) {
      return i;
    }
  }
  RTC_NOTREACHED();
  return -1;
}

// Simulcast stream width and height must both be dividable by
// |2 ^ (simulcast_layers - 1)|.
int NormalizeSimulcastSize(int size, size_t simulcast_layers) {
  const int base2_exponent = static_cast<int>(simulcast_layers) - 1;
  return ((size >> base2_exponent) << base2_exponent);
}

size_t FindSimulcastMaxLayers(int width, int height) {
  int index = FindSimulcastFormatIndex(width, height);
  return kSimulcastFormats[index].max_layers;
}

int FindSimulcastMaxBitrateBps(int width, int height) {
  const int format_index = FindSimulcastFormatIndex(width, height);
  return kSimulcastFormats[format_index].max_bitrate_kbps * 1000;
}

int FindSimulcastTargetBitrateBps(int width, int height) {
  const int format_index = FindSimulcastFormatIndex(width, height);
  return kSimulcastFormats[format_index].target_bitrate_kbps * 1000;
}

int FindSimulcastMinBitrateBps(int width, int height) {
  const int format_index = FindSimulcastFormatIndex(width, height);
  return kSimulcastFormats[format_index].min_bitrate_kbps * 1000;
}

void SlotSimulcastMaxResolution(size_t max_layers, int* width, int* height) {
  int index = FindSimulcastFormatIndex(*width, *height, max_layers);
  *width = kSimulcastFormats[index].width;
  *height = kSimulcastFormats[index].height;
  RTC_LOG(LS_INFO) << "SlotSimulcastMaxResolution to width:" << *width
                   << " height:" << *height;
}

void BoostMaxSimulcastLayer(int max_bitrate_bps,
                            std::vector<webrtc::VideoStream>* layers) {
  if (layers->empty())
    return;

  // Spend additional bits to boost the max layer.
  int bitrate_left_bps = max_bitrate_bps - GetTotalMaxBitrateBps(*layers);
  if (bitrate_left_bps > 0) {
    layers->back().max_bitrate_bps += bitrate_left_bps;
  }
}

int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& layers) {
  if (layers.empty())
    return 0;

  int total_max_bitrate_bps = 0;
  for (size_t s = 0; s < layers.size() - 1; ++s) {
    total_max_bitrate_bps += layers[s].target_bitrate_bps;
  }
  total_max_bitrate_bps += layers.back().max_bitrate_bps;
  return total_max_bitrate_bps;
}

std::vector<webrtc::VideoStream> GetSimulcastConfig(
    size_t max_layers,
    int width,
    int height,
    int /*max_bitrate_bps*/,
    double bitrate_priority,
    int max_qp,
    int max_framerate,
    bool is_screenshare,
    bool temporal_layers_supported) {
  if (is_screenshare) {
    return GetScreenshareLayers(max_layers, width, height, bitrate_priority,
                                max_qp, max_framerate,
                                ScreenshareSimulcastFieldTrialEnabled(),
                                temporal_layers_supported);
  } else {
    return GetNormalSimulcastLayers(max_layers, width, height, bitrate_priority,
                                    max_qp, max_framerate,
                                    temporal_layers_supported);
  }
}

std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
    size_t max_layers,
    int width,
    int height,
    double bitrate_priority,
    int max_qp,
    int max_framerate,
    bool temporal_layers_supported) {
  // TODO(bugs.webrtc.org/8785): Currently if the resolution isn't large enough
  // (defined in kSimulcastFormats) we scale down the number of simulcast
  // layers. Consider changing this so that the application can have more
  // control over exactly how many simulcast layers are used.
  size_t num_simulcast_layers = FindSimulcastMaxLayers(width, height);
  if (num_simulcast_layers > max_layers) {
    // TODO(bugs.webrtc.org/8486): This scales down the resolution if the
    // number of simulcast layers created by the application isn't sufficient
    // (defined in kSimulcastFormats). For example if the input frame's
    // resolution is HD, but there are only 2 simulcast layers, the
    // resolution gets scaled down to VGA. Consider taking this logic out to
    // allow the application more control over the resolutions.
    SlotSimulcastMaxResolution(max_layers, &width, &height);
    num_simulcast_layers = max_layers;
  }
  std::vector<webrtc::VideoStream> layers(num_simulcast_layers);

  // Format width and height has to be divisible by |2 ^ num_simulcast_layers -
  // 1|.
  width = NormalizeSimulcastSize(width, num_simulcast_layers);
  height = NormalizeSimulcastSize(height, num_simulcast_layers);
  // Add simulcast streams, from highest resolution (|s| = num_simulcast_layers
  // -1) to lowest resolution at |s| = 0.
  for (size_t s = num_simulcast_layers - 1;; --s) {
    layers[s].width = width;
    layers[s].height = height;
    // TODO(pbos): Fill actual temporal-layer bitrate thresholds.
    layers[s].max_qp = max_qp;
    layers[s].num_temporal_layers =
        temporal_layers_supported ? DefaultNumberOfTemporalLayers(s)
                                  : 0;
    layers[s].max_bitrate_bps = FindSimulcastMaxBitrateBps(width, height);
    layers[s].target_bitrate_bps = FindSimulcastTargetBitrateBps(width, height);
    int num_temporal_layers = DefaultNumberOfTemporalLayers(s);
    if (s == 0 && num_temporal_layers != 3) {
      // If alternative number temporal layers is selected, adjust the
      // bitrate of the lowest simulcast stream so that absolute bitrate for
      // the base temporal layer matches the bitrate for the base temporal
      // layer with the default 3 simulcast streams. Otherwise we risk a
      // higher threshold for receiving a feed at all.
      const float rate_factor =
          webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(3, 0) /
          webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
              num_temporal_layers, 0);
      layers[s].max_bitrate_bps =
          static_cast<int>(layers[s].max_bitrate_bps * rate_factor);
      layers[s].target_bitrate_bps =
          static_cast<int>(layers[s].target_bitrate_bps * rate_factor);
    }
    layers[s].min_bitrate_bps = FindSimulcastMinBitrateBps(width, height);
    layers[s].max_framerate = max_framerate;

    width /= 2;
    height /= 2;

    if (s == 0) {
      break;
    }
  }
  // Currently the relative bitrate priority of the sender is controlled by
  // the value of the lowest VideoStream.
  // TODO(bugs.webrtc.org/8630): The web specification describes being able to
  // control relative bitrate for each individual simulcast layer, but this
  // is currently just implemented per rtp sender.
  layers[0].bitrate_priority = bitrate_priority;
  return layers;
}

std::vector<webrtc::VideoStream> GetScreenshareLayers(
    size_t max_layers,
    int width,
    int height,
    double bitrate_priority,
    int max_qp,
    int max_framerate,
    bool screenshare_simulcast_enabled,
    bool temporal_layers_supported) {
  auto max_screenshare_layers =
      screenshare_simulcast_enabled ? kMaxScreenshareSimulcastLayers : 1;
  size_t num_simulcast_layers =
      std::min<int>(max_layers, max_screenshare_layers);

  std::vector<webrtc::VideoStream> layers(num_simulcast_layers);
  // For legacy screenshare in conference mode, tl0 and tl1 bitrates are
  // piggybacked on the VideoCodec struct as target and max bitrates,
  // respectively. See eg. webrtc::LibvpxVp8Encoder::SetRates().
  layers[0].width = width;
  layers[0].height = height;
  layers[0].max_qp = max_qp;
  layers[0].max_framerate = 5;
  layers[0].min_bitrate_bps = kMinVideoBitrateBps;
  layers[0].target_bitrate_bps = kScreenshareDefaultTl0BitrateKbps * 1000;
  layers[0].max_bitrate_bps = kScreenshareDefaultTl1BitrateKbps * 1000;
  layers[0].num_temporal_layers = temporal_layers_supported ? 2 : 0;

  // With simulcast enabled, add another spatial layer. This one will have a
  // more normal layout, with the regular 3 temporal layer pattern and no fps
  // restrictions. The base simulcast layer will still use legacy setup.
  if (num_simulcast_layers == kMaxScreenshareSimulcastLayers) {
    // Add optional upper simulcast layer.
    // Lowest temporal layers of a 3 layer setup will have 40% of the total
    // bitrate allocation for that simulcast layer. Make sure the gap between
    // the target of the lower simulcast layer and first temporal layer of the
    // higher one is at most 2x the bitrate, so that upswitching is not hampered
    // by stalled bitrate estimates.
    int max_bitrate_bps = 2 * ((layers[0].target_bitrate_bps * 10) / 4);
    // Cap max bitrate so it isn't overly high for the given resolution.
    max_bitrate_bps = std::min<int>(max_bitrate_bps,
                                    FindSimulcastMaxBitrateBps(width, height));

    layers[1].width = width;
    layers[1].height = height;
    layers[1].max_qp = max_qp;
    layers[1].max_framerate = max_framerate;
    layers[1].num_temporal_layers = 3;
    layers[1].min_bitrate_bps = layers[0].target_bitrate_bps * 2;
    layers[1].target_bitrate_bps = max_bitrate_bps;
    layers[1].max_bitrate_bps = max_bitrate_bps;
  }

  // The bitrate priority currently implemented on a per-sender level, so we
  // just set it for the first simulcast layer.
  layers[0].bitrate_priority = bitrate_priority;
  return layers;
}

bool ScreenshareSimulcastFieldTrialEnabled() {
  return webrtc::field_trial::IsEnabled(kSimulcastScreenshareFieldTrialName);
}

}  // namespace cricket
<commit_msg>Lower TL0 bitrate to 40% for lowest stream when using short 3tl<commit_after>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <stdio.h>
#include <algorithm>
#include <string>

#include "media/base/streamparams.h"
#include "media/engine/constants.h"
#include "media/engine/simulcast.h"
#include "modules/video_coding/utility/simulcast_rate_allocator.h"
#include "rtc_base/arraysize.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/field_trial.h"

namespace cricket {

namespace {

constexpr int kScreenshareDefaultTl0BitrateKbps = 200;
constexpr int kScreenshareDefaultTl1BitrateKbps = 1000;

static const char* kSimulcastScreenshareFieldTrialName =
    "WebRTC-SimulcastScreenshare";

}  // namespace

struct SimulcastFormat {
  int width;
  int height;
  // The maximum number of simulcast layers can be used for
  // resolutions at |widthxheigh|.
  size_t max_layers;
  // The maximum bitrate for encoding stream at |widthxheight|, when we are
  // not sending the next higher spatial stream.
  int max_bitrate_kbps;
  // The target bitrate for encoding stream at |widthxheight|, when this layer
  // is not the highest layer (i.e., when we are sending another higher spatial
  // stream).
  int target_bitrate_kbps;
  // The minimum bitrate needed for encoding stream at |widthxheight|.
  int min_bitrate_kbps;
};

// These tables describe from which resolution we can use how many
// simulcast layers at what bitrates (maximum, target, and minimum).
// Important!! Keep this table from high resolution to low resolution.
// clang-format off
const SimulcastFormat kSimulcastFormats[] = {
  {1920, 1080, 3, 5000, 4000, 800},
  {1280, 720, 3,  2500, 2500, 600},
  {960, 540, 3, 900, 900, 450},
  {640, 360, 2, 700, 500, 150},
  {480, 270, 2, 450, 350, 150},
  {320, 180, 1, 200, 150, 30},
  {0, 0, 1, 200, 150, 30}
};
// clang-format on

const int kMaxScreenshareSimulcastLayers = 2;

// Multiway: Number of temporal layers for each simulcast stream.
int DefaultNumberOfTemporalLayers(int simulcast_id) {
  RTC_CHECK_GE(simulcast_id, 0);
  RTC_CHECK_LT(simulcast_id, webrtc::kMaxSimulcastStreams);

  const int kDefaultNumTemporalLayers = 3;

  const std::string group_name =
      webrtc::field_trial::FindFullName("WebRTC-VP8ConferenceTemporalLayers");
  if (group_name.empty())
    return kDefaultNumTemporalLayers;

  int num_temporal_layers = kDefaultNumTemporalLayers;
  if (sscanf(group_name.c_str(), "%d", &num_temporal_layers) == 1 &&
      num_temporal_layers > 0 &&
      num_temporal_layers <= webrtc::kMaxTemporalStreams) {
    return num_temporal_layers;
  }

  RTC_LOG(LS_WARNING) << "Attempt to set number of temporal layers to "
                         "incorrect value: "
                      << group_name;

  return kDefaultNumTemporalLayers;
}

int FindSimulcastFormatIndex(int width, int height) {
  RTC_DCHECK_GE(width, 0);
  RTC_DCHECK_GE(height, 0);
  for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) {
    if (width * height >=
        kSimulcastFormats[i].width * kSimulcastFormats[i].height) {
      return i;
    }
  }
  RTC_NOTREACHED();
  return -1;
}

int FindSimulcastFormatIndex(int width, int height, size_t max_layers) {
  RTC_DCHECK_GE(width, 0);
  RTC_DCHECK_GE(height, 0);
  RTC_DCHECK_GT(max_layers, 0);
  for (uint32_t i = 0; i < arraysize(kSimulcastFormats); ++i) {
    if (width * height >=
            kSimulcastFormats[i].width * kSimulcastFormats[i].height &&
        max_layers == kSimulcastFormats[i].max_layers) {
      return i;
    }
  }
  RTC_NOTREACHED();
  return -1;
}

// Simulcast stream width and height must both be dividable by
// |2 ^ (simulcast_layers - 1)|.
int NormalizeSimulcastSize(int size, size_t simulcast_layers) {
  const int base2_exponent = static_cast<int>(simulcast_layers) - 1;
  return ((size >> base2_exponent) << base2_exponent);
}

size_t FindSimulcastMaxLayers(int width, int height) {
  int index = FindSimulcastFormatIndex(width, height);
  return kSimulcastFormats[index].max_layers;
}

int FindSimulcastMaxBitrateBps(int width, int height) {
  const int format_index = FindSimulcastFormatIndex(width, height);
  return kSimulcastFormats[format_index].max_bitrate_kbps * 1000;
}

int FindSimulcastTargetBitrateBps(int width, int height) {
  const int format_index = FindSimulcastFormatIndex(width, height);
  return kSimulcastFormats[format_index].target_bitrate_kbps * 1000;
}

int FindSimulcastMinBitrateBps(int width, int height) {
  const int format_index = FindSimulcastFormatIndex(width, height);
  return kSimulcastFormats[format_index].min_bitrate_kbps * 1000;
}

void SlotSimulcastMaxResolution(size_t max_layers, int* width, int* height) {
  int index = FindSimulcastFormatIndex(*width, *height, max_layers);
  *width = kSimulcastFormats[index].width;
  *height = kSimulcastFormats[index].height;
  RTC_LOG(LS_INFO) << "SlotSimulcastMaxResolution to width:" << *width
                   << " height:" << *height;
}

void BoostMaxSimulcastLayer(int max_bitrate_bps,
                            std::vector<webrtc::VideoStream>* layers) {
  if (layers->empty())
    return;

  // Spend additional bits to boost the max layer.
  int bitrate_left_bps = max_bitrate_bps - GetTotalMaxBitrateBps(*layers);
  if (bitrate_left_bps > 0) {
    layers->back().max_bitrate_bps += bitrate_left_bps;
  }
}

int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& layers) {
  if (layers.empty())
    return 0;

  int total_max_bitrate_bps = 0;
  for (size_t s = 0; s < layers.size() - 1; ++s) {
    total_max_bitrate_bps += layers[s].target_bitrate_bps;
  }
  total_max_bitrate_bps += layers.back().max_bitrate_bps;
  return total_max_bitrate_bps;
}

std::vector<webrtc::VideoStream> GetSimulcastConfig(
    size_t max_layers,
    int width,
    int height,
    int /*max_bitrate_bps*/,
    double bitrate_priority,
    int max_qp,
    int max_framerate,
    bool is_screenshare,
    bool temporal_layers_supported) {
  if (is_screenshare) {
    return GetScreenshareLayers(max_layers, width, height, bitrate_priority,
                                max_qp, max_framerate,
                                ScreenshareSimulcastFieldTrialEnabled(),
                                temporal_layers_supported);
  } else {
    return GetNormalSimulcastLayers(max_layers, width, height, bitrate_priority,
                                    max_qp, max_framerate,
                                    temporal_layers_supported);
  }
}

std::vector<webrtc::VideoStream> GetNormalSimulcastLayers(
    size_t max_layers,
    int width,
    int height,
    double bitrate_priority,
    int max_qp,
    int max_framerate,
    bool temporal_layers_supported) {
  // TODO(bugs.webrtc.org/8785): Currently if the resolution isn't large enough
  // (defined in kSimulcastFormats) we scale down the number of simulcast
  // layers. Consider changing this so that the application can have more
  // control over exactly how many simulcast layers are used.
  size_t num_simulcast_layers = FindSimulcastMaxLayers(width, height);
  if (num_simulcast_layers > max_layers) {
    // TODO(bugs.webrtc.org/8486): This scales down the resolution if the
    // number of simulcast layers created by the application isn't sufficient
    // (defined in kSimulcastFormats). For example if the input frame's
    // resolution is HD, but there are only 2 simulcast layers, the
    // resolution gets scaled down to VGA. Consider taking this logic out to
    // allow the application more control over the resolutions.
    SlotSimulcastMaxResolution(max_layers, &width, &height);
    num_simulcast_layers = max_layers;
  }
  std::vector<webrtc::VideoStream> layers(num_simulcast_layers);

  // Format width and height has to be divisible by |2 ^ num_simulcast_layers -
  // 1|.
  width = NormalizeSimulcastSize(width, num_simulcast_layers);
  height = NormalizeSimulcastSize(height, num_simulcast_layers);
  // Add simulcast streams, from highest resolution (|s| = num_simulcast_layers
  // -1) to lowest resolution at |s| = 0.
  for (size_t s = num_simulcast_layers - 1;; --s) {
    layers[s].width = width;
    layers[s].height = height;
    // TODO(pbos): Fill actual temporal-layer bitrate thresholds.
    layers[s].max_qp = max_qp;
    layers[s].num_temporal_layers =
        temporal_layers_supported ? DefaultNumberOfTemporalLayers(s)
                                  : 0;
    layers[s].max_bitrate_bps = FindSimulcastMaxBitrateBps(width, height);
    layers[s].target_bitrate_bps = FindSimulcastTargetBitrateBps(width, height);
    int num_temporal_layers = DefaultNumberOfTemporalLayers(s);
    if (s == 0) {
      // If alternative number temporal layers is selected, adjust the
      // bitrate of the lowest simulcast stream so that absolute bitrate for
      // the base temporal layer matches the bitrate for the base temporal
      // layer with the default 3 simulcast streams. Otherwise we risk a
      // higher threshold for receiving a feed at all.
      float rate_factor = 1.0;
      if (num_temporal_layers == 3) {
        if (webrtc::field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) {
          // Shortened pattern increases TL0 bitrate from 40% to 60%.
          rate_factor = 0.4 / 0.6;
        }
      } else {
        rate_factor =
            webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(3, 0) /
            webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(
                num_temporal_layers, 0);
      }

      layers[s].max_bitrate_bps =
          static_cast<int>(layers[s].max_bitrate_bps * rate_factor);
      layers[s].target_bitrate_bps =
          static_cast<int>(layers[s].target_bitrate_bps * rate_factor);
    }
    layers[s].min_bitrate_bps = FindSimulcastMinBitrateBps(width, height);
    layers[s].max_framerate = max_framerate;

    width /= 2;
    height /= 2;

    if (s == 0) {
      break;
    }
  }
  // Currently the relative bitrate priority of the sender is controlled by
  // the value of the lowest VideoStream.
  // TODO(bugs.webrtc.org/8630): The web specification describes being able to
  // control relative bitrate for each individual simulcast layer, but this
  // is currently just implemented per rtp sender.
  layers[0].bitrate_priority = bitrate_priority;
  return layers;
}

std::vector<webrtc::VideoStream> GetScreenshareLayers(
    size_t max_layers,
    int width,
    int height,
    double bitrate_priority,
    int max_qp,
    int max_framerate,
    bool screenshare_simulcast_enabled,
    bool temporal_layers_supported) {
  auto max_screenshare_layers =
      screenshare_simulcast_enabled ? kMaxScreenshareSimulcastLayers : 1;
  size_t num_simulcast_layers =
      std::min<int>(max_layers, max_screenshare_layers);

  std::vector<webrtc::VideoStream> layers(num_simulcast_layers);
  // For legacy screenshare in conference mode, tl0 and tl1 bitrates are
  // piggybacked on the VideoCodec struct as target and max bitrates,
  // respectively. See eg. webrtc::LibvpxVp8Encoder::SetRates().
  layers[0].width = width;
  layers[0].height = height;
  layers[0].max_qp = max_qp;
  layers[0].max_framerate = 5;
  layers[0].min_bitrate_bps = kMinVideoBitrateBps;
  layers[0].target_bitrate_bps = kScreenshareDefaultTl0BitrateKbps * 1000;
  layers[0].max_bitrate_bps = kScreenshareDefaultTl1BitrateKbps * 1000;
  layers[0].num_temporal_layers = temporal_layers_supported ? 2 : 0;

  // With simulcast enabled, add another spatial layer. This one will have a
  // more normal layout, with the regular 3 temporal layer pattern and no fps
  // restrictions. The base simulcast layer will still use legacy setup.
  if (num_simulcast_layers == kMaxScreenshareSimulcastLayers) {
    // Add optional upper simulcast layer.
    // Lowest temporal layers of a 3 layer setup will have 40% of the total
    // bitrate allocation for that simulcast layer. Make sure the gap between
    // the target of the lower simulcast layer and first temporal layer of the
    // higher one is at most 2x the bitrate, so that upswitching is not hampered
    // by stalled bitrate estimates.
    int max_bitrate_bps = 2 * ((layers[0].target_bitrate_bps * 10) / 4);
    // Cap max bitrate so it isn't overly high for the given resolution.
    max_bitrate_bps = std::min<int>(max_bitrate_bps,
                                    FindSimulcastMaxBitrateBps(width, height));

    layers[1].width = width;
    layers[1].height = height;
    layers[1].max_qp = max_qp;
    layers[1].max_framerate = max_framerate;
    layers[1].num_temporal_layers = 3;
    layers[1].min_bitrate_bps = layers[0].target_bitrate_bps * 2;
    layers[1].target_bitrate_bps = max_bitrate_bps;
    layers[1].max_bitrate_bps = max_bitrate_bps;
  }

  // The bitrate priority currently implemented on a per-sender level, so we
  // just set it for the first simulcast layer.
  layers[0].bitrate_priority = bitrate_priority;
  return layers;
}

bool ScreenshareSimulcastFieldTrialEnabled() {
  return webrtc::field_trial::IsEnabled(kSimulcastScreenshareFieldTrialName);
}

}  // namespace cricket
<|endoftext|>


<commit_before>#include <algorithm>
#include <fstream>
#include <ctime>

#ifdef WIN32
#  define WIN32_LEAN_AND_MEAN
#  include <Windows.h>
#else
#  include <sys/stat.h>
#endif

#include "CLogger.hpp"
#include "CSampConfigReader.hpp"
#include "CMessage.hpp"
#include "crashhandler.hpp"

CLogger::CLogger(std::string module) :
	m_ModuleName(module),
	m_FileName("logs/" + module + ".log")
{
	g3::installCrashHandler();

	//create possibly non-existing folders before opening log file
	size_t pos = 0;
	while ((pos = m_FileName.find('/', pos)) != std::string::npos)
	{
		auto dir = m_FileName.substr(0, pos++);
#ifdef WIN32
		std::replace(dir.begin(), dir.end(), '/', '\\');
		CreateDirectoryA(dir.c_str(), NULL);
#else
		mkdir(dir.c_str(), ACCESSPERMS);
#endif
	}
}

void CLogger::SetLogLevel(const LogLevel level, bool enabled)
{
	LogLevel current_loglevel = m_LogLevel.load(std::memory_order_acquire);
	if (enabled)
	{
		current_loglevel = static_cast<LogLevel>(
			static_cast<LogLevel_ut>(current_loglevel) | static_cast<LogLevel_ut>(level));
	}
	else
	{
		current_loglevel = static_cast<LogLevel>(
			static_cast<LogLevel_ut>(current_loglevel) & ~static_cast<LogLevel_ut>(level));
	}
	m_LogLevel.store(current_loglevel, std::memory_order_release);
}

bool CLogger::IsLogLevel(const LogLevel level)
{
	LogLevel current_loglevel = m_LogLevel.load(std::memory_order_acquire);
	return current_loglevel & level;
}

void CLogger::Log(const char *msg,
	const LogLevel level, int line/* = 0*/, const char *file/* = ""*/,
	const char *function/* = ""*/)
{
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
	g3::installSignalHandlerForThread();
#endif

	if (IsLogLevel(level) == false)
		return;

	Message_t message(new CMessage(
		m_FileName, m_ModuleName, level, msg, line, file, function));
	CLogManager::Get()->QueueLogMessage(std::move(message));
}

void CLogger::Destroy()
{
	delete this;
}

ILogger *CreateLoggerPtr(const char *modulename)
{
	return new CLogger(modulename);
}

CLogManager::CLogManager() :
	m_ThreadRunning(true),
	m_WarningLog("logs/warnings.log"),
	m_ErrorLog("logs/errors.log")
{
	if (CSampConfigReader::Get()->GetVar("logtimeformat", m_DateTimeFormat))
	{
		//delete brackets
		size_t pos = 0;
		while ((pos = m_DateTimeFormat.find_first_of("[]")) != std::string::npos)
			m_DateTimeFormat.erase(pos, 1);
	}
	else
	{
		m_DateTimeFormat = "%d.%m.%y %X";
	}

	m_Thread = new std::thread(std::bind(&CLogManager::Process, this));
}

CLogManager::~CLogManager()
{
	m_ThreadRunning = false;
	m_Thread->join();
	delete m_Thread;
}

void CLogManager::QueueLogMessage(Message_t &&msg)
{
	{
		std::lock_guard<std::mutex> lg(m_QueueMtx);
		m_LogMsgQueue.push(std::move(msg));
	}
	m_QueueNotifier.notify_one();
}

void CLogManager::Process()
{
	std::unique_lock<std::mutex> lk(m_QueueMtx);
	std::function<bool()> condition = [this]() { return !m_LogMsgQueue.empty(); };

	do
	{
		m_QueueNotifier.wait(lk, condition);
		Message_t &msg = m_LogMsgQueue.front();

		char buf[64];
		std::time_t now_c = std::chrono::system_clock::to_time_t(msg->timestamp);
		std::strftime(buf, 64, m_DateTimeFormat.c_str(), std::localtime(&now_c));
		std::string timestamp(buf);

		std::string loglevel_str;
		switch (msg->loglevel)
		{
		case LogLevel::DEBUG:
			loglevel_str = "DEBUG";
			break;
		case LogLevel::INFO:
			loglevel_str = "INFO";
			break;
		case LogLevel::WARNING:
			loglevel_str = "WARNING";
			break;
		case LogLevel::ERROR:
			loglevel_str = "ERROR";
			break;
		default:
			loglevel_str = "<unknown>";
		}

		//default logging
		std::ofstream logfile(msg->log_filename, std::ofstream::out | std::ofstream::app);
		logfile <<
			"[" << timestamp << "] " <<
			"[" << loglevel_str << "] " <<
			msg->text;
		if (msg->line != 0)
		{
			logfile << " (" << msg->file << ":" << msg->line << ")";
		}
		logfile << '\n' << std::flush;

		//log-level logging
		std::ofstream *loglevel_file = nullptr;
		if (msg->loglevel & LogLevel::WARNING)
			loglevel_file = &m_WarningLog;
		else if (msg->loglevel & LogLevel::ERROR)
			loglevel_file = &m_ErrorLog;

		if(loglevel_file != nullptr)
		{
			(*loglevel_file) <<
				"[" << timestamp << "] " <<
				"[" << msg->log_module << "] " <<
				msg->text;
			if (msg->line != 0)
			{
				(*loglevel_file) << " (" << msg->file << ":" << msg->line << ")";
			}
			(*loglevel_file) << '\n' << std::flush;
		}

		m_LogMsgQueue.pop();
	} while (m_ThreadRunning || (m_ThreadRunning == false && condition()) );
}
<commit_msg>minor improvements<commit_after>#include <algorithm>
#include <fstream>
#include <ctime>

#ifdef WIN32
#  define WIN32_LEAN_AND_MEAN
#  include <Windows.h>
#else
#  include <sys/stat.h>
#endif

#include "CLogger.hpp"
#include "CSampConfigReader.hpp"
#include "CMessage.hpp"
#include "crashhandler.hpp"

CLogger::CLogger(std::string module) :
	m_ModuleName(module),
	m_FileName("logs/" + module + ".log")
{
	g3::installCrashHandler();

	//create possibly non-existing folders before opening log file
	size_t pos = 0;
	while ((pos = m_FileName.find('/', pos)) != std::string::npos)
	{
		auto dir = m_FileName.substr(0, pos++);
#ifdef WIN32
		std::replace(dir.begin(), dir.end(), '/', '\\');
		CreateDirectoryA(dir.c_str(), NULL);
#else
		mkdir(dir.c_str(), ACCESSPERMS);
#endif
	}
}

void CLogger::SetLogLevel(const LogLevel level, bool enabled)
{
	LogLevel current_loglevel = m_LogLevel.load(std::memory_order_acquire);
	if (enabled)
	{
		current_loglevel = static_cast<LogLevel>(
			static_cast<LogLevel_ut>(current_loglevel) | static_cast<LogLevel_ut>(level));
	}
	else
	{
		current_loglevel = static_cast<LogLevel>(
			static_cast<LogLevel_ut>(current_loglevel) & ~static_cast<LogLevel_ut>(level));
	}
	m_LogLevel.store(current_loglevel, std::memory_order_release);
}

bool CLogger::IsLogLevel(const LogLevel level)
{
	LogLevel current_loglevel = m_LogLevel.load(std::memory_order_acquire);
	return current_loglevel & level;
}

void CLogger::Log(const char *msg,
	const LogLevel level, int line/* = 0*/, const char *file/* = ""*/,
	const char *function/* = ""*/)
{
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
	g3::installSignalHandlerForThread();
#endif

	if (IsLogLevel(level) == false)
		return;

	Message_t message(new CMessage(
		m_FileName, m_ModuleName, level, msg, line, file, function));
	CLogManager::Get()->QueueLogMessage(std::move(message));
}

void CLogger::Destroy()
{
	delete this;
}

ILogger *CreateLoggerPtr(const char *modulename)
{
	return new CLogger(modulename);
}

CLogManager::CLogManager() :
	m_ThreadRunning(true),
	m_WarningLog("logs/warnings.log"),
	m_ErrorLog("logs/errors.log")
{
	if (CSampConfigReader::Get()->GetVar("logtimeformat", m_DateTimeFormat))
	{
		//delete brackets
		size_t pos = 0;
		while ((pos = m_DateTimeFormat.find_first_of("[]()")) != std::string::npos)
			m_DateTimeFormat.erase(pos, 1);
	}
	else
	{
		m_DateTimeFormat = "%x %X";
	}

	m_Thread = new std::thread(std::bind(&CLogManager::Process, this));
}

CLogManager::~CLogManager()
{
	m_ThreadRunning = false;
	m_Thread->join();
	delete m_Thread;
}

void CLogManager::QueueLogMessage(Message_t &&msg)
{
	{
		std::lock_guard<std::mutex> lg(m_QueueMtx);
		m_LogMsgQueue.push(std::move(msg));
	}
	m_QueueNotifier.notify_one();
}

void CLogManager::Process()
{
	std::unique_lock<std::mutex> lk(m_QueueMtx);
	std::function<bool()> condition = [this]() { return !m_LogMsgQueue.empty(); };

	do
	{
		m_QueueNotifier.wait(lk, condition);
		Message_t &msg = m_LogMsgQueue.front();

		char timestamp[64];
		std::time_t now_c = std::chrono::system_clock::to_time_t(msg->timestamp);
		std::strftime(timestamp, sizeof(timestamp)/sizeof(char),
			m_DateTimeFormat.c_str(), std::localtime(&now_c));

		const char *loglevel_str = "<unknown>";
		switch (msg->loglevel)
		{
		case LogLevel::DEBUG:
			loglevel_str = "DEBUG";
			break;
		case LogLevel::INFO:
			loglevel_str = "INFO";
			break;
		case LogLevel::WARNING:
			loglevel_str = "WARNING";
			break;
		case LogLevel::ERROR:
			loglevel_str = "ERROR";
			break;
		}

		//default logging
		std::ofstream logfile(msg->log_filename, std::ofstream::out | std::ofstream::app);
		logfile <<
			"[" << timestamp << "] " <<
			"[" << loglevel_str << "] " <<
			msg->text;
		if (msg->line != 0)
		{
			logfile << " (" << msg->file << ":" << msg->line << ")";
		}
		logfile << '\n' << std::flush;

		//log-level logging
		std::ofstream *loglevel_file = nullptr;
		if (msg->loglevel & LogLevel::WARNING)
			loglevel_file = &m_WarningLog;
		else if (msg->loglevel & LogLevel::ERROR)
			loglevel_file = &m_ErrorLog;

		if(loglevel_file != nullptr)
		{
			(*loglevel_file) <<
				"[" << timestamp << "] " <<
				"[" << msg->log_module << "] " <<
				msg->text;
			if (msg->line != 0)
			{
				(*loglevel_file) << " (" << msg->file << ":" << msg->line << ")";
			}
			(*loglevel_file) << '\n' << std::flush;
		}

		m_LogMsgQueue.pop();
	} while (m_ThreadRunning || (m_ThreadRunning == false && condition()) );
}
<|endoftext|>


<commit_before>/**************************************************************************
** This file is part of LiteIDE
**
** Copyright (c) 2011-2017 LiteIDE Team. All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** In addition, as a special exception,  that plugins developed for LiteIDE,
** are allowed to remain closed sourced and can be distributed under any license .
** These rights are included in the file LGPL_EXCEPTION.txt in this package.
**
**************************************************************************/
// Module: idletimer.cpp
// Creator: visualfc <visualfc@gmail.com>

#include "idletimer.h"
#include <QApplication>
//lite_memory_check_begin
#if defined(WIN32) && defined(_MSC_VER) &&  defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
#endif
//lite_memory_check_end

AppIdleTimer::AppIdleTimer()
{
    m_timer = new QTimer(this);
    m_timer->setInterval(1000);
    connect(m_timer,SIGNAL(timeout()),this,SLOT(timeout()));
    qApp->installEventFilter(this);
    m_count = 0;
    m_timer->start();
}

AppIdleTimer::~AppIdleTimer()
{
    m_timer->stop();
}

void AppIdleTimer::resetTimer()
{
    m_count = 0;
    m_timer->stop();
    m_timer->start();
}

void AppIdleTimer::timeout()
{
    m_count++;
    emit appIdle(m_count);
}

bool AppIdleTimer::eventFilter(QObject *obj, QEvent *event)
{
    switch (event->type()) {
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
    case QEvent::MouseButtonDblClick:
    case QEvent::MouseMove:
        resetTimer();
        break;
    default:
        break;
    }
    return QObject::eventFilter(obj,event);
}
<commit_msg>fix build<commit_after>/**************************************************************************
** This file is part of LiteIDE
**
** Copyright (c) 2011-2017 LiteIDE Team. All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** In addition, as a special exception,  that plugins developed for LiteIDE,
** are allowed to remain closed sourced and can be distributed under any license .
** These rights are included in the file LGPL_EXCEPTION.txt in this package.
**
**************************************************************************/
// Module: idletimer.cpp
// Creator: visualfc <visualfc@gmail.com>

#include "idletimer.h"
#include <QApplication>
#include <QTimer>
//lite_memory_check_begin
#if defined(WIN32) && defined(_MSC_VER) &&  defined(_DEBUG)
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
     #define DEBUG_NEW new( _NORMAL_BLOCK, __FILE__, __LINE__ )
     #define new DEBUG_NEW
#endif
//lite_memory_check_end

AppIdleTimer::AppIdleTimer()
{
    m_timer = new QTimer(this);
    m_timer->setInterval(1000);
    connect(m_timer,SIGNAL(timeout()),this,SLOT(timeout()));
    qApp->installEventFilter(this);
    m_count = 0;
    m_timer->start();
}

AppIdleTimer::~AppIdleTimer()
{
    m_timer->stop();
}

void AppIdleTimer::resetTimer()
{
    m_count = 0;
    m_timer->stop();
    m_timer->start();
}

void AppIdleTimer::timeout()
{
    m_count++;
    emit appIdle(m_count);
}

bool AppIdleTimer::eventFilter(QObject *obj, QEvent *event)
{
    switch (event->type()) {
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
    case QEvent::MouseButtonDblClick:
    case QEvent::MouseMove:
        resetTimer();
        break;
    default:
        break;
    }
    return QObject::eventFilter(obj,event);
}
<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 * Copyright (C) 2005 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/opBuffer.h>

#ifndef DEBUG
#define DEBUG 0
#endif

namespace geos {

SubgraphDepthLocater::SubgraphDepthLocater(vector<BufferSubgraph*> *nsg):
	seg(new LineSegment()),
	subgraphs(nsg)
{
	//seg=new LineSegment();
	//cga=new RobustCGAlgorithms();
	//subgraphs=newSubgraphs;
}

SubgraphDepthLocater::~SubgraphDepthLocater(){
	delete seg;
	//delete cga;
}

int
SubgraphDepthLocater::getDepth(Coordinate &p)
{
	vector<DepthSegment*> *stabbedSegments=findStabbedSegments(p);
	// if no segments on stabbing line subgraph must be outside all others->
	if ((int)stabbedSegments->size()==0)
	{
		delete stabbedSegments;
		return 0;
	}
	sort(stabbedSegments->begin(),stabbedSegments->end(),DepthSegmentLT);
	DepthSegment *ds=(*stabbedSegments)[0];
	int ret = ds->leftDepth;
#if DEBUG
	cerr<<"SubgraphDepthLocater::getDepth("<<p.toString()<<"): "<<ret<<endl;
#endif

	vector<DepthSegment *>::iterator it;
	for (it=stabbedSegments->begin(); it != stabbedSegments->end(); it++)
		delete *it;
	delete stabbedSegments;

	return ret;
}

/**
* Finds all non-horizontal segments intersecting the stabbing line->
* The stabbing line is the ray to the right of stabbingRayLeftPt->
*
* @param stabbingRayLeftPt the left-hand origin of the stabbing line
* @return a List of {@link DepthSegments} intersecting the stabbing line
*/
vector<DepthSegment*>* SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt){
	vector<DepthSegment*> *stabbedSegments=new vector<DepthSegment*>();
	for (int i=0;i<(int)subgraphs->size();i++) {
		BufferSubgraph *bsg=(*subgraphs)[i];
		findStabbedSegments(stabbingRayLeftPt, bsg->getDirectedEdges(), stabbedSegments);
	}
	return stabbedSegments;
}

/**
* Finds all non-horizontal segments intersecting the stabbing line
* in the list of dirEdges->
* The stabbing line is the ray to the right of stabbingRayLeftPt->
*
* @param stabbingRayLeftPt the left-hand origin of the stabbing line
* @param stabbedSegments the current list of {@link DepthSegments} intersecting the stabbing line
*/
void SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,vector<DirectedEdge*> *dirEdges,vector<DepthSegment*> *stabbedSegments){
	/**
	* Check all forward DirectedEdges only->  This is still general,
	* because each Edge has a forward DirectedEdge->
	*/
	for(int i=0;i<(int)dirEdges->size();i++) {
		DirectedEdge *de=(*dirEdges)[i];
		if (!de->isForward())
			continue;
		findStabbedSegments(stabbingRayLeftPt, de, stabbedSegments);
	}
}

/**
 * Finds all non-horizontal segments intersecting the stabbing line
 * in the input dirEdge->
 * The stabbing line is the ray to the right of stabbingRayLeftPt->
 *
 * @param stabbingRayLeftPt the left-hand origin of the stabbing line
 * @param stabbedSegments the current list of DepthSegments
 * intersecting the stabbing line
 */
void
SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,DirectedEdge *dirEdge,vector<DepthSegment*> *stabbedSegments)
{
	const CoordinateSequence *pts=dirEdge->getEdge()->getCoordinates();

	for (int i=0; i<pts->getSize()-1; i++) {
		//seg->p0=pts->getAt(i);
		//seg->p1=pts->getAt(i + 1);

		const Coordinate *low=&(pts->getAt(i));
		const Coordinate *high=&(pts->getAt(i+1));
		const Coordinate *swap=NULL;

#if DEBUG
	cerr<<" SubgraphDepthLocater::findStabbedSegments: segment "<<i<<" ("<<seg->toString()<<") ";
#endif

//		// ensure segment always points upwards
//		//if (seg->p0.y > seg->p1.y)
//		{
//			seg->reverse();
//#if DEBUG
//			cerr<<" reverse ("<<seg->toString()<<") ";
//#endif
//		}

		// skip segment if it is left of the stabbing line
		//double maxx=max(seg->p0.x, seg->p1.x);
		double maxx=max(low->x, high->x);
		if (maxx < stabbingRayLeftPt.x)
		{
#if DEBUG
			cerr<<" segment is left to stabbing line, skipping "<<endl;
#endif
			continue;
		}

		// skip horizontal segments (there will be a non-horizontal
		// one carrying the same depth info
		//if (seg->isHorizontal())
		if (low->y == high->y)
		{
#if DEBUG
			cerr<<" segment is horizontal, skipping "<<endl;
#endif
			continue;
		}

		// skip if segment is above or below stabbing line
		//if (stabbingRayLeftPt.y < seg->p0.y ||
			//stabbingRayLeftPt.y > seg->p1.y)
		if (stabbingRayLeftPt.y < low->y ||
			stabbingRayLeftPt.y > high->y)
		{
#if DEBUG
			cerr<<" segment above or below stabbing line, skipping "<<endl;
#endif
			continue;
		}

		// skip if stabbing ray is right of the segment
		//if (CGAlgorithms::computeOrientation(seg->p0, seg->p1,
		if (CGAlgorithms::computeOrientation(*low, *high,
				stabbingRayLeftPt)==CGAlgorithms::RIGHT)
		{
#if DEBUG
			cerr<<" stabbing ray right of segment, skipping"<<endl;
#endif
			continue;
		}

//		// stabbing line cuts this segment, so record it
//		int depth=dirEdge->getDepth(Position::LEFT);
//		// if segment direction was flipped, use RHS depth instead
//		if (! (seg->p0==pts->getAt(i)))
//			depth=dirEdge->getDepth(Position::RIGHT);
		int depth = swap ?
			dirEdge->getDepth(Position::LEFT)
			:
			dirEdge->getDepth(Position::RIGHT);

#if DEBUG
	cerr<<" depth: "<<depth<<endl;
#endif
		seg->p0 = *low;
		seg->p1 = *high;
		DepthSegment *ds=new DepthSegment(seg, depth);
		stabbedSegments->push_back(ds);
	}
}

DepthSegment::DepthSegment(LineSegment *seg, int depth){
	// input seg is assumed to be normalized
	upwardSeg=new LineSegment(*seg);
	//upwardSeg->normalize();
	leftDepth=depth;
}

DepthSegment::~DepthSegment(){
	delete upwardSeg;
}
/**
* Defines a comparision operation on DepthSegments
* which orders them left to right
*
*

* DS1 < DS2   if   DS1->seg is left of DS2->seg
* DS1 > DS2   if   DS1->seg is right of DS2->seg
*

*
* @param obj
* @return
*/
int DepthSegment::compareTo(void* obj){
	DepthSegment *other=(DepthSegment*) obj;
	/**
	* try and compute a determinate orientation for the segments->
	* Test returns 1 if other is left of this (i->e-> this > other)
	*/
	int orientIndex=upwardSeg->orientationIndex(other->upwardSeg);
	/**
	* If comparison between this and other is indeterminate,
	* try the opposite call order->
	* orientationIndex value is 1 if this is left of other,
	* so have to flip sign to get proper comparison value of
	* -1 if this is leftmost
	*/
	if (orientIndex==0)
		orientIndex=-1 * other->upwardSeg->orientationIndex(upwardSeg);
	// if orientation is determinate, return it
	if (orientIndex != 0)
		return orientIndex;
	// otherwise, segs must be collinear - sort based on minimum X value
	return compareX(upwardSeg, other->upwardSeg);
}

/**
* Compare two collinear segments for left-most ordering->
* If segs are vertical, use vertical ordering for comparison->
* If segs are equal, return 0->
* Segments are assumed to be directed so that the second coordinate is >= to the first
* (e->g-> up and to the right)->
*
* @param seg0 a segment to compare
* @param seg1 a segment to compare
* @return
*/
int DepthSegment::compareX(LineSegment *seg0, LineSegment *seg1){
	int compare0=seg0->p0.compareTo(seg1->p0);
	if (compare0!=0)
		return compare0;
	return seg0->p1.compareTo(seg1->p1);

}

bool DepthSegmentLT(DepthSegment *first, DepthSegment *second) {
	if (first->compareTo(second)<=0)
		return true;
	else
		return false;
}

} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.10  2005/06/27 21:24:54  strk
 * Fixed bug just-introduced with optimization.
 *
 * Revision 1.9  2005/06/27 21:21:21  strk
 * Reduced Coordinate copies due to LineSegment overuse
 *
 * Revision 1.8  2005/05/23 15:13:00  strk
 * Added debugging output
 *
 * Revision 1.7  2005/05/20 16:15:41  strk
 * Code cleanups
 *
 * Revision 1.6  2005/05/19 10:29:28  strk
 * Removed some CGAlgorithms instances substituting them with direct calls
 * to the static functions. Interfaces accepting CGAlgorithms pointers kept
 * for backward compatibility but modified to make the argument optional.
 * Fixed a small memory leak in OffsetCurveBuilder::getRingCurve.
 * Inlined some smaller functions encountered during bug hunting.
 * Updated Copyright notices in the touched files.
 *
 * Revision 1.5  2004/07/08 19:34:49  strk
 * Mirrored JTS interface of CoordinateSequence, factory and
 * default implementations.
 * Added DefaultCoordinateSequenceFactory::instance() function.
 *
 * Revision 1.4  2004/07/02 13:28:28  strk
 * Fixed all #include lines to reflect headers layout change.
 * Added client application build tips in README.
 *
 * Revision 1.3  2004/05/05 12:29:44  strk
 * memleak fixed in ::getDepth
 *
 * Revision 1.2  2004/05/03 22:56:44  strk
 * leaks fixed, exception specification omitted.
 *
 * Revision 1.1  2004/04/10 08:40:01  ybychkov
 * "operation/buffer" upgraded to JTS 1.4
 *
 *
 **********************************************************************/

<commit_msg>Bugfix in DepthSegmentLT as suggested by Graeme Hiebert<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
 * Copyright (C) 2005 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#include <geos/opBuffer.h>

#ifndef DEBUG
#define DEBUG 0
#endif

namespace geos {

SubgraphDepthLocater::SubgraphDepthLocater(vector<BufferSubgraph*> *nsg):
	seg(new LineSegment()),
	subgraphs(nsg)
{
	//seg=new LineSegment();
	//cga=new RobustCGAlgorithms();
	//subgraphs=newSubgraphs;
}

SubgraphDepthLocater::~SubgraphDepthLocater(){
	delete seg;
	//delete cga;
}

int
SubgraphDepthLocater::getDepth(Coordinate &p)
{
	vector<DepthSegment*> *stabbedSegments=findStabbedSegments(p);
	// if no segments on stabbing line subgraph must be outside all others->
	if ((int)stabbedSegments->size()==0)
	{
		delete stabbedSegments;
		return 0;
	}
	sort(stabbedSegments->begin(),stabbedSegments->end(),DepthSegmentLT);
	DepthSegment *ds=(*stabbedSegments)[0];
	int ret = ds->leftDepth;
#if DEBUG
	cerr<<"SubgraphDepthLocater::getDepth("<<p.toString()<<"): "<<ret<<endl;
#endif

	vector<DepthSegment *>::iterator it;
	for (it=stabbedSegments->begin(); it != stabbedSegments->end(); it++)
		delete *it;
	delete stabbedSegments;

	return ret;
}

/**
* Finds all non-horizontal segments intersecting the stabbing line->
* The stabbing line is the ray to the right of stabbingRayLeftPt->
*
* @param stabbingRayLeftPt the left-hand origin of the stabbing line
* @return a List of {@link DepthSegments} intersecting the stabbing line
*/
vector<DepthSegment*>* SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt){
	vector<DepthSegment*> *stabbedSegments=new vector<DepthSegment*>();
	for (int i=0;i<(int)subgraphs->size();i++) {
		BufferSubgraph *bsg=(*subgraphs)[i];
		findStabbedSegments(stabbingRayLeftPt, bsg->getDirectedEdges(), stabbedSegments);
	}
	return stabbedSegments;
}

/**
* Finds all non-horizontal segments intersecting the stabbing line
* in the list of dirEdges->
* The stabbing line is the ray to the right of stabbingRayLeftPt->
*
* @param stabbingRayLeftPt the left-hand origin of the stabbing line
* @param stabbedSegments the current list of {@link DepthSegments} intersecting the stabbing line
*/
void SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,vector<DirectedEdge*> *dirEdges,vector<DepthSegment*> *stabbedSegments){
	/**
	* Check all forward DirectedEdges only->  This is still general,
	* because each Edge has a forward DirectedEdge->
	*/
	for(int i=0;i<(int)dirEdges->size();i++) {
		DirectedEdge *de=(*dirEdges)[i];
		if (!de->isForward())
			continue;
		findStabbedSegments(stabbingRayLeftPt, de, stabbedSegments);
	}
}

/**
 * Finds all non-horizontal segments intersecting the stabbing line
 * in the input dirEdge->
 * The stabbing line is the ray to the right of stabbingRayLeftPt->
 *
 * @param stabbingRayLeftPt the left-hand origin of the stabbing line
 * @param stabbedSegments the current list of DepthSegments
 * intersecting the stabbing line
 */
void
SubgraphDepthLocater::findStabbedSegments(Coordinate &stabbingRayLeftPt,DirectedEdge *dirEdge,vector<DepthSegment*> *stabbedSegments)
{
	const CoordinateSequence *pts=dirEdge->getEdge()->getCoordinates();

	for (int i=0; i<pts->getSize()-1; i++) {
		//seg->p0=pts->getAt(i);
		//seg->p1=pts->getAt(i + 1);

		const Coordinate *low=&(pts->getAt(i));
		const Coordinate *high=&(pts->getAt(i+1));
		const Coordinate *swap=NULL;

#if DEBUG
	cerr<<" SubgraphDepthLocater::findStabbedSegments: segment "<<i<<" ("<<seg->toString()<<") ";
#endif

//		// ensure segment always points upwards
//		//if (seg->p0.y > seg->p1.y)
//		{
//			seg->reverse();
//#if DEBUG
//			cerr<<" reverse ("<<seg->toString()<<") ";
//#endif
//		}

		// skip segment if it is left of the stabbing line
		//double maxx=max(seg->p0.x, seg->p1.x);
		double maxx=max(low->x, high->x);
		if (maxx < stabbingRayLeftPt.x)
		{
#if DEBUG
			cerr<<" segment is left to stabbing line, skipping "<<endl;
#endif
			continue;
		}

		// skip horizontal segments (there will be a non-horizontal
		// one carrying the same depth info
		//if (seg->isHorizontal())
		if (low->y == high->y)
		{
#if DEBUG
			cerr<<" segment is horizontal, skipping "<<endl;
#endif
			continue;
		}

		// skip if segment is above or below stabbing line
		//if (stabbingRayLeftPt.y < seg->p0.y ||
			//stabbingRayLeftPt.y > seg->p1.y)
		if (stabbingRayLeftPt.y < low->y ||
			stabbingRayLeftPt.y > high->y)
		{
#if DEBUG
			cerr<<" segment above or below stabbing line, skipping "<<endl;
#endif
			continue;
		}

		// skip if stabbing ray is right of the segment
		//if (CGAlgorithms::computeOrientation(seg->p0, seg->p1,
		if (CGAlgorithms::computeOrientation(*low, *high,
				stabbingRayLeftPt)==CGAlgorithms::RIGHT)
		{
#if DEBUG
			cerr<<" stabbing ray right of segment, skipping"<<endl;
#endif
			continue;
		}

//		// stabbing line cuts this segment, so record it
//		int depth=dirEdge->getDepth(Position::LEFT);
//		// if segment direction was flipped, use RHS depth instead
//		if (! (seg->p0==pts->getAt(i)))
//			depth=dirEdge->getDepth(Position::RIGHT);
		int depth = swap ?
			dirEdge->getDepth(Position::LEFT)
			:
			dirEdge->getDepth(Position::RIGHT);

#if DEBUG
	cerr<<" depth: "<<depth<<endl;
#endif
		seg->p0 = *low;
		seg->p1 = *high;
		DepthSegment *ds=new DepthSegment(seg, depth);
		stabbedSegments->push_back(ds);
	}
}

DepthSegment::DepthSegment(LineSegment *seg, int depth){
	// input seg is assumed to be normalized
	upwardSeg=new LineSegment(*seg);
	//upwardSeg->normalize();
	leftDepth=depth;
}

DepthSegment::~DepthSegment(){
	delete upwardSeg;
}
/**
* Defines a comparision operation on DepthSegments
* which orders them left to right
*
*

* DS1 < DS2   if   DS1->seg is left of DS2->seg
* DS1 > DS2   if   DS1->seg is right of DS2->seg
*

*
* @param obj
* @return
*/
int DepthSegment::compareTo(void* obj){
	DepthSegment *other=(DepthSegment*) obj;
	/**
	* try and compute a determinate orientation for the segments->
	* Test returns 1 if other is left of this (i->e-> this > other)
	*/
	int orientIndex=upwardSeg->orientationIndex(other->upwardSeg);
	/**
	* If comparison between this and other is indeterminate,
	* try the opposite call order->
	* orientationIndex value is 1 if this is left of other,
	* so have to flip sign to get proper comparison value of
	* -1 if this is leftmost
	*/
	if (orientIndex==0)
		orientIndex=-1 * other->upwardSeg->orientationIndex(upwardSeg);
	// if orientation is determinate, return it
	if (orientIndex != 0)
		return orientIndex;
	// otherwise, segs must be collinear - sort based on minimum X value
	return compareX(upwardSeg, other->upwardSeg);
}

/**
* Compare two collinear segments for left-most ordering->
* If segs are vertical, use vertical ordering for comparison->
* If segs are equal, return 0->
* Segments are assumed to be directed so that the second coordinate is >= to the first
* (e->g-> up and to the right)->
*
* @param seg0 a segment to compare
* @param seg1 a segment to compare
* @return
*/
int DepthSegment::compareX(LineSegment *seg0, LineSegment *seg1){
	int compare0=seg0->p0.compareTo(seg1->p0);
	if (compare0!=0)
		return compare0;
	return seg0->p1.compareTo(seg1->p1);

}

bool DepthSegmentLT(DepthSegment *first, DepthSegment *second) {
	if (first->compareTo(second)<0)
		return true;
	else
		return false;
}

} // namespace geos

/**********************************************************************
 * $Log$
 * Revision 1.11  2005/06/27 21:58:31  strk
 * Bugfix in DepthSegmentLT as suggested by Graeme Hiebert
 *
 * Revision 1.10  2005/06/27 21:24:54  strk
 * Fixed bug just-introduced with optimization.
 *
 * Revision 1.9  2005/06/27 21:21:21  strk
 * Reduced Coordinate copies due to LineSegment overuse
 *
 * Revision 1.8  2005/05/23 15:13:00  strk
 * Added debugging output
 *
 * Revision 1.7  2005/05/20 16:15:41  strk
 * Code cleanups
 *
 * Revision 1.6  2005/05/19 10:29:28  strk
 * Removed some CGAlgorithms instances substituting them with direct calls
 * to the static functions. Interfaces accepting CGAlgorithms pointers kept
 * for backward compatibility but modified to make the argument optional.
 * Fixed a small memory leak in OffsetCurveBuilder::getRingCurve.
 * Inlined some smaller functions encountered during bug hunting.
 * Updated Copyright notices in the touched files.
 *
 * Revision 1.5  2004/07/08 19:34:49  strk
 * Mirrored JTS interface of CoordinateSequence, factory and
 * default implementations.
 * Added DefaultCoordinateSequenceFactory::instance() function.
 *
 * Revision 1.4  2004/07/02 13:28:28  strk
 * Fixed all #include lines to reflect headers layout change.
 * Added client application build tips in README.
 *
 * Revision 1.3  2004/05/05 12:29:44  strk
 * memleak fixed in ::getDepth
 *
 * Revision 1.2  2004/05/03 22:56:44  strk
 * leaks fixed, exception specification omitted.
 *
 * Revision 1.1  2004/04/10 08:40:01  ybychkov
 * "operation/buffer" upgraded to JTS 1.4
 *
 *
 **********************************************************************/

<|endoftext|>


<commit_before>/* Copyright 2013 - 2015 Yurii Litvinov and CyberTech Labs Ltd.
 *
 * 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. */

#include "controller.h"

#include <QtCore/QProcess>
#include <QtCore/QFileInfo>

#include <QtXml/QDomDocument>

#include <trikKernel/configurer.h>
#include <trikKernel/fileUtils.h>
#include <trikKernel/paths.h>
#include <trikKernel/exceptions/internalErrorException.h>
#include <trikControl/brickFactory.h>
#include <trikControl/gamepadInterface.h>
#include <trikNetwork/mailboxFactory.h>
#include <trikWiFi/trikWiFi.h>

#include "runningWidget.h"
#include "autoRunner.h"

using namespace trikGui;

const int communicatorPort = 8888;
const int telemetryPort = 9000;

Controller::Controller(const QString &configPath)
	: mBrick(trikControl::BrickFactory::create(configPath, trikKernel::Paths::mediaPath()))
{
	if (configPath.isEmpty()) {
		throw trikKernel::InternalErrorException("Config path is empty");
	}

	auto correctedConfigPath = configPath.endsWith('/') ? configPath : configPath + '/';

	trikKernel::Configurer configurer(correctedConfigPath + "system-config.xml"
			, correctedConfigPath + "model-config.xml");

	connect(mBrick->gamepad(), &trikControl::GamepadInterface::disconnected
			, this, &Controller::gamepadDisconnected);
	connect(mBrick->gamepad(), &trikControl::GamepadInterface::connected
			, this, &Controller::gamepadConnected);

	mMailbox.reset(trikNetwork::MailboxFactory::create(configurer));
	mTelemetry.reset(new trikTelemetry::TrikTelemetry(*mBrick));
	mScriptRunner.reset(new trikScriptRunner::TrikScriptRunner(*mBrick, mMailbox.data()));
	mCommunicator.reset(new trikCommunicator::TrikCommunicator(*mScriptRunner, configurer.version()));

	mWiFi.reset(new trikWiFi::TrikWiFi("/tmp/trikwifi", "/var/run/wpa_supplicant/wlan0", this));
	connect(mWiFi.data(), &trikWiFi::TrikWiFi::connected, this, &Controller::wiFiConnected);
	connect(mWiFi.data(), &trikWiFi::TrikWiFi::disconnected, this, &Controller::wiFiDisconnected);

	connect(mCommunicator.data(), &trikCommunicator::TrikCommunicator::stopCommandReceived
			, this, &Controller::abortExecution);
	connect(mCommunicator.data(), &trikCommunicator::TrikCommunicator::connected
			, this, &Controller::updateCommunicatorStatus);
	connect(mCommunicator.data(), &trikCommunicator::TrikCommunicator::disconnected
			, this, &Controller::updateCommunicatorStatus);
	connect(mTelemetry.data(), &trikTelemetry::TrikTelemetry::connected
			, this, &Controller::updateCommunicatorStatus);
	connect(mTelemetry.data(), &trikTelemetry::TrikTelemetry::disconnected
			, this, &Controller::updateCommunicatorStatus);
	connect(mMailbox.data(), &trikNetwork::MailboxInterface::connectionStatusChanged
			, this, &Controller::mailboxStatusChanged);

	connect(mScriptRunner.data(), &trikScriptRunner::TrikScriptRunner::completed
			, this, &Controller::scriptExecutionCompleted);

	connect(mScriptRunner.data(), &trikScriptRunner::TrikScriptRunner::sendMessage, this, [](const QString &m){
		QTextStream(stdout) << m << "\n";
	});

	connect(mScriptRunner.data(), &trikScriptRunner::TrikScriptRunner::startedScript
			, this, &Controller::scriptExecutionFromFileStarted);

	connect(mScriptRunner.data(), &trikScriptRunner::TrikScriptRunner::startedDirectScript
			, this, &Controller::directScriptExecutionStarted);

\

	connect(mBrick.data(), &trikControl::BrickInterface::stopped, this, &Controller::brickStopped);

	mCommunicator->startServer(communicatorPort);
	mTelemetry->startServer(telemetryPort);

	mAutoRunner.reset(new AutoRunner(*this));

	mBrick->led()->green();
}

Controller::~Controller()
{
	mBrick->led()->orange();
}

void Controller::runFile(const QString &filePath)
{
	const QFileInfo fileInfo(filePath);
	if (fileInfo.suffix() == "qts" || fileInfo.suffix() == "js") {
		mScriptRunner->run(trikKernel::FileUtils::readFromFile(fileInfo.canonicalFilePath()), fileInfo.baseName());
	} else if (fileInfo.suffix() == "wav" || fileInfo.suffix() == "mp3") {
		mScriptRunner->run("brick.playSound(\"" + fileInfo.canonicalFilePath() + "\");", fileInfo.baseName());
	} else if (fileInfo.suffix() == "sh") {
		QProcess::startDetached("sh", {filePath});
	} else if (fileInfo.suffix() == "exe") {
		QProcess::startDetached("mono", {filePath});
	} else if (fileInfo.suffix() == "py") {
		mScriptRunner->run(trikKernel::FileUtils::readFromFile(fileInfo.canonicalFilePath()),
						   trikScriptRunner::ScriptType::PYTHON, fileInfo.baseName());
	} else if (fileInfo.isExecutable()) {
		QProcess::startDetached(filePath);
	}
}

void Controller::runScript(const QString &script)
{
	mScriptRunner->run(script);
}

void Controller::abortExecution()
{
	emit hideScriptWidgets();
	mScriptRunner->abort();

	// Now script engine will stop (after some time maybe) and send "completed" signal, which will be caught and
	// processed as if a script finished by itself.
}

trikControl::BrickInterface &Controller::brick()
{
	return *mBrick;
}

trikNetwork::MailboxInterface *Controller::mailbox()
{
	return mMailbox.data();
}

trikWiFi::TrikWiFi &Controller::wiFi()
{
	return *mWiFi;
}

bool Controller::communicatorConnectionStatus()
{
	return mTelemetry->activeConnections() > 0 && mCommunicator->activeConnections() > 0;
}

bool Controller::gamepadConnectionStatus() const
{
	if (mBrick->gamepad() != nullptr) {
		return mBrick->gamepad()->isConnected();
	} else {
		return false;
	}
}

void Controller::updateCommunicatorStatus()
{
	emit communicatorStatusChanged(communicatorConnectionStatus());
}

void Controller::scriptExecutionCompleted(const QString &error, int scriptId)
{
	if (error.isEmpty()) {
		emit hideRunningWidget(scriptId);
	} else {
		mCommunicator->sendMessage("error: " + error);
		emit showError(error, scriptId);
	}

	mBrick->reset();

	if (mMailbox) {
		mMailbox->clearQueue();
	}

	mBrick->led()->green();
}

void Controller::scriptExecutionFromFileStarted(const QString &fileName, int scriptId)
{
	emit showRunningWidget(fileName, scriptId);
}

void Controller::directScriptExecutionStarted(int scriptId)
{
	scriptExecutionFromFileStarted(tr("direct command"), scriptId);
}
<commit_msg>Delete extra lines<commit_after>/* Copyright 2013 - 2015 Yurii Litvinov and CyberTech Labs Ltd.
 *
 * 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. */

#include "controller.h"

#include <QtCore/QProcess>
#include <QtCore/QFileInfo>

#include <QtXml/QDomDocument>

#include <trikKernel/configurer.h>
#include <trikKernel/fileUtils.h>
#include <trikKernel/paths.h>
#include <trikKernel/exceptions/internalErrorException.h>
#include <trikControl/brickFactory.h>
#include <trikControl/gamepadInterface.h>
#include <trikNetwork/mailboxFactory.h>
#include <trikWiFi/trikWiFi.h>

#include "runningWidget.h"
#include "autoRunner.h"

using namespace trikGui;

const int communicatorPort = 8888;
const int telemetryPort = 9000;

Controller::Controller(const QString &configPath)
	: mBrick(trikControl::BrickFactory::create(configPath, trikKernel::Paths::mediaPath()))
{
	if (configPath.isEmpty()) {
		throw trikKernel::InternalErrorException("Config path is empty");
	}

	auto correctedConfigPath = configPath.endsWith('/') ? configPath : configPath + '/';

	trikKernel::Configurer configurer(correctedConfigPath + "system-config.xml"
			, correctedConfigPath + "model-config.xml");

	connect(mBrick->gamepad(), &trikControl::GamepadInterface::disconnected
			, this, &Controller::gamepadDisconnected);
	connect(mBrick->gamepad(), &trikControl::GamepadInterface::connected
			, this, &Controller::gamepadConnected);

	mMailbox.reset(trikNetwork::MailboxFactory::create(configurer));
	mTelemetry.reset(new trikTelemetry::TrikTelemetry(*mBrick));
	mScriptRunner.reset(new trikScriptRunner::TrikScriptRunner(*mBrick, mMailbox.data()));
	mCommunicator.reset(new trikCommunicator::TrikCommunicator(*mScriptRunner, configurer.version()));

	mWiFi.reset(new trikWiFi::TrikWiFi("/tmp/trikwifi", "/var/run/wpa_supplicant/wlan0", this));
	connect(mWiFi.data(), &trikWiFi::TrikWiFi::connected, this, &Controller::wiFiConnected);
	connect(mWiFi.data(), &trikWiFi::TrikWiFi::disconnected, this, &Controller::wiFiDisconnected);

	connect(mCommunicator.data(), &trikCommunicator::TrikCommunicator::stopCommandReceived
			, this, &Controller::abortExecution);
	connect(mCommunicator.data(), &trikCommunicator::TrikCommunicator::connected
			, this, &Controller::updateCommunicatorStatus);
	connect(mCommunicator.data(), &trikCommunicator::TrikCommunicator::disconnected
			, this, &Controller::updateCommunicatorStatus);
	connect(mTelemetry.data(), &trikTelemetry::TrikTelemetry::connected
			, this, &Controller::updateCommunicatorStatus);
	connect(mTelemetry.data(), &trikTelemetry::TrikTelemetry::disconnected
			, this, &Controller::updateCommunicatorStatus);
	connect(mMailbox.data(), &trikNetwork::MailboxInterface::connectionStatusChanged
			, this, &Controller::mailboxStatusChanged);

	connect(mScriptRunner.data(), &trikScriptRunner::TrikScriptRunner::completed
			, this, &Controller::scriptExecutionCompleted);

	connect(mScriptRunner.data(), &trikScriptRunner::TrikScriptRunner::sendMessage, this, [](const QString &m){
		QTextStream(stdout) << m << "\n";
	});

	connect(mScriptRunner.data(), &trikScriptRunner::TrikScriptRunner::startedScript
			, this, &Controller::scriptExecutionFromFileStarted);

	connect(mScriptRunner.data(), &trikScriptRunner::TrikScriptRunner::startedDirectScript
			, this, &Controller::directScriptExecutionStarted);

	connect(mBrick.data(), &trikControl::BrickInterface::stopped, this, &Controller::brickStopped);

	mCommunicator->startServer(communicatorPort);
	mTelemetry->startServer(telemetryPort);

	mAutoRunner.reset(new AutoRunner(*this));

	mBrick->led()->green();
}

Controller::~Controller()
{
	mBrick->led()->orange();
}

void Controller::runFile(const QString &filePath)
{
	const QFileInfo fileInfo(filePath);
	if (fileInfo.suffix() == "qts" || fileInfo.suffix() == "js") {
		mScriptRunner->run(trikKernel::FileUtils::readFromFile(fileInfo.canonicalFilePath()), fileInfo.baseName());
	} else if (fileInfo.suffix() == "wav" || fileInfo.suffix() == "mp3") {
		mScriptRunner->run("brick.playSound(\"" + fileInfo.canonicalFilePath() + "\");", fileInfo.baseName());
	} else if (fileInfo.suffix() == "sh") {
		QProcess::startDetached("sh", {filePath});
	} else if (fileInfo.suffix() == "exe") {
		QProcess::startDetached("mono", {filePath});
	} else if (fileInfo.suffix() == "py") {
		mScriptRunner->run(trikKernel::FileUtils::readFromFile(fileInfo.canonicalFilePath()),
						   trikScriptRunner::ScriptType::PYTHON, fileInfo.baseName());
	} else if (fileInfo.isExecutable()) {
		QProcess::startDetached(filePath);
	}
}

void Controller::runScript(const QString &script)
{
	mScriptRunner->run(script);
}

void Controller::abortExecution()
{
	emit hideScriptWidgets();
	mScriptRunner->abort();

	// Now script engine will stop (after some time maybe) and send "completed" signal, which will be caught and
	// processed as if a script finished by itself.
}

trikControl::BrickInterface &Controller::brick()
{
	return *mBrick;
}

trikNetwork::MailboxInterface *Controller::mailbox()
{
	return mMailbox.data();
}

trikWiFi::TrikWiFi &Controller::wiFi()
{
	return *mWiFi;
}

bool Controller::communicatorConnectionStatus()
{
	return mTelemetry->activeConnections() > 0 && mCommunicator->activeConnections() > 0;
}

bool Controller::gamepadConnectionStatus() const
{
	if (mBrick->gamepad() != nullptr) {
		return mBrick->gamepad()->isConnected();
	} else {
		return false;
	}
}

void Controller::updateCommunicatorStatus()
{
	emit communicatorStatusChanged(communicatorConnectionStatus());
}

void Controller::scriptExecutionCompleted(const QString &error, int scriptId)
{
	if (error.isEmpty()) {
		emit hideRunningWidget(scriptId);
	} else {
		mCommunicator->sendMessage("error: " + error);
		emit showError(error, scriptId);
	}

	mBrick->reset();

	if (mMailbox) {
		mMailbox->clearQueue();
	}

	mBrick->led()->green();
}

void Controller::scriptExecutionFromFileStarted(const QString &fileName, int scriptId)
{
	emit showRunningWidget(fileName, scriptId);
}

void Controller::directScriptExecutionStarted(int scriptId)
{
	scriptExecutionFromFileStarted(tr("direct command"), scriptId);
}
<|endoftext|>


<commit_before>/// \file
/// \ingroup tutorial_r
/// \notebook -nodraw
///
/// \macro_code
///
/// \author

using namespace ROOT::R;
void Function()
{
   auto &r = ROOT::R::TRInterface::Instance();
   r.SetVerbose(1);

   // Defining functions to be used from R
   TRFunctionImport c("c");
   TRFunctionImport list("list");
   TRFunctionImport asformula("as.formula");
   TRFunctionImport nls("nls");
   TRFunctionImport confint("confint");
   TRFunctionImport summary("summary");
   TRFunctionImport print("print");
   TRFunctionImport plot("plot");
   TRFunctionImport lines("lines");
   TRFunctionImport devnew("dev.new");
   TRFunctionImport devoff("dev.off");
   TRFunctionImport devcur("dev.cur");
   TRFunctionImport min("min");
   TRFunctionImport max("max");
   TRFunctionImport seq("seq");
   TRFunctionImport predict("predict");

   r<<"options(device='pdf')";

   // doing the procedure
   TRObject xdata = c(-2,-1.64,-1.33,-0.7,0,0.45,1.2,1.64,2.32,2.9);
   TRObject ydata = c(0.699369,0.700462,0.695354,1.03905,1.97389,2.41143,1.91091,0.919576,-0.730975,-1.42001);

   TRDataFrame data;
   data["xdata"]=xdata;
   data["ydata"]=ydata;

   // fit = nls(ydata ~ p1*cos(p2*xdata) + p2*sin(p1*xdata), start=list(p1=1,p2=0.2))
   TRObject fit = nls(asformula("ydata ~ p1*cos(p2*xdata) + p2*sin(p1*xdata)"),Label["data"]=data, Label["start"]=list(Label["p1"]=1,Label["p2"]=0.2));
   print(summary(fit));

   print(confint(fit));

   if (!gROOT->IsBatch()) {
      devnew("Fitting Regression");
      plot(xdata,ydata);

      TRObject xgrid=seq(min(xdata),max(xdata),Label["len"]=10);
      lines(xgrid,predict(fit,xgrid),Label["col"] = "green");
      devoff(Label["which"] = devcur() );
   }
}
<commit_msg>Fix tutorial to make it work as notebook<commit_after>/// \file
/// \ingroup tutorial_r
/// \notebook -nodraw
///
/// \macro_code
///
/// \author

using namespace ROOT::R;
void Function()
{
   auto &r = ROOT::R::TRInterface::Instance();
   r.SetVerbose(1);

   // Defining functions to be used from R
   TRFunctionImport c("c");
   TRFunctionImport rlist("list");
   TRFunctionImport asformula("as.formula");
   TRFunctionImport nls("nls");
   TRFunctionImport confint("confint");
   TRFunctionImport summary("summary");
   TRFunctionImport print("print");
   TRFunctionImport plot("plot");
   TRFunctionImport lines("lines");
   TRFunctionImport devnew("dev.new");
   TRFunctionImport devoff("dev.off");
   TRFunctionImport devcur("dev.cur");
   TRFunctionImport rmin("min");
   TRFunctionImport rmax("max");
   TRFunctionImport seq("seq");
   TRFunctionImport predict("predict");

   r<<"options(device='pdf')";

   // doing the procedure
   TRObject xdata = c(-2,-1.64,-1.33,-0.7,0,0.45,1.2,1.64,2.32,2.9);
   TRObject ydata = c(0.699369,0.700462,0.695354,1.03905,1.97389,2.41143,1.91091,0.919576,-0.730975,-1.42001);

   TRDataFrame data;
   data["xdata"]=xdata;
   data["ydata"]=ydata;

   // fit = nls(ydata ~ p1*cos(p2*xdata) + p2*sin(p1*xdata), start=list(p1=1,p2=0.2))
   TRObject fit = nls(asformula("ydata ~ p1*cos(p2*xdata) + p2*sin(p1*xdata)"),Label["data"]=data, Label["start"]=rlist(Label["p1"]=1,Label["p2"]=0.2));
   print(summary(fit));

   print(confint(fit));

   if (!gROOT->IsBatch()) {
      devnew("Fitting Regression");
      plot(xdata,ydata);

      TRObject xgrid=seq(rmin(xdata),rmax(xdata),Label["len"]=10);
      lines(xgrid,predict(fit,xgrid),Label["col"] = "green");
      devoff(Label["which"] = devcur() );
   }
}
<|endoftext|>


<commit_before>/*
 * Telefónica Digital - Product Development and Innovation
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Copyright (c) Telefónica Investigación y Desarrollo S.A.U.
 * All rights reserved.
 */
/* ****************************************************************************
 *
 * FILE            readFile_test.cpp
 *
 * AUTHOR          Javier Lois
 *
 * DATE            January 2012
 *
 * DESCRIPTION
 *
 * Unit testing of the ReadFile class in the engine library
 *
 *
 * Telefonica Digital - Product Development and Innovation
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Copyright (c) Telefonica Investigacion y Desarrollo S.A.U.
 * All rights reserved.
 */
#include <stdlib.h>  // for MAX_PATH

#include <string>

#include "gtest/gtest.h"

#include "engine/ReadFile.h"

// -----------------------------------------------------------------------------
// openTest - test to open a file that doesn't exist and another one that does
//
TEST(engine_ReadFile, openTest) {
  engine::ReadFile file1("badfile");

  EXPECT_TRUE(file1.IsValid() == false);

  engine::ReadFile file2("test_data/testdata.txt");
  EXPECT_TRUE(file2.IsValid());
}

// -----------------------------------------------------------------------------
// readTest -
//
TEST(readfileTest, readTest) {
  engine::ReadFile file("test_data/testdata.txt");

  EXPECT_TRUE(file.IsValid());

  if (file.IsValid()) {
    char data[10];
    file.Read(data, 5);
    data[5] = '\0';
    EXPECT_EQ(strcmp(data, "01234"), 0);
  }
}

// -----------------------------------------------------------------------------
// seekTest - ok and not-ok seeks tested
//
TEST(engine_ReadFile, seekTest) {
  engine::ReadFile file("test_data/testdata.txt");

  EXPECT_TRUE(file.IsValid());

  if (file.IsValid()) {
    char data[10];
    int  x;

    file.Seek(2);
    file.Read(data, 5);
    data[5] = '\0';
    EXPECT_EQ(strcmp(data, "23456"), 0);

    x = file.Read(data, 50000);
    EXPECT_EQ(x, 1);

    x = file.Seek(-2);
    EXPECT_EQ(2, x);
  }

  engine::ReadFile fileBad("badfile");
  EXPECT_EQ(fileBad.Seek(2), 1) << "Trying to seek a bad file should return 1";
}

// -----------------------------------------------------------------------------
// closeTest - testing validity and closing of ReadFile
//
TEST(engine_ReadFile, closeTest) {
  engine::ReadFile file1("badfile");

  EXPECT_TRUE(file1.IsValid() == false);

  engine::ReadFile file2("test_data/testdata.txt");
  EXPECT_TRUE(file2.IsValid());

  if (file2.IsValid()) {
    file2.Close();
    EXPECT_FALSE(file2.IsValid());
  }
}

// -----------------------------------------------------------------------------
// seekSamePositionTest - test a seek to the same position
//
TEST(engine_ReadFile, seekSamePositionTest) {
  engine::ReadFile  file("test_data/testdata.txt");
  int               pos;

  EXPECT_TRUE(file.IsValid());

  pos = file.Seek(2);
  EXPECT_EQ(pos, 0);
  pos = file.Seek(2);
  EXPECT_EQ(pos, 0);
}

// -----------------------------------------------------------------------------
// misc - test offset and a read of zero bytes
//
TEST(engine_ReadFile, misc) {
  engine::ReadFile  file("test_data/testdata.txt");

  std::string name = file.file_name();
  EXPECT_STREQ(name.c_str(), "test_data/testdata.txt");

  size_t offset = file.offset();
  EXPECT_EQ(0, offset);

  char buf[3];
  int s = file.Read(buf, 0);
  EXPECT_EQ(0, s);
}
<commit_msg>Disabling engine_ReadFile_seekTest<commit_after>/*
 * Telefónica Digital - Product Development and Innovation
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Copyright (c) Telefónica Investigación y Desarrollo S.A.U.
 * All rights reserved.
 */
/* ****************************************************************************
 *
 * FILE            readFile_test.cpp
 *
 * AUTHOR          Javier Lois
 *
 * DATE            January 2012
 *
 * DESCRIPTION
 *
 * Unit testing of the ReadFile class in the engine library
 *
 *
 * Telefonica Digital - Product Development and Innovation
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Copyright (c) Telefonica Investigacion y Desarrollo S.A.U.
 * All rights reserved.
 */
#include <stdlib.h>  // for MAX_PATH

#include <string>

#include "gtest/gtest.h"

#include "engine/ReadFile.h"

// -----------------------------------------------------------------------------
// openTest - test to open a file that doesn't exist and another one that does
//
TEST(engine_ReadFile, openTest) {
  engine::ReadFile file1("badfile");

  EXPECT_TRUE(file1.IsValid() == false);

  engine::ReadFile file2("test_data/testdata.txt");
  EXPECT_TRUE(file2.IsValid());
}

// -----------------------------------------------------------------------------
// readTest -
//
TEST(readfileTest, readTest) {
  engine::ReadFile file("test_data/testdata.txt");

  EXPECT_TRUE(file.IsValid());

  if (file.IsValid()) {
    char data[10];
    file.Read(data, 5);
    data[5] = '\0';
    EXPECT_EQ(strcmp(data, "01234"), 0);
  }
}

// -----------------------------------------------------------------------------
// seekTest - ok and not-ok seeks tested
//

TEST(engine_ReadFile, DISABLED_seekTest) {
  engine::ReadFile file("test_data/testdata.txt");

  EXPECT_TRUE(file.IsValid());

  if (file.IsValid()) {
    char data[10];
    int  x;

    file.Seek(2);
    file.Read(data, 5);
    data[5] = '\0';
    EXPECT_EQ(strcmp(data, "23456"), 0);

    x = file.Read(data, 50000);
    EXPECT_EQ(x, 1);

    x = file.Seek(-2);
    EXPECT_EQ(2, x);
  }

  engine::ReadFile fileBad("badfile");
  EXPECT_EQ(fileBad.Seek(2), 1) << "Trying to seek a bad file should return 1";
}

// -----------------------------------------------------------------------------
// closeTest - testing validity and closing of ReadFile
//
TEST(engine_ReadFile, closeTest) {
  engine::ReadFile file1("badfile");

  EXPECT_TRUE(file1.IsValid() == false);

  engine::ReadFile file2("test_data/testdata.txt");
  EXPECT_TRUE(file2.IsValid());

  if (file2.IsValid()) {
    file2.Close();
    EXPECT_FALSE(file2.IsValid());
  }
}

// -----------------------------------------------------------------------------
// seekSamePositionTest - test a seek to the same position
//
TEST(engine_ReadFile, seekSamePositionTest) {
  engine::ReadFile  file("test_data/testdata.txt");
  int               pos;

  EXPECT_TRUE(file.IsValid());

  pos = file.Seek(2);
  EXPECT_EQ(pos, 0);
  pos = file.Seek(2);
  EXPECT_EQ(pos, 0);
}

// -----------------------------------------------------------------------------
// misc - test offset and a read of zero bytes
//
TEST(engine_ReadFile, misc) {
  engine::ReadFile  file("test_data/testdata.txt");

  std::string name = file.file_name();
  EXPECT_STREQ(name.c_str(), "test_data/testdata.txt");

  size_t offset = file.offset();
  EXPECT_EQ(0, offset);

  char buf[3];
  int s = file.Read(buf, 0);
  EXPECT_EQ(0, s);
}
<|endoftext|>