<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: String.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 06:13:22 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _CONNECTIVITY_JAVA_LANG_STRING_HXX_
#include "java/lang/String.hxx"
#endif
#ifndef _CONNECTIVITY_JAVA_TOOLS_HXX_
#include "java/tools.hxx"
#endif
using namespace connectivity;
//**************************************************************
//************ Class: java.lang.String
//**************************************************************

jclass java_lang_String::theClass = 0;

java_lang_String::~java_lang_String()
{}

jclass java_lang_String::getMyClass()
{
    // die Klasse muss nur einmal geholt werden, daher statisch
    if( !theClass ){
        SDBThreadAttach t;
        if( !t.pEnv ) return (jclass)NULL;
        jclass tempClass = t.pEnv->FindClass("java/lang/String");
        OSL_ENSURE(tempClass,"Java : FindClass nicht erfolgreich!");
        jclass globClass = (jclass)t.pEnv->NewGlobalRef( tempClass );
        t.pEnv->DeleteLocalRef( tempClass );
        saveClassRef( globClass );
    }
    return theClass;
}

//--------------------------------------------------------------------------
void java_lang_String::saveClassRef( jclass pClass )
{
    if( pClass==NULL  )
        return;
    // der uebergebe Klassen-Handle ist schon global, daher einfach speichern
    theClass = pClass;
}
//--------------------------------------------------------------------------
java_lang_String::java_lang_String( const ::rtl::OUString& _par0 ): java_lang_Object( NULL, (jobject)NULL )
{
    SDBThreadAttach t;
    if( !t.pEnv )
        return;
    jvalue args[1];
    // Parameter konvertieren
    args[0].l = convertwchar_tToJavaString(t.pEnv,_par0);
    // Java-Call fuer den Konstruktor absetzen
    // temporaere Variable initialisieren
    static char * cSignature = "(Ljava/lang/String;)V";
    jobject tempObj;
    static jmethodID mID = NULL;
    if ( !mID  )
        mID  = t.pEnv->GetMethodID( getMyClass(), "<init>", cSignature );OSL_ENSURE(mID,"Unknown method id!");
    tempObj = t.pEnv->NewObjectA( getMyClass(), mID, args );
    saveRef( t.pEnv, tempObj );
    t.pEnv->DeleteLocalRef( tempObj );
    t.pEnv->DeleteLocalRef((jstring)args[0].l);
}
//--------------------------------------------------------------------------
java_lang_String::operator ::rtl::OUString()
{
    SDBThreadAttach t;
    if(!t.pEnv)
        return ::rtl::OUString();
    return JavaString2String(t.pEnv,(jstring)object);
}

<commit_msg>INTEGRATION: CWS warnings01 (1.6.30); FILE MERGED 2005/11/21 10:07:50 fs 1.6.30.1: #i57457# warning-free code on unx*<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: String.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 01:36:50 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _CONNECTIVITY_JAVA_LANG_STRING_HXX_
#include "java/lang/String.hxx"
#endif
#ifndef _CONNECTIVITY_JAVA_TOOLS_HXX_
#include "java/tools.hxx"
#endif
using namespace connectivity;
//**************************************************************
//************ Class: java.lang.String
//**************************************************************

jclass java_lang_String::theClass = 0;

java_lang_String::~java_lang_String()
{}

jclass java_lang_String::getMyClass()
{
    // die Klasse muss nur einmal geholt werden, daher statisch
    if( !theClass ){
        SDBThreadAttach t;
        if( !t.pEnv ) return (jclass)NULL;
        jclass tempClass = t.pEnv->FindClass("java/lang/String");
        OSL_ENSURE(tempClass,"Java : FindClass nicht erfolgreich!");
        jclass globClass = (jclass)t.pEnv->NewGlobalRef( tempClass );
        t.pEnv->DeleteLocalRef( tempClass );
        saveClassRef( globClass );
    }
    return theClass;
}

//--------------------------------------------------------------------------
void java_lang_String::saveClassRef( jclass pClass )
{
    if( pClass==NULL  )
        return;
    // der uebergebe Klassen-Handle ist schon global, daher einfach speichern
    theClass = pClass;
}
//--------------------------------------------------------------------------
java_lang_String::java_lang_String( const ::rtl::OUString& _par0 ): java_lang_Object( NULL, (jobject)NULL )
{
    SDBThreadAttach t;
    if( !t.pEnv )
        return;
    jvalue args[1];
    // Parameter konvertieren
    args[0].l = convertwchar_tToJavaString(t.pEnv,_par0);
    // Java-Call fuer den Konstruktor absetzen
    // temporaere Variable initialisieren
    static const char * cSignature = "(Ljava/lang/String;)V";
    jobject tempObj;
    static jmethodID mID = NULL;
    if ( !mID  )
        mID  = t.pEnv->GetMethodID( getMyClass(), "<init>", cSignature );OSL_ENSURE(mID,"Unknown method id!");
    tempObj = t.pEnv->NewObjectA( getMyClass(), mID, args );
    saveRef( t.pEnv, tempObj );
    t.pEnv->DeleteLocalRef( tempObj );
    t.pEnv->DeleteLocalRef((jstring)args[0].l);
}
//--------------------------------------------------------------------------
java_lang_String::operator ::rtl::OUString()
{
    SDBThreadAttach t;
    if(!t.pEnv)
        return ::rtl::OUString();
    return JavaString2String(t.pEnv,(jstring)object);
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: TSkipDeletedSet.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2004-03-02 12:35:45 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an AS IS basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef CONNECTIVITY_SKIPDELETEDSSET_HXX
#define CONNECTIVITY_SKIPDELETEDSSET_HXX

#ifndef CONNECTIVITY_TRESULTSETHELPER_HXX
#include "TResultSetHelper.hxx"
#endif

#ifndef _RTL_ALLOC_H_
#include <rtl/alloc.h>
#endif
#include <map>
#include <vector>

namespace connectivity
{
    /**
        the class OSkipDeletedSet supports a general method to skip deleted rows
    */
    class OSkipDeletedSet
    {
        typedef ::std::map<sal_Int32,sal_Int32> TInt2IntMap;
        TInt2IntMap                             m_aBookmarks;         // map from postion to logical position
        ::std::vector<TInt2IntMap::iterator>    m_aBookmarksPositions;// vector of iterators to position map, the order is the logical position
        IResultSetHelper*                       m_pHelper;            // used for moving in the resultset

        sal_Bool    moveAbsolute(sal_Int32 _nOffset,sal_Bool _bRetrieveData);
    public:
        OSkipDeletedSet(IResultSetHelper* _pHelper);
        ~OSkipDeletedSet();

        inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
            { return ::rtl_allocateMemory( nSize ); }
        inline static void * SAL_CALL operator new( size_t nSize,void* _pHint ) SAL_THROW( () )
            { return _pHint; }
        inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
            { ::rtl_freeMemory( pMem ); }
        inline static void SAL_CALL operator delete( void * pMem,void* _pHint ) SAL_THROW( () )
            {  }

        /**
            skipDeleted moves the resultset to the position defined by the parameters
            it garantees that the row isn't deleted
                @param
                    IResultSetHelper::Movement  _eCursorPosition        in which direction the resultset should be moved
                    sal_Int32                   _nOffset                the position relativ to the movement
                    sal_Bool                    _bRetrieveData          is true when the current row should be filled which data
                @return
                    true when the movement was successful otherwise false
        */
        sal_Bool    skipDeleted(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, sal_Bool _bRetrieveData);
        /**
            clear the map and the vector used in this class
        */
        void        clear();
        /**
            getMappedPosition returns the mapped position of a logical position
            @param
                sal_Int32 _nPos the logical position

            @return the mapped position
        */
        sal_Int32   getMappedPosition(sal_Int32 _nPos) const;
        /**
            insertNewPosition adds a new position to the map
            @param
                sal_Int32 _nPos the logical position
        */
        void        insertNewPosition(sal_Int32 _nPos);
        /**
            deletePosition deletes this position from the map and decrement all following positions
            @param
                sal_Int32 _nPos the logical position
        */
        void        deletePosition(sal_Int32 _nPos);
        /**
            getLastPosition returns the last position
            @return the last position
        */
        sal_Int32   getLastPosition() const { return m_aBookmarksPositions.size(); }
    };
}
#endif // CONNECTIVITY_SKIPDELETEDSSET_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.4.162); FILE MERGED 2005/09/05 17:24:50 rt 1.4.162.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: TSkipDeletedSet.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 06:40:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef CONNECTIVITY_SKIPDELETEDSSET_HXX
#define CONNECTIVITY_SKIPDELETEDSSET_HXX

#ifndef CONNECTIVITY_TRESULTSETHELPER_HXX
#include "TResultSetHelper.hxx"
#endif

#ifndef _RTL_ALLOC_H_
#include <rtl/alloc.h>
#endif
#include <map>
#include <vector>

namespace connectivity
{
    /**
        the class OSkipDeletedSet supports a general method to skip deleted rows
    */
    class OSkipDeletedSet
    {
        typedef ::std::map<sal_Int32,sal_Int32> TInt2IntMap;
        TInt2IntMap                             m_aBookmarks;         // map from postion to logical position
        ::std::vector<TInt2IntMap::iterator>    m_aBookmarksPositions;// vector of iterators to position map, the order is the logical position
        IResultSetHelper*                       m_pHelper;            // used for moving in the resultset

        sal_Bool    moveAbsolute(sal_Int32 _nOffset,sal_Bool _bRetrieveData);
    public:
        OSkipDeletedSet(IResultSetHelper* _pHelper);
        ~OSkipDeletedSet();

        inline static void * SAL_CALL operator new( size_t nSize ) SAL_THROW( () )
            { return ::rtl_allocateMemory( nSize ); }
        inline static void * SAL_CALL operator new( size_t nSize,void* _pHint ) SAL_THROW( () )
            { return _pHint; }
        inline static void SAL_CALL operator delete( void * pMem ) SAL_THROW( () )
            { ::rtl_freeMemory( pMem ); }
        inline static void SAL_CALL operator delete( void * pMem,void* _pHint ) SAL_THROW( () )
            {  }

        /**
            skipDeleted moves the resultset to the position defined by the parameters
            it garantees that the row isn't deleted
                @param
                    IResultSetHelper::Movement  _eCursorPosition        in which direction the resultset should be moved
                    sal_Int32                   _nOffset                the position relativ to the movement
                    sal_Bool                    _bRetrieveData          is true when the current row should be filled which data
                @return
                    true when the movement was successful otherwise false
        */
        sal_Bool    skipDeleted(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, sal_Bool _bRetrieveData);
        /**
            clear the map and the vector used in this class
        */
        void        clear();
        /**
            getMappedPosition returns the mapped position of a logical position
            @param
                sal_Int32 _nPos the logical position

            @return the mapped position
        */
        sal_Int32   getMappedPosition(sal_Int32 _nPos) const;
        /**
            insertNewPosition adds a new position to the map
            @param
                sal_Int32 _nPos the logical position
        */
        void        insertNewPosition(sal_Int32 _nPos);
        /**
            deletePosition deletes this position from the map and decrement all following positions
            @param
                sal_Int32 _nPos the logical position
        */
        void        deletePosition(sal_Int32 _nPos);
        /**
            getLastPosition returns the last position
            @return the last position
        */
        sal_Int32   getLastPosition() const { return m_aBookmarksPositions.size(); }
    };
}
#endif // CONNECTIVITY_SKIPDELETEDSSET_HXX

<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#ifndef PCL_SEARCH_IMPL_ORGANIZED_NEIGHBOR_SEARCH_H_
#define PCL_SEARCH_IMPL_ORGANIZED_NEIGHBOR_SEARCH_H_

#include "pcl/search/organized.h"
#include <pcl/common/eigen.h>
#include "pcl/common/time.h"
#include <Eigen/Eigenvalues>
//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> int
pcl::search::OrganizedNeighbor<PointT>::radiusSearch (int                 index,
                                                       const double        radius,
                                                       std::vector<int>    &k_indices,
                                                       std::vector<float>  &k_sqr_distances,
                                                       unsigned int        max_nn) const
{
  const PointT& searchPoint = input_->points [index];
  return (radiusSearch (searchPoint, radius, k_indices, k_sqr_distances, max_nn));
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> int
pcl::search::OrganizedNeighbor<PointT>::radiusSearch (const               PointT &p_q,
                                                       const double        radius,
                                                       std::vector<int>    &k_indices,
                                                       std::vector<float>  &k_sqr_distances,
                                                       unsigned int        max_nn) const
{
  if (projection_matrix_.coeffRef (0) == 0)
  {
    PCL_ERROR ("[pcl::%s::radiusSearch] Invalid projection matrix. Probably input dataset was not organized!\n", getName ().c_str ());
    return (0);
  }

  // NAN test
  if (!pcl_isfinite (p_q.x) || !pcl_isfinite (p_q.y) || !pcl_isfinite (p_q.z))
    return (0);

  // search window
  unsigned left, right, top, bottom;
  //unsigned x, y, idx;
  float squared_distance, squared_radius;

  k_indices.clear ();
  k_sqr_distances.clear ();

  squared_radius = radius * radius;

  this->getProjectedRadiusSearchBox (p_q, squared_radius, left, right, top, bottom);

  // iterate over search box
  if (max_nn == 0 || max_nn >= (unsigned int)input_->points.size ())
    max_nn = input_->points.size ();

  k_indices.reserve (max_nn);
  k_sqr_distances.reserve (max_nn);

  unsigned yEnd  = (bottom + 1) * input_->width + right + 1;
  register unsigned idx  = top * input_->width + left;
  unsigned skip = input_->width - right + left - 1;
  unsigned xEnd = idx - left + right + 1;

  for (; xEnd != yEnd; idx += skip, xEnd += input_->width)
  {
    for (; idx < xEnd; ++idx)
    {
      squared_distance = (input_->points[idx].getVector3fMap () - p_q.getVector3fMap ()).squaredNorm ();
      if (squared_distance <= squared_radius)
      {
        k_indices.push_back (idx);
        k_sqr_distances.push_back (squared_distance);
        // already done ?
        if (k_indices.size () == max_nn)
          return max_nn;
      }
    }
  }
  return (k_indices.size ());
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> int
pcl::search::OrganizedNeighbor<PointT>::nearestKSearch (const pcl::PointCloud<PointT> &cloud,
                                                        int                           index,
                                                        int                           k,
                                                        std::vector<int>              &k_indices,
                                                        std::vector<float>            &k_sqr_distances) const
{
  return (nearestKSearch (index, k, k_indices, k_sqr_distances));
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> int
pcl::search::OrganizedNeighbor<PointT>::nearestKSearch (int index,
                                                        int k,
                                                        std::vector<int> &k_indices,
                                                        std::vector<float> &k_distances) const
{
  PCL_ERROR ("[pcl::search::OrganizedNeighbor::nearestKSearch] Method not implemented!\n");
  return (0);
}

////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> void
pcl::search::OrganizedNeighbor<PointT>::getProjectedRadiusSearchBox (const PointT& point,
                                                                      float squared_radius,
                                                                      unsigned &minX,
                                                                      unsigned &maxX,
                                                                      unsigned &minY,
                                                                      unsigned &maxY) const
{
  Eigen::Vector3f q = KR_ * point.getVector3fMap () + projection_matrix_.block <3, 1> (0, 3);

  float a = squared_radius * KR_KRT_.coeff (8) - q [2] * q [2];
  float b = squared_radius * KR_KRT_.coeff (7) - q [1] * q [2];
  float c = squared_radius * KR_KRT_.coeff (4) - q [1] * q [1];

  // a and c are multiplied by two already => - 4ac -> - ac
  float det = b * b - a * c;
  if (det < 0)
  {
    minY = 0;
    maxY = input_->height - 1;
  }
  else
  {
    minY = (unsigned) std::max (0, (int) floor ((b + sqrt (det)) / a));
    maxY = (unsigned) std::min ((int) input_->height - 1, (int) ceil ((b - sqrt (det)) / a));
  }

  b = squared_radius * KR_KRT_.coeff (6) - q [0] * q [2];
  c = squared_radius * KR_KRT_.coeff (0) - q [0] * q [0];

  det = b * b - a * c;
  if (det < 0)
  {
    minX = 0;
    maxX = input_->width - 1;
  }
  else
  {
    minX = (unsigned) std::max (0, (int) floor ((b + sqrt (det)) / a));
    maxX = (unsigned) std::min ((int)input_->width - 1, (int) ceil ((b - sqrt (det)) / a));
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> template <typename MatrixType> void
pcl::search::OrganizedNeighbor<PointT>::makeSymmetric (MatrixType& matrix, bool use_upper_triangular) const
{
  if (use_upper_triangular)
  {
    matrix.coeffRef (4) = matrix.coeff (1);
    matrix.coeffRef (8) = matrix.coeff (2);
    matrix.coeffRef (9) = matrix.coeff (6);
    matrix.coeffRef (12) = matrix.coeff (3);
    matrix.coeffRef (13) = matrix.coeff (7);
    matrix.coeffRef (14) = matrix.coeff (11);
  }
  else
  {
    matrix.coeffRef (1) = matrix.coeff (4);
    matrix.coeffRef (2) = matrix.coeff (8);
    matrix.coeffRef (6) = matrix.coeff (9);
    matrix.coeffRef (3) = matrix.coeff (12);
    matrix.coeffRef (7) = matrix.coeff (13);
    matrix.coeffRef (11) = matrix.coeff (14);
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> void
pcl::search::OrganizedNeighbor<PointT>::estimateProjectionMatrix ()
{
  // internally we calculate with double but store the result into float matrices.
  typedef double Scalar;
  projection_matrix_.setZero ();
  if (input_->height == 1 || input_->width == 1)
  {
    PCL_ERROR ("[pcl::%s::estimateProjectionMatrix] Input dataset is not organized!\n", getName ().c_str ());
    return;
  }

  // we just want to use every 16th column and row -> skip = 2^4
  const unsigned int skip = input_->width >> 4;
  Eigen::Matrix<Scalar, 4, 4> A = Eigen::Matrix<Scalar, 4, 4>::Zero ();
  Eigen::Matrix<Scalar, 4, 4> B = Eigen::Matrix<Scalar, 4, 4>::Zero ();
  Eigen::Matrix<Scalar, 4, 4> C = Eigen::Matrix<Scalar, 4, 4>::Zero ();
  Eigen::Matrix<Scalar, 4, 4> D = Eigen::Matrix<Scalar, 4, 4>::Zero ();

  for (unsigned yIdx = 0, idx = 0; yIdx < input_->height; yIdx += skip, idx += input_->width * (skip-1))
  {
    for (unsigned xIdx = 0; xIdx < input_->width; xIdx += skip, idx += skip)
    {
      const PointT& point = input_->points[idx];
      if (isFinite (point))
      {
        Scalar xx = point.x * point.x;
        Scalar xy = point.x * point.y;
        Scalar xz = point.x * point.z;
        Scalar yy = point.y * point.y;
        Scalar yz = point.y * point.z;
        Scalar zz = point.z * point.z;
        Scalar xx_yy = xIdx * xIdx + yIdx * yIdx;

        A.coeffRef (0) += xx;
        A.coeffRef (1) += xy;
        A.coeffRef (2) += xz;
        A.coeffRef (3) += point.x;

        A.coeffRef (5) += yy;
        A.coeffRef (6) += yz;
        A.coeffRef (7) += point.y;

        A.coeffRef (10) += zz;
        A.coeffRef (11) += point.z;
        A.coeffRef (15) += 1.0;

        B.coeffRef (0) -= xx * xIdx;
        B.coeffRef (1) -= xy * xIdx;
        B.coeffRef (2) -= xz * xIdx;
        B.coeffRef (3) -= point.x * xIdx;

        B.coeffRef (5) -= yy * xIdx;
        B.coeffRef (6) -= yz * xIdx;
        B.coeffRef (7) -= point.y * xIdx;

        B.coeffRef (10) -= zz * xIdx;
        B.coeffRef (11) -= point.z * xIdx;

        B.coeffRef (15) -= xIdx;

        C.coeffRef (0) -= xx * yIdx;
        C.coeffRef (1) -= xy * yIdx;
        C.coeffRef (2) -= xz * yIdx;
        C.coeffRef (3) -= point.x * yIdx;

        C.coeffRef (5) -= yy * yIdx;
        C.coeffRef (6) -= yz * yIdx;
        C.coeffRef (7) -= point.y * yIdx;

        C.coeffRef (10) -= zz * yIdx;
        C.coeffRef (11) -= point.z * yIdx;

        C.coeffRef (15) -= yIdx;

        D.coeffRef (0) += xx * xx_yy;
        D.coeffRef (1) += xy * xx_yy;
        D.coeffRef (2) += xz * xx_yy;
        D.coeffRef (3) += point.x * xx_yy;

        D.coeffRef (5) += yy * xx_yy;
        D.coeffRef (6) += yz * xx_yy;
        D.coeffRef (7) += point.y * xx_yy;

        D.coeffRef (10) += zz * xx_yy;
        D.coeffRef (11) += point.z * xx_yy;

        D.coeffRef (15) += xx_yy;
      }
    }
  }

  makeSymmetric(A);
  makeSymmetric(B);
  makeSymmetric(C);
  makeSymmetric(D);

  Eigen::Matrix<Scalar, 12, 12> X = Eigen::Matrix<Scalar, 12, 12>::Zero ();
  X.topLeftCorner<4,4> () = A;
  X.block<4,4> (0, 8) = B;
  X.block<4,4> (8, 0) = B;
  X.block<4,4> (4, 4) = A;
  X.block<4,4> (4, 8) = C;
  X.block<4,4> (8, 4) = C;
  X.block<4,4> (8, 8) = D;

  Eigen::SelfAdjointEigenSolver<Eigen::Matrix<Scalar, 12, 12> > ei_symm(X);
  Eigen::Matrix<Scalar, 12, 12> eigen_vectors = ei_symm.eigenvectors();

  // check whether the residual MSE is low. If its high, the cloud was not captured from a projective device.
  Eigen::Matrix<Scalar, 1, 1> residual_sqr = eigen_vectors.col (0).transpose () * X *  eigen_vectors.col (0);
  if ( residual_sqr.coeff (0) > eps_ * A.coeff (15))
  {
    PCL_ERROR ("[pcl::%s::radiusSearch] Input dataset is not from a projective device!\n", getName ().c_str ());
    return;
  }

  projection_matrix_.coeffRef (0) = eigen_vectors.coeff (0);
  projection_matrix_.coeffRef (1) = eigen_vectors.coeff (12);
  projection_matrix_.coeffRef (2) = eigen_vectors.coeff (24);
  projection_matrix_.coeffRef (3) = eigen_vectors.coeff (36);
  projection_matrix_.coeffRef (4) = eigen_vectors.coeff (48);
  projection_matrix_.coeffRef (5) = eigen_vectors.coeff (60);
  projection_matrix_.coeffRef (6) = eigen_vectors.coeff (72);
  projection_matrix_.coeffRef (7) = eigen_vectors.coeff (84);
  projection_matrix_.coeffRef (8) = eigen_vectors.coeff (96);
  projection_matrix_.coeffRef (9) = eigen_vectors.coeff (108);
  projection_matrix_.coeffRef (10) = eigen_vectors.coeff (120);
  projection_matrix_.coeffRef (11) = eigen_vectors.coeff (132);

  if (projection_matrix_.coeff (0) < 0)
    projection_matrix_ *= -1.0;

  // get left 3x3 sub matrix, which contains K * R, with K = camera matrix = [[fx s cx] [0 fy cy] [0 0 1]]
  // and R being the rotation matrix
  KR_ = projection_matrix_.topLeftCorner <3, 3> ();

  // precalculate KR * KR^T needed by calculations during nn-search
  KR_KRT_ = KR_ * KR_.transpose ();
}

#define PCL_INSTANTIATE_OrganizedNeighbor(T) template class PCL_EXPORTS pcl::search::OrganizedNeighbor<T>;

#endif
<commit_msg>small bugfix in organized neighbor search<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#ifndef PCL_SEARCH_IMPL_ORGANIZED_NEIGHBOR_SEARCH_H_
#define PCL_SEARCH_IMPL_ORGANIZED_NEIGHBOR_SEARCH_H_

#include "pcl/search/organized.h"
#include <pcl/common/eigen.h>
#include "pcl/common/time.h"
#include <Eigen/Eigenvalues>
//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> int
pcl::search::OrganizedNeighbor<PointT>::radiusSearch (int                 index,
                                                       const double        radius,
                                                       std::vector<int>    &k_indices,
                                                       std::vector<float>  &k_sqr_distances,
                                                       unsigned int        max_nn) const
{
  const PointT& searchPoint = input_->points [index];
  return (radiusSearch (searchPoint, radius, k_indices, k_sqr_distances, max_nn));
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> int
pcl::search::OrganizedNeighbor<PointT>::radiusSearch (const               PointT &p_q,
                                                       const double        radius,
                                                       std::vector<int>    &k_indices,
                                                       std::vector<float>  &k_sqr_distances,
                                                       unsigned int        max_nn) const
{
  if (projection_matrix_.coeffRef (0) == 0)
  {
    PCL_ERROR ("[pcl::%s::radiusSearch] Invalid projection matrix. Probably input dataset was not organized!\n", getName ().c_str ());
    return (0);
  }

  // NAN test
  if (!pcl_isfinite (p_q.x) || !pcl_isfinite (p_q.y) || !pcl_isfinite (p_q.z))
    return (0);

  // search window
  unsigned left, right, top, bottom;
  //unsigned x, y, idx;
  float squared_distance, squared_radius;

  k_indices.clear ();
  k_sqr_distances.clear ();

  squared_radius = radius * radius;

  this->getProjectedRadiusSearchBox (p_q, squared_radius, left, right, top, bottom);

  // iterate over search box
  if (max_nn == 0 || max_nn >= (unsigned int)input_->points.size ())
    max_nn = input_->points.size ();

  k_indices.reserve (max_nn);
  k_sqr_distances.reserve (max_nn);

  unsigned yEnd  = (bottom + 1) * input_->width + right + 1;
  register unsigned idx  = top * input_->width + left;
  unsigned skip = input_->width - right + left - 1;
  unsigned xEnd = idx - left + right + 1;

  for (; xEnd != yEnd; idx += skip, xEnd += input_->width)
  {
    for (; idx < xEnd; ++idx)
    {
      squared_distance = (input_->points[idx].getVector3fMap () - p_q.getVector3fMap ()).squaredNorm ();
      if (squared_distance <= squared_radius)
      {
        k_indices.push_back (idx);
        k_sqr_distances.push_back (squared_distance);
        // already done ?
        if (k_indices.size () == max_nn)
          return max_nn;
      }
    }
  }
  return (k_indices.size ());
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> int
pcl::search::OrganizedNeighbor<PointT>::nearestKSearch (const pcl::PointCloud<PointT> &cloud,
                                                        int                           index,
                                                        int                           k,
                                                        std::vector<int>              &k_indices,
                                                        std::vector<float>            &k_sqr_distances) const
{
  return (nearestKSearch (index, k, k_indices, k_sqr_distances));
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> int
pcl::search::OrganizedNeighbor<PointT>::nearestKSearch (int index,
                                                        int k,
                                                        std::vector<int> &k_indices,
                                                        std::vector<float> &k_distances) const
{
  PCL_ERROR ("[pcl::search::OrganizedNeighbor::nearestKSearch] Method not implemented!\n");
  return (0);
}

////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> void
pcl::search::OrganizedNeighbor<PointT>::getProjectedRadiusSearchBox (const PointT& point,
                                                                      float squared_radius,
                                                                      unsigned &minX,
                                                                      unsigned &maxX,
                                                                      unsigned &minY,
                                                                      unsigned &maxY) const
{
  Eigen::Vector3f q = KR_ * point.getVector3fMap () + projection_matrix_.block <3, 1> (0, 3);

  float a = squared_radius * KR_KRT_.coeff (8) - q [2] * q [2];
  float b = squared_radius * KR_KRT_.coeff (7) - q [1] * q [2];
  float c = squared_radius * KR_KRT_.coeff (4) - q [1] * q [1];
  int min, max;
  // a and c are multiplied by two already => - 4ac -> - ac
  float det = b * b - a * c;
  if (det < 0)
  {
    minY = 0;
    maxY = input_->height - 1;
  }
  else
  {
    min = std::min ((int) floor ((b - sqrt (det)) / a), (int) floor ((b + sqrt (det)) / a));
    max = std::max ((int) ceil ((b - sqrt (det)) / a), (int) ceil ((b + sqrt (det)) / a));
    minY = (unsigned) std::min ((int) input_->height - 1, std::max (0, min));
    maxY = (unsigned) std::max (std::min ((int) input_->height - 1, max), 0);
  }

  b = squared_radius * KR_KRT_.coeff (6) - q [0] * q [2];
  c = squared_radius * KR_KRT_.coeff (0) - q [0] * q [0];

  det = b * b - a * c;
  if (det < 0)
  {
    minX = 0;
    maxX = input_->width - 1;
  }
  else
  {
    min = std::min ((int) floor ((b - sqrt (det)) / a), (int) floor ((b + sqrt (det)) / a));
    max = std::max ((int) ceil ((b - sqrt (det)) / a), (int) ceil ((b + sqrt (det)) / a));
    minX = (unsigned) std::min ((int)input_->width - 1, std::max (0, min));
    maxX = (unsigned) std::max (std::min ((int)input_->width - 1, max), 0);
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> template <typename MatrixType> void
pcl::search::OrganizedNeighbor<PointT>::makeSymmetric (MatrixType& matrix, bool use_upper_triangular) const
{
  if (use_upper_triangular)
  {
    matrix.coeffRef (4) = matrix.coeff (1);
    matrix.coeffRef (8) = matrix.coeff (2);
    matrix.coeffRef (9) = matrix.coeff (6);
    matrix.coeffRef (12) = matrix.coeff (3);
    matrix.coeffRef (13) = matrix.coeff (7);
    matrix.coeffRef (14) = matrix.coeff (11);
  }
  else
  {
    matrix.coeffRef (1) = matrix.coeff (4);
    matrix.coeffRef (2) = matrix.coeff (8);
    matrix.coeffRef (6) = matrix.coeff (9);
    matrix.coeffRef (3) = matrix.coeff (12);
    matrix.coeffRef (7) = matrix.coeff (13);
    matrix.coeffRef (11) = matrix.coeff (14);
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename PointT> void
pcl::search::OrganizedNeighbor<PointT>::estimateProjectionMatrix ()
{
  // internally we calculate with double but store the result into float matrices.
  typedef double Scalar;
  projection_matrix_.setZero ();
  if (input_->height == 1 || input_->width == 1)
  {
    PCL_ERROR ("[pcl::%s::estimateProjectionMatrix] Input dataset is not organized!\n", getName ().c_str ());
    return;
  }

  // we just want to use every 16th column and row -> skip = 2^4
  const unsigned int skip = input_->width >> 4;
  Eigen::Matrix<Scalar, 4, 4> A = Eigen::Matrix<Scalar, 4, 4>::Zero ();
  Eigen::Matrix<Scalar, 4, 4> B = Eigen::Matrix<Scalar, 4, 4>::Zero ();
  Eigen::Matrix<Scalar, 4, 4> C = Eigen::Matrix<Scalar, 4, 4>::Zero ();
  Eigen::Matrix<Scalar, 4, 4> D = Eigen::Matrix<Scalar, 4, 4>::Zero ();

  for (unsigned yIdx = 0, idx = 0; yIdx < input_->height; yIdx += skip, idx += input_->width * (skip-1))
  {
    for (unsigned xIdx = 0; xIdx < input_->width; xIdx += skip, idx += skip)
    {
      const PointT& point = input_->points[idx];
      if (isFinite (point))
      {
        Scalar xx = point.x * point.x;
        Scalar xy = point.x * point.y;
        Scalar xz = point.x * point.z;
        Scalar yy = point.y * point.y;
        Scalar yz = point.y * point.z;
        Scalar zz = point.z * point.z;
        Scalar xx_yy = xIdx * xIdx + yIdx * yIdx;

        A.coeffRef (0) += xx;
        A.coeffRef (1) += xy;
        A.coeffRef (2) += xz;
        A.coeffRef (3) += point.x;

        A.coeffRef (5) += yy;
        A.coeffRef (6) += yz;
        A.coeffRef (7) += point.y;

        A.coeffRef (10) += zz;
        A.coeffRef (11) += point.z;
        A.coeffRef (15) += 1.0;

        B.coeffRef (0) -= xx * xIdx;
        B.coeffRef (1) -= xy * xIdx;
        B.coeffRef (2) -= xz * xIdx;
        B.coeffRef (3) -= point.x * xIdx;

        B.coeffRef (5) -= yy * xIdx;
        B.coeffRef (6) -= yz * xIdx;
        B.coeffRef (7) -= point.y * xIdx;

        B.coeffRef (10) -= zz * xIdx;
        B.coeffRef (11) -= point.z * xIdx;

        B.coeffRef (15) -= xIdx;

        C.coeffRef (0) -= xx * yIdx;
        C.coeffRef (1) -= xy * yIdx;
        C.coeffRef (2) -= xz * yIdx;
        C.coeffRef (3) -= point.x * yIdx;

        C.coeffRef (5) -= yy * yIdx;
        C.coeffRef (6) -= yz * yIdx;
        C.coeffRef (7) -= point.y * yIdx;

        C.coeffRef (10) -= zz * yIdx;
        C.coeffRef (11) -= point.z * yIdx;

        C.coeffRef (15) -= yIdx;

        D.coeffRef (0) += xx * xx_yy;
        D.coeffRef (1) += xy * xx_yy;
        D.coeffRef (2) += xz * xx_yy;
        D.coeffRef (3) += point.x * xx_yy;

        D.coeffRef (5) += yy * xx_yy;
        D.coeffRef (6) += yz * xx_yy;
        D.coeffRef (7) += point.y * xx_yy;

        D.coeffRef (10) += zz * xx_yy;
        D.coeffRef (11) += point.z * xx_yy;

        D.coeffRef (15) += xx_yy;
      }
    }
  }

  makeSymmetric(A);
  makeSymmetric(B);
  makeSymmetric(C);
  makeSymmetric(D);

  Eigen::Matrix<Scalar, 12, 12> X = Eigen::Matrix<Scalar, 12, 12>::Zero ();
  X.topLeftCorner<4,4> () = A;
  X.block<4,4> (0, 8) = B;
  X.block<4,4> (8, 0) = B;
  X.block<4,4> (4, 4) = A;
  X.block<4,4> (4, 8) = C;
  X.block<4,4> (8, 4) = C;
  X.block<4,4> (8, 8) = D;

  Eigen::SelfAdjointEigenSolver<Eigen::Matrix<Scalar, 12, 12> > ei_symm(X);
  Eigen::Matrix<Scalar, 12, 12> eigen_vectors = ei_symm.eigenvectors();

  // check whether the residual MSE is low. If its high, the cloud was not captured from a projective device.
  Eigen::Matrix<Scalar, 1, 1> residual_sqr = eigen_vectors.col (0).transpose () * X *  eigen_vectors.col (0);
  if ( residual_sqr.coeff (0) > eps_ * A.coeff (15))
  {
    PCL_ERROR ("[pcl::%s::radiusSearch] Input dataset is not from a projective device!\n", getName ().c_str ());
    return;
  }

  projection_matrix_.coeffRef (0) = eigen_vectors.coeff (0);
  projection_matrix_.coeffRef (1) = eigen_vectors.coeff (12);
  projection_matrix_.coeffRef (2) = eigen_vectors.coeff (24);
  projection_matrix_.coeffRef (3) = eigen_vectors.coeff (36);
  projection_matrix_.coeffRef (4) = eigen_vectors.coeff (48);
  projection_matrix_.coeffRef (5) = eigen_vectors.coeff (60);
  projection_matrix_.coeffRef (6) = eigen_vectors.coeff (72);
  projection_matrix_.coeffRef (7) = eigen_vectors.coeff (84);
  projection_matrix_.coeffRef (8) = eigen_vectors.coeff (96);
  projection_matrix_.coeffRef (9) = eigen_vectors.coeff (108);
  projection_matrix_.coeffRef (10) = eigen_vectors.coeff (120);
  projection_matrix_.coeffRef (11) = eigen_vectors.coeff (132);

  if (projection_matrix_.coeff (0) < 0)
    projection_matrix_ *= -1.0;

  // get left 3x3 sub matrix, which contains K * R, with K = camera matrix = [[fx s cx] [0 fy cy] [0 0 1]]
  // and R being the rotation matrix
  KR_ = projection_matrix_.topLeftCorner <3, 3> ();

  // precalculate KR * KR^T needed by calculations during nn-search
  KR_KRT_ = KR_ * KR_.transpose ();
}

#define PCL_INSTANTIATE_OrganizedNeighbor(T) template class PCL_EXPORTS pcl::search::OrganizedNeighbor<T>;

#endif
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "fusionrunner.h"
#include "eventlogger.h"
#include "fusionspec.h"
#include <vespa/searchlib/common/serialnumfileheadercontext.h>
#include <vespa/searchlib/attribute/fixedsourceselector.h>
#include <vespa/searchlib/queryeval/isourceselector.h>
#include <vespa/searchlib/util/dirtraverse.h>
#include <vespa/vespalib/util/jsonwriter.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchcorespi.index.fusionrunner");

using search::FixedSourceSelector;
using search::TuneFileAttributes;
using search::TuneFileIndexing;
using search::common::FileHeaderContext;
using search::common::SerialNumFileHeaderContext;
using search::index::Schema;
using search::queryeval::ISourceSelector;
using search::diskindex::SelectorArray;
using search::SerialNum;
using std::vector;
using vespalib::string;
using vespalib::JSONStringer;

namespace searchcorespi::index {

FusionRunner::FusionRunner(const string &base_dir,
                           const Schema &schema,
                           const TuneFileAttributes &tuneFileAttributes,
                           const FileHeaderContext &fileHeaderContext)
    : _diskLayout(base_dir),
      _schema(schema),
      _tuneFileAttributes(tuneFileAttributes),
      _fileHeaderContext(fileHeaderContext)
{ }

FusionRunner::~FusionRunner() {
}

namespace {

void readSelectorArray(const string &selector_name, SelectorArray &selector_array,
                       const vector<uint8_t> &id_map, uint32_t base_id) {
    FixedSourceSelector::UP selector =
        FixedSourceSelector::load(selector_name);
    if (base_id != selector->getBaseId()) {
        selector = selector->cloneAndSubtract("tmp_for_fusion", base_id - selector->getBaseId());
    }

    const uint32_t num_docs = selector->getDocIdLimit();
    selector_array.reserve(num_docs);
    auto it = selector->createIterator();
    for (uint32_t i = 0; i < num_docs; ++i) {
        search::queryeval::Source source = it->getSource(i);
        assert(source < id_map.size());
        selector_array.push_back(id_map[source]);
    }
}

bool
writeFusionSelector(const IndexDiskLayout &diskLayout, uint32_t fusion_id,
                    uint32_t highest_doc_id,
                    const TuneFileAttributes &tuneFileAttributes,
                    const FileHeaderContext &fileHeaderContext)
{
    const search::queryeval::Source default_source = 0;
    FixedSourceSelector fusion_selector(default_source, "fusion_selector");
    fusion_selector.setSource(highest_doc_id, default_source);
    fusion_selector.setBaseId(fusion_id);
    string selector_name = IndexDiskLayout::getSelectorFileName(diskLayout.getFusionDir(fusion_id));
    if (!fusion_selector.extractSaveInfo(selector_name)->save(tuneFileAttributes, fileHeaderContext)) {
        LOG(warning, "Unable to write source selector data for fusion.%u.", fusion_id);
        return false;
    }
    return true;
}
}  // namespace

uint32_t
FusionRunner::fuse(const FusionSpec &fusion_spec,
                   SerialNum lastSerialNum,
                   IIndexMaintainerOperations &operations)
{
    const vector<uint32_t> &ids = fusion_spec.flush_ids;
    if (ids.empty()) {
        return 0;
    }
    const uint32_t fusion_id = ids.back();
    const string fusion_dir = _diskLayout.getFusionDir(fusion_id);

    vector<string> sources;
    vector<uint8_t> id_map(fusion_id + 1);
    if (fusion_spec.last_fusion_id != 0) {
        id_map[0] = sources.size();
        sources.push_back(_diskLayout.getFusionDir(fusion_spec.last_fusion_id));
    }
    for (size_t i = 0; i < ids.size(); ++i) {
        id_map[ids[i] - fusion_spec.last_fusion_id] = sources.size();
        sources.push_back(_diskLayout.getFlushDir(ids[i]));
    }

    if (LOG_WOULD_LOG(event)) {
        EventLogger::diskFusionStart(sources, fusion_dir);
    }
    FastOS_Time timer;
    timer.SetNow();

    const string selector_name = IndexDiskLayout::getSelectorFileName(_diskLayout.getFlushDir(fusion_id));
    SelectorArray selector_array;
    readSelectorArray(selector_name, selector_array, id_map, fusion_spec.last_fusion_id);

    if (!operations.runFusion(_schema, fusion_dir, sources, selector_array, lastSerialNum)) {
        return 0;
    }

    const uint32_t highest_doc_id = selector_array.size() - 1;
    SerialNumFileHeaderContext fileHeaderContext(_fileHeaderContext, lastSerialNum);
    if (!writeFusionSelector(_diskLayout, fusion_id, highest_doc_id, _tuneFileAttributes, fileHeaderContext)) {
        return 0;
    }

    if (LOG_WOULD_LOG(event)) {
        EventLogger::diskFusionComplete(fusion_dir, (int64_t)timer.MilliSecsToNow());
    }
    return fusion_id;
}

}
<commit_msg>Add workaround for source selector corruption.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "fusionrunner.h"
#include "eventlogger.h"
#include "fusionspec.h"
#include <vespa/searchlib/common/serialnumfileheadercontext.h>
#include <vespa/searchlib/attribute/fixedsourceselector.h>
#include <vespa/searchlib/queryeval/isourceselector.h>
#include <vespa/searchlib/util/dirtraverse.h>
#include <vespa/vespalib/util/jsonwriter.h>

#include <vespa/log/log.h>
LOG_SETUP(".searchcorespi.index.fusionrunner");

using search::FixedSourceSelector;
using search::TuneFileAttributes;
using search::TuneFileIndexing;
using search::common::FileHeaderContext;
using search::common::SerialNumFileHeaderContext;
using search::index::Schema;
using search::queryeval::ISourceSelector;
using search::diskindex::SelectorArray;
using search::SerialNum;
using std::vector;
using vespalib::string;
using vespalib::JSONStringer;

namespace searchcorespi::index {

FusionRunner::FusionRunner(const string &base_dir,
                           const Schema &schema,
                           const TuneFileAttributes &tuneFileAttributes,
                           const FileHeaderContext &fileHeaderContext)
    : _diskLayout(base_dir),
      _schema(schema),
      _tuneFileAttributes(tuneFileAttributes),
      _fileHeaderContext(fileHeaderContext)
{ }

FusionRunner::~FusionRunner() {
}

namespace {

void readSelectorArray(const string &selector_name, SelectorArray &selector_array,
                       const vector<uint8_t> &id_map, uint32_t base_id) {
    FixedSourceSelector::UP selector =
        FixedSourceSelector::load(selector_name);
    if (base_id != selector->getBaseId()) {
        selector = selector->cloneAndSubtract("tmp_for_fusion", base_id - selector->getBaseId());
    }

    const uint32_t num_docs = selector->getDocIdLimit();
    selector_array.reserve(num_docs);
    auto it = selector->createIterator();
    for (uint32_t i = 0; i < num_docs; ++i) {
        search::queryeval::Source source = it->getSource(i);
        // Workaround for source selector corruption.
        // Treat out of range source as last source.
        if (source >= id_map.size()) {
            source = id_map.size() - 1;
        }
        assert(source < id_map.size());
        selector_array.push_back(id_map[source]);
    }
}

bool
writeFusionSelector(const IndexDiskLayout &diskLayout, uint32_t fusion_id,
                    uint32_t highest_doc_id,
                    const TuneFileAttributes &tuneFileAttributes,
                    const FileHeaderContext &fileHeaderContext)
{
    const search::queryeval::Source default_source = 0;
    FixedSourceSelector fusion_selector(default_source, "fusion_selector");
    fusion_selector.setSource(highest_doc_id, default_source);
    fusion_selector.setBaseId(fusion_id);
    string selector_name = IndexDiskLayout::getSelectorFileName(diskLayout.getFusionDir(fusion_id));
    if (!fusion_selector.extractSaveInfo(selector_name)->save(tuneFileAttributes, fileHeaderContext)) {
        LOG(warning, "Unable to write source selector data for fusion.%u.", fusion_id);
        return false;
    }
    return true;
}
}  // namespace

uint32_t
FusionRunner::fuse(const FusionSpec &fusion_spec,
                   SerialNum lastSerialNum,
                   IIndexMaintainerOperations &operations)
{
    const vector<uint32_t> &ids = fusion_spec.flush_ids;
    if (ids.empty()) {
        return 0;
    }
    const uint32_t fusion_id = ids.back();
    const string fusion_dir = _diskLayout.getFusionDir(fusion_id);

    vector<string> sources;
    vector<uint8_t> id_map(fusion_id + 1);
    if (fusion_spec.last_fusion_id != 0) {
        id_map[0] = sources.size();
        sources.push_back(_diskLayout.getFusionDir(fusion_spec.last_fusion_id));
    }
    for (size_t i = 0; i < ids.size(); ++i) {
        id_map[ids[i] - fusion_spec.last_fusion_id] = sources.size();
        sources.push_back(_diskLayout.getFlushDir(ids[i]));
    }

    if (LOG_WOULD_LOG(event)) {
        EventLogger::diskFusionStart(sources, fusion_dir);
    }
    FastOS_Time timer;
    timer.SetNow();

    const string selector_name = IndexDiskLayout::getSelectorFileName(_diskLayout.getFlushDir(fusion_id));
    SelectorArray selector_array;
    readSelectorArray(selector_name, selector_array, id_map, fusion_spec.last_fusion_id);

    if (!operations.runFusion(_schema, fusion_dir, sources, selector_array, lastSerialNum)) {
        return 0;
    }

    const uint32_t highest_doc_id = selector_array.size() - 1;
    SerialNumFileHeaderContext fileHeaderContext(_fileHeaderContext, lastSerialNum);
    if (!writeFusionSelector(_diskLayout, fusion_id, highest_doc_id, _tuneFileAttributes, fileHeaderContext)) {
        return 0;
    }

    if (LOG_WOULD_LOG(event)) {
        EventLogger::diskFusionComplete(fusion_dir, (int64_t)timer.MilliSecsToNow());
    }
    return fusion_id;
}

}
<|endoftext|>


<commit_before>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "startWidget.h"

#include <QtCore/QSignalMapper>
#include <QtGui/QPainter>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QScrollArea>

#include <qrkernel/settingsManager.h>
#include <qrgui/plugins/pluginManager/editorManager.h>
#include <qrgui/plugins/pluginManager/interpreterEditorManager.h>
#include <qrgui/plugins/pluginManager/proxyEditorManager.h>

#include "mainWindow/mainWindow.h"
#include "styledButton.h"
#include "circleWidget.h"
#include "brandManager/brandManager.h"

using namespace qReal;

StartWidget::StartWidget(MainWindow *mainWindow, ProjectManager *projectManager)
	: mMainWindow(mainWindow)
	, mProjectManager(projectManager)
	, mProjectListSize(5)  // TODO: Why 5?
	, mNewProjectButton(nullptr)
	, mOpenProjectButton(nullptr)
	, mOpenInterpreterButton(nullptr)
	, mCreateInterpreterButton(nullptr)
{
	setStyleSheet(BrandManager::styles()->startTabSubstrateBackgroundStyle());
	QWidget * const mainWidget = createMainWidget();

	QHBoxLayout * const mainLayout = new QHBoxLayout;
	mainLayout->addStretch(1);
	mainLayout->addWidget(mainWidget, 10);
	mainLayout->addStretch(1);
	setLayout(mainLayout);
}

QWidget *StartWidget::createMainWidget()
{
	QWidget * const result = new QWidget;
	result->setStyleSheet(BrandManager::styles()->startTabBackgroundStyle());

	QWidget * const header = createHeader();
	mRecentProjectsWidget = createRecentProjectsWidget();
	QWidget * const projectsManagement = createProjectsManagementWidget();

	QVBoxLayout * mainLayout = new QVBoxLayout;
	QHBoxLayout * contentsLayout = new QHBoxLayout;

	mainLayout->addWidget(header);
	mainLayout->addLayout(contentsLayout);
	mainLayout->setStretch(1, 10);
	if (mRecentProjectsWidget) {
		contentsLayout->addWidget(mRecentProjectsWidget);
	}

	contentsLayout->addWidget(projectsManagement);
	contentsLayout->setStretch(0, 10);
	contentsLayout->setStretch(1, 20);

	result->setLayout(mainLayout);
	result->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
	return result;
}

QWidget *StartWidget::createHeader()
{
	QLabel * const appName = new QLabel(BrandManager::applicationName());
	appName->setStyleSheet(BrandManager::styles()->startTabLabelLevel1Style());

	QLabel * const appLogo = new QLabel;
	appLogo->setFixedSize(200, 100);
	appLogo->setScaledContents(false);
	appLogo->setPixmap(QPixmap::fromImage(BrandManager::applicationLogo()).scaled(appLogo->size()
			, Qt::KeepAspectRatio, Qt::SmoothTransformation));

	QHBoxLayout * const headerLayout = new QHBoxLayout;
	headerLayout->addWidget(appName);
	headerLayout->addStretch();
	headerLayout->addWidget(appLogo);

	QWidget * const header = new QWidget;
	header->setStyleSheet(BrandManager::styles()->startTabHeaderBackgroundStyle());
	header->setLayout(headerLayout);

	return header;
}

QWidget *StartWidget::createRecentProjectsWidget()
{
	const QString recentProjects = SettingsManager::value("recentProjects").toString();
	if (recentProjects.isEmpty() || mMainWindow->editorManager().editors().isEmpty()) {
		return nullptr;
	}

	QWidget * const result = new QWidget;
	result->setStyleSheet(BrandManager::styles()->startTabRecentProjectsBackgroundStyle());
	result->setLayout(createRecentProjectsList(recentProjects));
	return result;
}

QWidget *StartWidget::createProjectsManagementWidget()
{
	mProjectsManagementLayout = new QBoxLayout(QBoxLayout::TopToBottom);
	mProjectsManagementLayout->addStretch();

	mOpenProjectButton = new StyledButton(tr("Open existing project")
			, ":/mainWindow/images/startTab/open.svg");
	connect(mOpenProjectButton, &QPushButton::clicked, this, &StartWidget::openExistingProject);
	mProjectsManagementLayout->addWidget(mOpenProjectButton);

	const Id theOnlyDiagram = mMainWindow->editorManager().theOnlyDiagram();
	if (!theOnlyDiagram.isNull()) {
		const Id editor = mMainWindow->editorManager().editors()[0];
		const QString diagramIdString = mMainWindow->editorManager().diagramNodeNameString(editor, theOnlyDiagram);

		mNewProjectButton = new StyledButton(tr("New project"), ":/mainWindow/images/startTab/new.svg");
		mProjectsManagementLayout->addWidget(mNewProjectButton);

		QSignalMapper *newProjectMapper = new QSignalMapper(this);
		newProjectMapper->setMapping(mNewProjectButton, diagramIdString);
		connect(mNewProjectButton, SIGNAL(clicked()), newProjectMapper, SLOT(map()));
		connect(newProjectMapper, SIGNAL(mapped(QString)), this, SLOT(createProjectWithDiagram(QString)));
	} else {
		if (!mMainWindow->editorManager().editors().isEmpty()) {
			QWidget * const pluginsWidget = createPluginsList();
			mProjectsManagementLayout->addWidget(pluginsWidget, 1);
		} else {
			mOpenProjectButton->hide();
		}
	}

	mOpenInterpreterButton = new StyledButton(tr("Open interpreted diagram")
			, ":/mainWindow/images/startTab/openInterpreted.svg");
	mCreateInterpreterButton = new StyledButton(tr("Create interpreted diagram")
			, ":/mainWindow/images/startTab/createInterpreted.svg");
	connect(mOpenInterpreterButton, SIGNAL(clicked()), this, SLOT(openInterpretedDiagram()));
	connect(mCreateInterpreterButton, SIGNAL(clicked()), this, SLOT(createInterpretedDiagram()));

	mProjectsManagementLayout->addWidget(mCreateInterpreterButton);
	mProjectsManagementLayout->addWidget(mOpenInterpreterButton);
	mProjectsManagementLayout->addStretch();

	QWidget * const result = new QWidget;
	result->setLayout(mProjectsManagementLayout);
	result->setStyleSheet(BrandManager::styles()->startTabProjectsManagementBackgroundStyle());
	return result;
}

void StartWidget::openRecentProject(const QString &fileName)
{
	mProjectManager->open(fileName);
}

void StartWidget::openExistingProject()
{
	mProjectManager->suggestToOpenExisting();
}

void StartWidget::createProjectWithDiagram(const QString &idString)
{
	mMainWindow->createProject(idString);
}

QLayout *StartWidget::createRecentProjectsList(const QString &recentProjects)
{
	QVBoxLayout * const mainLayout = new QVBoxLayout;
	QVBoxLayout * const recentProjectsLayout = new QVBoxLayout;
	recentProjectsLayout->setContentsMargins(0, 0, 0, 0);

	QLabel * const recentProjectsLabel = new QLabel(tr("Recent projects"));
	recentProjectsLabel->setWordWrap(true);
	recentProjectsLabel->setStyleSheet(BrandManager::styles()->startTabLabelLevel2Style());

	QWidget * const spacer = new QWidget;
	spacer->setFixedHeight(10);

	mainLayout->addWidget(recentProjectsLabel);
	mainLayout->addWidget(spacer);
	mainLayout->addLayout(recentProjectsLayout);

	mainLayout->addStretch(0);

	QSignalMapper * const projectNameMapper = new QSignalMapper(this);
	connect(projectNameMapper, SIGNAL(mapped(QString)), this, SLOT(openRecentProject(QString)));

	int i = 0;
	for (const QString &project : recentProjects.split(";", QString::SkipEmptyParts)) {
		const QString name = project.split("/").last().split("\\").last();
		QPushButton * const projectItem = new StyledButton(name);
		projectItem->setToolTip(project);
		recentProjectsLayout->addWidget(projectItem);

		projectNameMapper->setMapping(projectItem, project);
		connect(projectItem, SIGNAL(clicked()), projectNameMapper, SLOT(map()));

		++i;
		if (i >= mProjectListSize) {
			break;
		}
	}

	return mainLayout;
}

QWidget *StartWidget::createPluginsList()
{
	QWidget * const circleWidget = new CircleWidget(QSize(70, 70), ":/mainWindow/images/startTab/new.svg");
	circleWidget->setStyleSheet(BrandManager::styles()->startTabButtonStyle());

	QVBoxLayout * const innerLayout = new QVBoxLayout;
	innerLayout->addStretch();
	foreach (const Id &editor, mMainWindow->editorManager().editors()) {
		const Id editorTmpId = Id::loadFromString("qrm:/" + editor.editor());
		foreach (const Id &diagram, mMainWindow->editorManager().diagrams(editorTmpId)) {
			QWidget * const pluginWidget = createPluginButton(editor, diagram, circleWidget);
			innerLayout->addWidget(pluginWidget);
		}
	}

	innerLayout->addStretch();
	innerLayout->setContentsMargins(0, 0, 0, 0);
	innerLayout->setMargin(0);
	innerLayout->setSpacing(0);

	QWidget *innerWidget = new QWidget;
	innerWidget->setLayout(innerLayout);

	QScrollArea *scrollArea = new QScrollArea;
	scrollArea->setFrameShape(QFrame::NoFrame);
	scrollArea->setWidgetResizable(true);
	scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
	scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	scrollArea->setWidget(innerWidget);

	QHBoxLayout * const mainLayout = new QHBoxLayout;
	mainLayout->addWidget(circleWidget, Qt::AlignCenter);
	mainLayout->addWidget(scrollArea);
	mainLayout->setStretch(0, 0);
	mainLayout->setStretch(1, 10);
	mainLayout->setMargin(0);

	QWidget * const result = new QWidget;
	result->setLayout(mainLayout);

	return result;
}

QWidget *StartWidget::createPluginButton(const Id &editor, const Id &diagram, QWidget * const bindedImage)
{
	const EditorManagerInterface &editorManagerInterface = mMainWindow->editorManager();

	const QString diagramName = editorManagerInterface.diagramName(editor.editor(), diagram.diagram());
	const QString diagramNodeName = editorManagerInterface.diagramNodeName(editor.editor(), diagram.diagram());

	if (diagramNodeName.isEmpty()) {
		return nullptr;
	}

	StyledButton * const result = new StyledButton(tr("Create ") + diagramName);
	result->bindHighlightedOnHover(bindedImage);
	result->setFocusPolicy(Qt::StrongFocus);
	result->setStyleSheet(BrandManager::styles()->startTabButtonStyle());
	result->setToolTip(tr("Editor: ") + editor.editor() + tr("; Diagram: ") + diagram.diagram());

	QSignalMapper *pluginMapper = new QSignalMapper(result);
	pluginMapper->setMapping(result, "qrm:/" + editor.editor() + "/" + diagram.diagram() + "/" + diagramNodeName);
	connect(result, SIGNAL(clicked()), pluginMapper, SLOT(map()));
	connect(pluginMapper, SIGNAL(mapped(QString)), mMainWindow, SLOT(createDiagram(QString)));

	return result;
}

void StartWidget::openInterpretedDiagram()
{
	hide();
	const QString fileName = mProjectManager->openFileName(tr("Select file with metamodel to open"));
	ProxyEditorManager &editorManagerProxy = mMainWindow->editorManagerProxy();

	if (!fileName.isEmpty()) {
		editorManagerProxy.setProxyManager(new InterpreterEditorManager(fileName));
		QStringList interpreterDiagramsList;
		foreach (const Id &editor, editorManagerProxy.editors()) {
			foreach (const Id &diagram, editorManagerProxy.diagrams(editor)) {
				const QString diagramNodeName = editorManagerProxy.diagramNodeName(editor.editor(), diagram.diagram());
				if (diagramNodeName.isEmpty()) {
					continue;
				}

				interpreterDiagramsList.append("qrm:/" + editor.editor() + "/"
						+ diagram.diagram() + "/" + diagramNodeName);
			}
		}

		mMainWindow->initInterpretedPlugins();

		foreach (const QString &interpreterIdString, interpreterDiagramsList) {
			// TODO: ???
			mMainWindow->models().repoControlApi().exterminate();
			mMainWindow->models().reinit();
			mMainWindow->loadPlugins();
			mMainWindow->createDiagram(interpreterIdString);
		}
	} else {
		show();
		editorManagerProxy.setProxyManager(new EditorManager());
	}
}

void StartWidget::createInterpretedDiagram()
{
	hide();
	ProxyEditorManager &editorManagerProxy = mMainWindow->editorManagerProxy();
	editorManagerProxy.setProxyManager(new InterpreterEditorManager(""));
	bool ok = false;
	QString name = QInputDialog::getText(this, tr("Enter the diagram name:"), tr("diagram name:")
			, QLineEdit::Normal, "", &ok);
	while (ok && name.isEmpty()) {
		name = QInputDialog::getText(this, tr("Enter the diagram name:"), tr("diagram name:")
				, QLineEdit::Normal, "", &ok);
	}

	if (ok) {
		QPair<Id, Id> editorAndDiagram = editorManagerProxy.createEditorAndDiagram(name);
		mMainWindow->addEditorElementsToPalette(editorAndDiagram.first, editorAndDiagram.second);
		mMainWindow->models().repoControlApi().exterminate();
		mMainWindow->models().reinit();
		mMainWindow->loadPlugins();
		mMainWindow->initInterpretedPlugins();
	} else {
		show();
		editorManagerProxy.setProxyManager(new EditorManager());
	}
}

void StartWidget::setVisibleForInterpreterButton(const bool visible)
{
	if (!visible) {
		/// @todo: For some reason setVisible on interpreter buttons still leaves them visible.
		/// This surely can be fixed and then setVisible(visible) call must be restored,
		/// but for now working it arround...
		delete mOpenInterpreterButton;
		delete mCreateInterpreterButton;
		mOpenInterpreterButton = nullptr;
		mCreateInterpreterButton = nullptr;
	}

	const int editorsCount = mMainWindow->editorManager().editors().count();
	QList<QPushButton *> toCentralize;
	bool needLayoutHorizontally = false;
	if (visible) {
		needLayoutHorizontally = editorsCount == 0;
		toCentralize << mCreateInterpreterButton << mOpenInterpreterButton;
	} else {
		needLayoutHorizontally = editorsCount == 1 && !mRecentProjectsWidget;
		toCentralize << mNewProjectButton << mOpenProjectButton;
	}

	if (needLayoutHorizontally) {
		for (QPushButton * const button : toCentralize) {
			centralizeButton(button);
		}

		mProjectsManagementLayout->setDirection(QBoxLayout::LeftToRight);
	}
}

void StartWidget::centralizeButton(QPushButton * const styledButton)
{
	if (!styledButton) {
		return;
	}

	QBoxLayout * const layout = static_cast<QBoxLayout *>(styledButton->layout());
	layout->setDirection(QBoxLayout::TopToBottom);
	QWidget * const icon = layout->itemAt(0)->widget();
	QLabel * const label = static_cast<QLabel *>(layout->itemAt(1)->widget());
	label->setAlignment(Qt::AlignHCenter);
	layout->setAlignment(icon, Qt::AlignHCenter | Qt::AlignBottom);
	layout->setAlignment(label, Qt::AlignHCenter | Qt::AlignTop);
	layout->activate();
	layout->update();
	styledButton->update();

	mProjectsManagementLayout->setAlignment(styledButton, Qt::AlignVCenter);
	const int index = mProjectsManagementLayout->indexOf(styledButton);
	mProjectsManagementLayout->setStretch(index, 10000);
}

void StartWidget::paintEvent(QPaintEvent *event)
{
	Q_UNUSED(event);

	QStyleOption styleOption;
	styleOption.initFrom(this);
	QPainter painter(this);
	style()->drawPrimitive(QStyle::PE_Widget, &styleOption, &painter, this);
}
<commit_msg>Fixed segfaults after creating diagrams of two different types first from start widget and then from editors dialog<commit_after>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "startWidget.h"

#include <QtCore/QSignalMapper>
#include <QtGui/QPainter>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QScrollArea>

#include <qrkernel/settingsManager.h>
#include <qrgui/plugins/pluginManager/editorManager.h>
#include <qrgui/plugins/pluginManager/interpreterEditorManager.h>
#include <qrgui/plugins/pluginManager/proxyEditorManager.h>

#include "mainWindow/mainWindow.h"
#include "styledButton.h"
#include "circleWidget.h"
#include "brandManager/brandManager.h"

using namespace qReal;

StartWidget::StartWidget(MainWindow *mainWindow, ProjectManager *projectManager)
	: mMainWindow(mainWindow)
	, mProjectManager(projectManager)
	, mProjectListSize(5)  // TODO: Why 5?
	, mNewProjectButton(nullptr)
	, mOpenProjectButton(nullptr)
	, mOpenInterpreterButton(nullptr)
	, mCreateInterpreterButton(nullptr)
{
	setStyleSheet(BrandManager::styles()->startTabSubstrateBackgroundStyle());
	QWidget * const mainWidget = createMainWidget();

	QHBoxLayout * const mainLayout = new QHBoxLayout;
	mainLayout->addStretch(1);
	mainLayout->addWidget(mainWidget, 10);
	mainLayout->addStretch(1);
	setLayout(mainLayout);
}

QWidget *StartWidget::createMainWidget()
{
	QWidget * const result = new QWidget;
	result->setStyleSheet(BrandManager::styles()->startTabBackgroundStyle());

	QWidget * const header = createHeader();
	mRecentProjectsWidget = createRecentProjectsWidget();
	QWidget * const projectsManagement = createProjectsManagementWidget();

	QVBoxLayout * mainLayout = new QVBoxLayout;
	QHBoxLayout * contentsLayout = new QHBoxLayout;

	mainLayout->addWidget(header);
	mainLayout->addLayout(contentsLayout);
	mainLayout->setStretch(1, 10);
	if (mRecentProjectsWidget) {
		contentsLayout->addWidget(mRecentProjectsWidget);
	}

	contentsLayout->addWidget(projectsManagement);
	contentsLayout->setStretch(0, 10);
	contentsLayout->setStretch(1, 20);

	result->setLayout(mainLayout);
	result->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
	return result;
}

QWidget *StartWidget::createHeader()
{
	QLabel * const appName = new QLabel(BrandManager::applicationName());
	appName->setStyleSheet(BrandManager::styles()->startTabLabelLevel1Style());

	QLabel * const appLogo = new QLabel;
	appLogo->setFixedSize(200, 100);
	appLogo->setScaledContents(false);
	appLogo->setPixmap(QPixmap::fromImage(BrandManager::applicationLogo()).scaled(appLogo->size()
			, Qt::KeepAspectRatio, Qt::SmoothTransformation));

	QHBoxLayout * const headerLayout = new QHBoxLayout;
	headerLayout->addWidget(appName);
	headerLayout->addStretch();
	headerLayout->addWidget(appLogo);

	QWidget * const header = new QWidget;
	header->setStyleSheet(BrandManager::styles()->startTabHeaderBackgroundStyle());
	header->setLayout(headerLayout);

	return header;
}

QWidget *StartWidget::createRecentProjectsWidget()
{
	const QString recentProjects = SettingsManager::value("recentProjects").toString();
	if (recentProjects.isEmpty() || mMainWindow->editorManager().editors().isEmpty()) {
		return nullptr;
	}

	QWidget * const result = new QWidget;
	result->setStyleSheet(BrandManager::styles()->startTabRecentProjectsBackgroundStyle());
	result->setLayout(createRecentProjectsList(recentProjects));
	return result;
}

QWidget *StartWidget::createProjectsManagementWidget()
{
	mProjectsManagementLayout = new QBoxLayout(QBoxLayout::TopToBottom);
	mProjectsManagementLayout->addStretch();

	mOpenProjectButton = new StyledButton(tr("Open existing project")
			, ":/mainWindow/images/startTab/open.svg");
	connect(mOpenProjectButton, &QPushButton::clicked, this, &StartWidget::openExistingProject);
	mProjectsManagementLayout->addWidget(mOpenProjectButton);

	const Id theOnlyDiagram = mMainWindow->editorManager().theOnlyDiagram();
	if (!theOnlyDiagram.isNull()) {
		const Id editor = mMainWindow->editorManager().editors()[0];
		const QString diagramIdString = mMainWindow->editorManager().diagramNodeNameString(editor, theOnlyDiagram);

		mNewProjectButton = new StyledButton(tr("New project"), ":/mainWindow/images/startTab/new.svg");
		mProjectsManagementLayout->addWidget(mNewProjectButton);

		QSignalMapper *newProjectMapper = new QSignalMapper(this);
		newProjectMapper->setMapping(mNewProjectButton, diagramIdString);
		connect(mNewProjectButton, SIGNAL(clicked()), newProjectMapper, SLOT(map()));
		connect(newProjectMapper, SIGNAL(mapped(QString)), this, SLOT(createProjectWithDiagram(QString)));
	} else {
		if (!mMainWindow->editorManager().editors().isEmpty()) {
			QWidget * const pluginsWidget = createPluginsList();
			mProjectsManagementLayout->addWidget(pluginsWidget, 1);
		} else {
			mOpenProjectButton->hide();
		}
	}

	mOpenInterpreterButton = new StyledButton(tr("Open interpreted diagram")
			, ":/mainWindow/images/startTab/openInterpreted.svg");
	mCreateInterpreterButton = new StyledButton(tr("Create interpreted diagram")
			, ":/mainWindow/images/startTab/createInterpreted.svg");
	connect(mOpenInterpreterButton, SIGNAL(clicked()), this, SLOT(openInterpretedDiagram()));
	connect(mCreateInterpreterButton, SIGNAL(clicked()), this, SLOT(createInterpretedDiagram()));

	mProjectsManagementLayout->addWidget(mCreateInterpreterButton);
	mProjectsManagementLayout->addWidget(mOpenInterpreterButton);
	mProjectsManagementLayout->addStretch();

	QWidget * const result = new QWidget;
	result->setLayout(mProjectsManagementLayout);
	result->setStyleSheet(BrandManager::styles()->startTabProjectsManagementBackgroundStyle());
	return result;
}

void StartWidget::openRecentProject(const QString &fileName)
{
	mProjectManager->open(fileName);
}

void StartWidget::openExistingProject()
{
	mProjectManager->suggestToOpenExisting();
}

void StartWidget::createProjectWithDiagram(const QString &idString)
{
	mMainWindow->createProject(idString);
}

QLayout *StartWidget::createRecentProjectsList(const QString &recentProjects)
{
	QVBoxLayout * const mainLayout = new QVBoxLayout;
	QVBoxLayout * const recentProjectsLayout = new QVBoxLayout;
	recentProjectsLayout->setContentsMargins(0, 0, 0, 0);

	QLabel * const recentProjectsLabel = new QLabel(tr("Recent projects"));
	recentProjectsLabel->setWordWrap(true);
	recentProjectsLabel->setStyleSheet(BrandManager::styles()->startTabLabelLevel2Style());

	QWidget * const spacer = new QWidget;
	spacer->setFixedHeight(10);

	mainLayout->addWidget(recentProjectsLabel);
	mainLayout->addWidget(spacer);
	mainLayout->addLayout(recentProjectsLayout);

	mainLayout->addStretch(0);

	QSignalMapper * const projectNameMapper = new QSignalMapper(this);
	connect(projectNameMapper, SIGNAL(mapped(QString)), this, SLOT(openRecentProject(QString)));

	int i = 0;
	for (const QString &project : recentProjects.split(";", QString::SkipEmptyParts)) {
		const QString name = project.split("/").last().split("\\").last();
		QPushButton * const projectItem = new StyledButton(name);
		projectItem->setToolTip(project);
		recentProjectsLayout->addWidget(projectItem);

		projectNameMapper->setMapping(projectItem, project);
		connect(projectItem, SIGNAL(clicked()), projectNameMapper, SLOT(map()));

		++i;
		if (i >= mProjectListSize) {
			break;
		}
	}

	return mainLayout;
}

QWidget *StartWidget::createPluginsList()
{
	QWidget * const circleWidget = new CircleWidget(QSize(70, 70), ":/mainWindow/images/startTab/new.svg");
	circleWidget->setStyleSheet(BrandManager::styles()->startTabButtonStyle());

	QVBoxLayout * const innerLayout = new QVBoxLayout;
	innerLayout->addStretch();
	foreach (const Id &editor, mMainWindow->editorManager().editors()) {
		const Id editorTmpId = Id::loadFromString("qrm:/" + editor.editor());
		foreach (const Id &diagram, mMainWindow->editorManager().diagrams(editorTmpId)) {
			QWidget * const pluginWidget = createPluginButton(editor, diagram, circleWidget);
			innerLayout->addWidget(pluginWidget);
		}
	}

	innerLayout->addStretch();
	innerLayout->setContentsMargins(0, 0, 0, 0);
	innerLayout->setMargin(0);
	innerLayout->setSpacing(0);

	QWidget *innerWidget = new QWidget;
	innerWidget->setLayout(innerLayout);

	QScrollArea *scrollArea = new QScrollArea;
	scrollArea->setFrameShape(QFrame::NoFrame);
	scrollArea->setWidgetResizable(true);
	scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
	scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	scrollArea->setWidget(innerWidget);

	QHBoxLayout * const mainLayout = new QHBoxLayout;
	mainLayout->addWidget(circleWidget, Qt::AlignCenter);
	mainLayout->addWidget(scrollArea);
	mainLayout->setStretch(0, 0);
	mainLayout->setStretch(1, 10);
	mainLayout->setMargin(0);

	QWidget * const result = new QWidget;
	result->setLayout(mainLayout);

	return result;
}

QWidget *StartWidget::createPluginButton(const Id &editor, const Id &diagram, QWidget * const bindedImage)
{
	const EditorManagerInterface &editorManagerInterface = mMainWindow->editorManager();

	const QString diagramName = editorManagerInterface.diagramName(editor.editor(), diagram.diagram());
	const QString diagramNodeName = editorManagerInterface.diagramNodeName(editor.editor(), diagram.diagram());

	if (diagramNodeName.isEmpty()) {
		return nullptr;
	}

	StyledButton * const result = new StyledButton(tr("Create ") + diagramName);
	result->bindHighlightedOnHover(bindedImage);
	result->setFocusPolicy(Qt::StrongFocus);
	result->setStyleSheet(BrandManager::styles()->startTabButtonStyle());
	result->setToolTip(tr("Editor: ") + editor.editor() + tr("; Diagram: ") + diagram.diagram());

	QSignalMapper *pluginMapper = new QSignalMapper(result);
	pluginMapper->setMapping(result, "qrm:/" + editor.editor() + "/" + diagram.diagram() + "/" + diagramNodeName);
	connect(result, SIGNAL(clicked()), pluginMapper, SLOT(map()));
	connect(pluginMapper, SIGNAL(mapped(QString)), mMainWindow, SLOT(createProject(QString)));

	return result;
}

void StartWidget::openInterpretedDiagram()
{
	hide();
	const QString fileName = mProjectManager->openFileName(tr("Select file with metamodel to open"));
	ProxyEditorManager &editorManagerProxy = mMainWindow->editorManagerProxy();

	if (!fileName.isEmpty()) {
		editorManagerProxy.setProxyManager(new InterpreterEditorManager(fileName));
		QStringList interpreterDiagramsList;
		foreach (const Id &editor, editorManagerProxy.editors()) {
			foreach (const Id &diagram, editorManagerProxy.diagrams(editor)) {
				const QString diagramNodeName = editorManagerProxy.diagramNodeName(editor.editor(), diagram.diagram());
				if (diagramNodeName.isEmpty()) {
					continue;
				}

				interpreterDiagramsList.append("qrm:/" + editor.editor() + "/"
						+ diagram.diagram() + "/" + diagramNodeName);
			}
		}

		mMainWindow->initInterpretedPlugins();

		foreach (const QString &interpreterIdString, interpreterDiagramsList) {
			// TODO: ???
			mMainWindow->models().repoControlApi().exterminate();
			mMainWindow->models().reinit();
			mMainWindow->loadPlugins();
			mMainWindow->createDiagram(interpreterIdString);
		}
	} else {
		show();
		editorManagerProxy.setProxyManager(new EditorManager());
	}
}

void StartWidget::createInterpretedDiagram()
{
	hide();
	ProxyEditorManager &editorManagerProxy = mMainWindow->editorManagerProxy();
	editorManagerProxy.setProxyManager(new InterpreterEditorManager(""));
	bool ok = false;
	QString name = QInputDialog::getText(this, tr("Enter the diagram name:"), tr("diagram name:")
			, QLineEdit::Normal, "", &ok);
	while (ok && name.isEmpty()) {
		name = QInputDialog::getText(this, tr("Enter the diagram name:"), tr("diagram name:")
				, QLineEdit::Normal, "", &ok);
	}

	if (ok) {
		QPair<Id, Id> editorAndDiagram = editorManagerProxy.createEditorAndDiagram(name);
		mMainWindow->addEditorElementsToPalette(editorAndDiagram.first, editorAndDiagram.second);
		mMainWindow->models().repoControlApi().exterminate();
		mMainWindow->models().reinit();
		mMainWindow->loadPlugins();
		mMainWindow->initInterpretedPlugins();
	} else {
		show();
		editorManagerProxy.setProxyManager(new EditorManager());
	}
}

void StartWidget::setVisibleForInterpreterButton(const bool visible)
{
	if (!visible) {
		/// @todo: For some reason setVisible on interpreter buttons still leaves them visible.
		/// This surely can be fixed and then setVisible(visible) call must be restored,
		/// but for now working it arround...
		delete mOpenInterpreterButton;
		delete mCreateInterpreterButton;
		mOpenInterpreterButton = nullptr;
		mCreateInterpreterButton = nullptr;
	}

	const int editorsCount = mMainWindow->editorManager().editors().count();
	QList<QPushButton *> toCentralize;
	bool needLayoutHorizontally = false;
	if (visible) {
		needLayoutHorizontally = editorsCount == 0;
		toCentralize << mCreateInterpreterButton << mOpenInterpreterButton;
	} else {
		needLayoutHorizontally = editorsCount == 1 && !mRecentProjectsWidget;
		toCentralize << mNewProjectButton << mOpenProjectButton;
	}

	if (needLayoutHorizontally) {
		for (QPushButton * const button : toCentralize) {
			centralizeButton(button);
		}

		mProjectsManagementLayout->setDirection(QBoxLayout::LeftToRight);
	}
}

void StartWidget::centralizeButton(QPushButton * const styledButton)
{
	if (!styledButton) {
		return;
	}

	QBoxLayout * const layout = static_cast<QBoxLayout *>(styledButton->layout());
	layout->setDirection(QBoxLayout::TopToBottom);
	QWidget * const icon = layout->itemAt(0)->widget();
	QLabel * const label = static_cast<QLabel *>(layout->itemAt(1)->widget());
	label->setAlignment(Qt::AlignHCenter);
	layout->setAlignment(icon, Qt::AlignHCenter | Qt::AlignBottom);
	layout->setAlignment(label, Qt::AlignHCenter | Qt::AlignTop);
	layout->activate();
	layout->update();
	styledButton->update();

	mProjectsManagementLayout->setAlignment(styledButton, Qt::AlignVCenter);
	const int index = mProjectsManagementLayout->indexOf(styledButton);
	mProjectsManagementLayout->setStretch(index, 10000);
}

void StartWidget::paintEvent(QPaintEvent *event)
{
	Q_UNUSED(event);

	QStyleOption styleOption;
	styleOption.initFrom(this);
	QPainter painter(this);
	style()->drawPrimitive(QStyle::PE_Widget, &styleOption, &painter, this);
}
<|endoftext|>