<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLPixelFormat.h"
#include "OgreRoot.h"
#include "OgreRenderSystem.h"
#include "OgreBitwise.h"

namespace Ogre  {
    //-----------------------------------------------------------------------------
    GLenum GLPixelUtil::getGLOriginFormat(PixelFormat mFormat)
    {
        switch(mFormat)
        {
            case PF_DEPTH:
                return GL_DEPTH_COMPONENT;
            case PF_A8:
                return GL_ALPHA;
            case PF_L8:
                return GL_LUMINANCE;
            case PF_L16:
                return GL_LUMINANCE;
            case PF_BYTE_LA:
                return GL_LUMINANCE_ALPHA;
            case PF_R3G3B2:
                return GL_RGB;
            case PF_A1R5G5B5:
                return GL_BGRA;
            case PF_R5G6B5:
                return GL_RGB;
            case PF_B5G6R5:
                return GL_BGR;
            case PF_A4R4G4B4:
                return GL_BGRA;
#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
            // Formats are in native endian, so R8G8B8 on little endian is
            // BGR, on big endian it is RGB.
            case PF_R8G8B8:
                return GL_RGB;
            case PF_B8G8R8:
                return GL_BGR;
#else
            case PF_R8G8B8:
                return GL_BGR;
            case PF_B8G8R8:
                return GL_RGB;
#endif
            case PF_X8R8G8B8:
            case PF_A8R8G8B8:
                return GL_BGRA;
            case PF_X8B8G8R8:
            case PF_A8B8G8R8:
                return GL_RGBA;
            case PF_B8G8R8A8:
                return GL_BGRA;
            case PF_R8G8B8A8:
                return GL_RGBA;
            case PF_A2R10G10B10:
                return GL_BGRA;
            case PF_A2B10G10R10:
                return GL_RGBA;
            case PF_FLOAT16_R:
                return GL_LUMINANCE;
            case PF_FLOAT16_GR:
                return GL_LUMINANCE_ALPHA;
            case PF_FLOAT16_RGB:
                return GL_RGB;
            case PF_FLOAT16_RGBA:
                return GL_RGBA;
            case PF_FLOAT32_R:
                return GL_LUMINANCE;
            case PF_FLOAT32_GR:
                return GL_LUMINANCE_ALPHA;
            case PF_FLOAT32_RGB:
                return GL_RGB;
            case PF_FLOAT32_RGBA:
                return GL_RGBA;
            case PF_SHORT_RGBA:
                return GL_RGBA;
            case PF_SHORT_RGB:
                return GL_RGB;
            case PF_SHORT_GR:
                return GL_LUMINANCE_ALPHA;
            case PF_DXT1:
                return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
            case PF_DXT3:
                 return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
            case PF_DXT5:
                 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
            default:
                return 0;
        }
    }
    //-----------------------------------------------------------------------------
    GLenum GLPixelUtil::getGLOriginDataType(PixelFormat mFormat)
    {
        switch(mFormat)
        {
            case PF_DEPTH:
                return GL_UNSIGNED_SHORT;
            case PF_A8:
            case PF_L8:
            case PF_R8G8B8:
            case PF_B8G8R8:
            case PF_BYTE_LA:
                return GL_UNSIGNED_BYTE;
            case PF_R3G3B2:
                return GL_UNSIGNED_BYTE_3_3_2;
            case PF_A1R5G5B5:
                return GL_UNSIGNED_SHORT_1_5_5_5_REV;
            case PF_R5G6B5:
            case PF_B5G6R5:
                return GL_UNSIGNED_SHORT_5_6_5;
            case PF_A4R4G4B4:
                return GL_UNSIGNED_SHORT_4_4_4_4_REV;
            case PF_L16:
                return GL_UNSIGNED_SHORT;
#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
            case PF_X8B8G8R8:
            case PF_A8B8G8R8:
                return GL_UNSIGNED_INT_8_8_8_8_REV;
            case PF_X8R8G8B8:
            case PF_A8R8G8B8:
                return GL_UNSIGNED_INT_8_8_8_8_REV;
            case PF_B8G8R8A8:
                return GL_UNSIGNED_BYTE;
            case PF_R8G8B8A8:
                return GL_UNSIGNED_BYTE;
#else
            case PF_X8B8G8R8:
            case PF_A8B8G8R8:
                return GL_UNSIGNED_BYTE;
            case PF_X8R8G8B8:
            case PF_A8R8G8B8:
                return GL_UNSIGNED_BYTE;
            case PF_B8G8R8A8:
                return GL_UNSIGNED_INT_8_8_8_8;
            case PF_R8G8B8A8:
                return GL_UNSIGNED_INT_8_8_8_8;
#endif
            case PF_A2R10G10B10:
                return GL_UNSIGNED_INT_2_10_10_10_REV;
            case PF_A2B10G10R10:
                return GL_UNSIGNED_INT_2_10_10_10_REV;
            case PF_FLOAT16_R:
            case PF_FLOAT16_GR:
            case PF_FLOAT16_RGB:
            case PF_FLOAT16_RGBA:
                return GL_HALF_FLOAT_ARB;
            case PF_FLOAT32_R:
            case PF_FLOAT32_GR:
            case PF_FLOAT32_RGB:
            case PF_FLOAT32_RGBA:
                return GL_FLOAT;
            case PF_SHORT_RGBA:
            case PF_SHORT_RGB:
            case PF_SHORT_GR:
                return GL_UNSIGNED_SHORT;
            default:
                return 0;
        }
    }

    GLenum GLPixelUtil::getGLInternalFormat(PixelFormat mFormat, bool hwGamma)
    {
        switch(mFormat) {
            case PF_DEPTH:
                return GL_DEPTH_COMPONENT16;
            case PF_L8:
                return GL_LUMINANCE8;
            case PF_L16:
                return GL_LUMINANCE16;
            case PF_A8:
                return GL_ALPHA8;
            case PF_A4L4:
                return GL_LUMINANCE4_ALPHA4;
            case PF_BYTE_LA:
                return GL_LUMINANCE8_ALPHA8;
            case PF_R3G3B2:
                return GL_R3_G3_B2;
            case PF_A1R5G5B5:
                return GL_RGB5_A1;
            case PF_R5G6B5:
            case PF_B5G6R5:
                return GL_RGB5;
            case PF_A4R4G4B4:
                return GL_RGBA4;
            case PF_R8G8B8:
            case PF_B8G8R8:
            case PF_X8B8G8R8:
            case PF_X8R8G8B8:
                if (hwGamma)
                    return GL_SRGB8;
                else
                    return GL_RGB8;
            case PF_A8R8G8B8:
            case PF_B8G8R8A8:
                if (hwGamma)
                    return GL_SRGB8_ALPHA8;
                else
                    return GL_RGBA8;
            case PF_A2R10G10B10:
            case PF_A2B10G10R10:
                return GL_RGB10_A2;
            case PF_FLOAT16_R:
                return GL_LUMINANCE16F_ARB;
            case PF_FLOAT16_RGB:
                return GL_RGB16F_ARB;
            case PF_FLOAT16_GR:
                return GL_LUMINANCE_ALPHA16F_ARB;
            case PF_FLOAT16_RGBA:
                return GL_RGBA16F_ARB;
            case PF_FLOAT32_R:
                return GL_LUMINANCE32F_ARB;
            case PF_FLOAT32_GR:
                return GL_LUMINANCE_ALPHA32F_ARB;
            case PF_FLOAT32_RGB:
                return GL_RGB32F_ARB;
            case PF_FLOAT32_RGBA:
                return GL_RGBA32F_ARB;
            case PF_SHORT_RGBA:
                return GL_RGBA16;
            case PF_SHORT_RGB:
                return GL_RGB16;
            case PF_SHORT_GR:
                return GL_LUMINANCE16_ALPHA16;
            case PF_DXT1:
                if (hwGamma)
                    return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
                else
                    return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
            case PF_DXT3:
                if (hwGamma)
                    return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
                else
                    return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
            case PF_DXT5:
                if (hwGamma)
                    return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
                else
                    return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
            default:
                return GL_NONE;
        }
    }

    GLenum GLPixelUtil::getClosestGLInternalFormat(PixelFormat mFormat, bool hwGamma)
    {
        GLenum format = getGLInternalFormat(mFormat, hwGamma);
        if(format==GL_NONE)
        {
            if (hwGamma)
                return GL_SRGB8;
            else
                return GL_RGBA8;
        }
        else
            return format;
    }

    //-----------------------------------------------------------------------------
    PixelFormat GLPixelUtil::getClosestOGREFormat(GLenum fmt)
    {
        switch(fmt)
        {
        case GL_DEPTH_COMPONENT16:
        case GL_DEPTH_COMPONENT24:
        case GL_DEPTH_COMPONENT32:
        case GL_DEPTH_COMPONENT32F:
        case GL_DEPTH_COMPONENT:
            return PF_DEPTH;
        case GL_LUMINANCE8:
            return PF_L8;
        case GL_LUMINANCE16:
            return PF_L16;
        case GL_ALPHA8:
            return PF_A8;
        case GL_LUMINANCE4_ALPHA4:
            // Unsupported by GL as input format, use the byte packed format
            return PF_BYTE_LA;
        case GL_LUMINANCE8_ALPHA8:
            return PF_BYTE_LA;
        case GL_R3_G3_B2:
            return PF_R3G3B2;
        case GL_RGB5_A1:
            return PF_A1R5G5B5;
        case GL_RGB5:
            return PF_R5G6B5;
        case GL_RGBA4:
            return PF_A4R4G4B4;
        case GL_RGB8:
        case GL_SRGB8:
            return PF_R8G8B8;
        case GL_RGBA8:
        case GL_SRGB8_ALPHA8:
            return PF_A8R8G8B8;
        case GL_RGB10_A2:
            return PF_A2R10G10B10;
        case GL_RGBA16:
            return PF_SHORT_RGBA;
        case GL_RGB16:
            return PF_SHORT_RGB;
        case GL_LUMINANCE16_ALPHA16:
            return PF_SHORT_GR;
        case GL_LUMINANCE_FLOAT16_ATI:
            return PF_FLOAT16_R;
        case GL_LUMINANCE_ALPHA_FLOAT16_ATI:
            return PF_FLOAT16_GR;
        case GL_LUMINANCE_ALPHA_FLOAT32_ATI:
            return PF_FLOAT32_GR;
        case GL_LUMINANCE_FLOAT32_ATI:
            return PF_FLOAT32_R;
        case GL_RGB_FLOAT16_ATI: // GL_RGB16F_ARB
            return PF_FLOAT16_RGB;
        case GL_RGBA_FLOAT16_ATI:
            return PF_FLOAT16_RGBA;
        case GL_RGB_FLOAT32_ATI:
            return PF_FLOAT32_RGB;
        case GL_RGBA_FLOAT32_ATI:
            return PF_FLOAT32_RGBA;
        case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
        case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
        case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
        case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
            return PF_DXT1;
        case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
        case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
            return PF_DXT3;
        case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
        case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
            return PF_DXT5;
        default:
            return PF_A8R8G8B8;
        };
    }
    //-----------------------------------------------------------------------------
    uint32 GLPixelUtil::optionalPO2(uint32 value)
    {
        const RenderSystemCapabilities *caps = Root::getSingleton().getRenderSystem()->getCapabilities();
        if(caps->hasCapability(RSC_NON_POWER_OF_2_TEXTURES))
            return value;
        else
            return Bitwise::firstPO2From(value);
    }

}
<commit_msg>GLPixelUtil: use a format table instead of multiple switch/ cases<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLPixelFormat.h"
#include "OgreRoot.h"
#include "OgreRenderSystem.h"
#include "OgreBitwise.h"

namespace Ogre  {

    struct GLPixelFormatDescription {
        GLenum format;
        GLenum type;
        GLenum internalFormat;
    };

    static GLPixelFormatDescription _pixelFormats[int(PF_COUNT)] = {
            {GL_NONE},                                           // PF_UNKNOWN
            {GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LUMINANCE8},     // PF_L8
            {GL_LUMINANCE, GL_UNSIGNED_SHORT, GL_LUMINANCE16},   // PF_L16
            {GL_ALPHA, GL_UNSIGNED_BYTE, GL_ALPHA8},             // PF_A8
            {GL_NONE},                                           // PF_A4L4
            {GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GL_LUMINANCE8_ALPHA8},// PF_BYTE_LA
            {GL_RGB, GL_UNSIGNED_SHORT_5_6_5, GL_RGB5},          // PF_R5G6B5
            {GL_BGR, GL_UNSIGNED_SHORT_5_6_5, GL_RGB5},          // PF_B5G6R5
            {GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_RGBA4},  // PF_A4R4G4B4
            {GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_RGB5_A1},// PF_A1R5G5B5
#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
            {GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8},                 // PF_R8G8B8
            {GL_BGR, GL_UNSIGNED_BYTE, GL_RGB8},                 // PF_B8G8R8
#else
            {GL_BGR, GL_UNSIGNED_BYTE, GL_RGB8},                 // PF_R8G8B8
            {GL_RGB, GL_UNSIGNED_BYTE, GL_RGB8},                 // PF_B8G8R8
#endif
            {GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, GL_RGBA8},    // PF_A8R8G8B8
            {GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, GL_RGBA8},    // PF_A8B8G8R8
            {GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA8},        // PF_B8G8R8A8
            {GL_NONE},                                           // PF_A2R10G10B10
            {GL_NONE},                                           // PF_A2B10G10R10
            {GL_NONE, GL_NONE, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT},// PF_DXT1
            {GL_NONE},                                           // PF_DXT2
            {GL_NONE, GL_NONE, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT},// PF_DXT3
            {GL_NONE},                                           // PF_DXT4
            {GL_NONE, GL_NONE, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT},// PF_DXT5
            {GL_RGB, GL_HALF_FLOAT, GL_RGB16F_ARB},              // PF_FLOAT16_RGB
            {GL_RGBA, GL_HALF_FLOAT, GL_RGBA16F_ARB},            // PF_FLOAT16_RGBA
            {GL_RGB, GL_FLOAT, GL_RGB32F_ARB},                   // PF_FLOAT32_RGB
            {GL_RGBA, GL_FLOAT, GL_RGBA32F_ARB},                 // PF_FLOAT32_RGBA
            {GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, GL_RGBA8},    // PF_X8R8G8B8
            {GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, GL_RGBA8},    // PF_X8B8G8R8
            {GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, GL_RGBA8},        // PF_R8G8B8A8
            {GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, GL_DEPTH_COMPONENT16}, // PF_DEPTH
            {GL_RGBA, GL_UNSIGNED_SHORT, GL_RGBA16},             // PF_SHORT_RGBA
            {GL_RGB, GL_UNSIGNED_BYTE_3_3_2, GL_R3_G3_B2},       // PF_R3G3B2
            {GL_LUMINANCE, GL_HALF_FLOAT, GL_LUMINANCE16F_ARB},  // PF_FLOAT16_R
            {GL_LUMINANCE, GL_FLOAT, GL_LUMINANCE32F_ARB},       // PF_FLOAT32_R
            {GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT, GL_LUMINANCE16_ALPHA16},// PF_SHORT_GR
            {GL_LUMINANCE_ALPHA, GL_HALF_FLOAT, GL_LUMINANCE_ALPHA16F_ARB}, // PF_FLOAT16_GR
            {GL_LUMINANCE_ALPHA, GL_FLOAT, GL_LUMINANCE_ALPHA32F_ARB},      // PF_FLOAT32_GR
            {GL_RGB, GL_UNSIGNED_SHORT, GL_RGB16},               // PF_SHORT_RGB
            // limited format support: the rest is PF_NONE
    };

    //-----------------------------------------------------------------------------
    GLenum GLPixelUtil::getGLOriginFormat(PixelFormat pf)
    {
        return _pixelFormats[pf].format;
    }
    //-----------------------------------------------------------------------------
    GLenum GLPixelUtil::getGLOriginDataType(PixelFormat pf)
    {
        return _pixelFormats[pf].type;
    }

    GLenum GLPixelUtil::getGLInternalFormat(PixelFormat pf, bool hwGamma)
    {
        GLenum ret = _pixelFormats[pf].internalFormat;

        if(!hwGamma)
            return ret;

        switch(ret)
        {
        case GL_RGB8:
            return GL_SRGB8;
        case GL_RGBA8:
            return GL_SRGB8_ALPHA8;
        case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
            return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
        case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
            return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
        case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
            return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
        default:
            return ret;
        }
    }

    GLenum GLPixelUtil::getClosestGLInternalFormat(PixelFormat format, bool hwGamma)
    {
        GLenum GLformat = getGLInternalFormat(format, hwGamma);
        if (GLformat == GL_NONE)
        {
            return hwGamma ? GL_SRGB8 : GL_RGBA8;
        }

        return GLformat;
    }

    //-----------------------------------------------------------------------------
    PixelFormat GLPixelUtil::getClosestOGREFormat(GLenum format)
    {
        switch(format)
        {
        case GL_DEPTH_COMPONENT24:
        case GL_DEPTH_COMPONENT32:
        case GL_DEPTH_COMPONENT32F:
        case GL_DEPTH_COMPONENT:
            return PF_DEPTH;
        case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
            return PF_DXT1;
        case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
            return PF_DXT3;
        case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
            return PF_DXT5;
        case GL_SRGB8:
        case GL_RGB8:  // prefer native endian byte format
            return PF_BYTE_RGB;
        case GL_SRGB8_ALPHA8:
        case GL_RGBA8:  // prefer native endian byte format
            return PF_BYTE_RGBA;
        };

        for(int pf = 0; pf < PF_COUNT; pf++) {
            if(_pixelFormats[pf].internalFormat == format)
                return (PixelFormat)pf;
        }

        return PF_BYTE_RGBA;
    }
    //-----------------------------------------------------------------------------
    uint32 GLPixelUtil::optionalPO2(uint32 value)
    {
        const RenderSystemCapabilities *caps = Root::getSingleton().getRenderSystem()->getCapabilities();
        if(caps->hasCapability(RSC_NON_POWER_OF_2_TEXTURES))
            return value;
        else
            return Bitwise::firstPO2From(value);
    }

}
<|endoftext|>


<commit_before>#include <cmath>
#include <cstdio>
#include <vector>
#include <deque>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <limits.h>

#define DEBUG   0
#define MAX_MN  8
#define BITS    3

char c[MAX_MN][MAX_MN];
int flag[256][256];

using namespace std;

int main()
{
#if DEBUG
    ifstream inFile;
    inFile.open("input.txt");
#endif

    unsigned int m, n, k;
#if DEBUG
    inFile >> m >> n >> k;
#else
    cin >> m >> n >> k;
#endif

    for (size_t i = 0; i < m; i++)
    {
        for (size_t j = 0; j < n; j++)
        {
#if DEBUG
            inFile >> c[i][j];
#else
            cin >> c[i][j];
#endif
        }
    }

    int pn = pow(2, n);

    for (size_t i = 0; i < pn; i++)
    {
        for (size_t j = 0; j < pn; j++)
        {
            flag[i][j] = -1;
        }
    }

    unsigned int ret = 0;
    map<unsigned int, unsigned int> cnt[2][pn][2 * m * n + 1];  // cnt[index][pn][difference]
    int index = 0;

    for (size_t i_m = 0; i_m < m; i_m++)
    {
        if (1 < i_m)
        {
            // clear all maps
            for (size_t i_pn = 0; i_pn < pn; i_pn++)
            {
                for (size_t difference = 0; difference < 2 * m * n + 1; difference++)
                {
                    cnt[index][i_pn][difference].clear();
                }
            }
        }

        for (size_t curr_pn = 0; curr_pn < pn; curr_pn++)
        {
            // i - new
            // 'D' - 0, 'T' - 1, 'U'
            bool nextI = false;
            for (size_t mask = 1, pos = 0; mask < pn; mask = mask << 1, pos++)
            {
                if ((curr_pn & mask) && 'D' == c[i_m][pos])
                {
                    nextI = true;
                    break;
                }

                if (0 == (curr_pn & mask) && 'T' == c[i_m][pos])
                {
                    nextI = true;
                    break;
                }
            }

            if (nextI)
            {
                continue;
            }

            if (0 == i_m)
            {
                unsigned int group = 0;
                unsigned int val = 0;
                int offset = 0;
                unsigned int difference = 0;
                set<unsigned int> new_group;
                for (size_t pos = 0, mask = 3; pos < n; pos++)
                {
                    if (curr_pn & (1 << pos))
                    {
                        offset ++;
                    }
                    else
                    {
                        offset --;
                    }

                    if (0 == pos)
                    {
                        val = group;
                        new_group.insert(group);
                    }
                    else
                    {
                        if ((curr_pn & mask) == mask || 0 == (curr_pn & mask))
                        {
                            // 11 or 00
                            val |= group << (pos * BITS);
                        }
                        else
                        {
                            group++;
                            val |= group << (pos * BITS);
                            new_group.insert(group);
                        }

                        mask <<= 1;
                    }
                }

                difference = m * n + offset;

                if (0 == m - 1 && 2 < new_group.size())
                {
                }
                else
                {
                    if (0 == m - 1)
                    {
                        ret++;
                    }
                    else
                    {
                        cnt[index][curr_pn][difference].insert(pair<unsigned int, unsigned int>(val, 1));
                    }
                }
            }
            else
            {
                int offset = 0;
                for (size_t pos = 0; pos < n; pos++)
                {
                    if (curr_pn & (1 << pos))
                    {
                        offset ++;
                    }
                    else
                    {
                        offset --;
                    }
                }

                for (size_t last_pn = 0; last_pn < pn; last_pn++)
                {
                    if (0 <= flag[last_pn][curr_pn])
                    {
                        if (0 == flag[last_pn][curr_pn])
                        {
                            continue;
                        }
                    }
                    else
                    {
                        bool nextJ = false;
                        // j for 1 - index
                        for (size_t pos = 1, mask = 3; pos < n; pos++, mask <<= 1)
                        {
                            if (0 == (curr_pn & mask) || mask == (curr_pn & mask))
                            {
                                if ((curr_pn & mask) == (last_pn & mask))
                                {
                                    // have 2x2 square
                                    nextJ = true;
                                    flag[last_pn][curr_pn] = 0;
                                    flag[curr_pn][last_pn] = 0;
                                    break;
                                }
                            }
                        }

                        if (nextJ)
                        {
                            continue;
                        }

                        flag[last_pn][curr_pn] = 1;
                        flag[curr_pn][last_pn] = 1;
                    }

                    for (size_t difference = 0; difference < 2 * m * n + 1; difference++)
                    {
                        if (0 < cnt[1 - index][last_pn][difference].size())
                        {
                            for (map<unsigned int, unsigned int>::iterator it = cnt[1 - index][last_pn][difference].begin(); it != cnt[1 - index][last_pn][difference].end(); it++)
                            {
                                unsigned int old_val = it->first;
                                unsigned int new_val = 0;
                                unsigned char old_c[n];
                                unsigned char new_c[n];
                                char old_v[n];
                                char new_v[n];
                                set<unsigned int> old_group;
                                set<unsigned int> toNext;
                                set<unsigned int> new_group;
                                unsigned int already_end = old_val >> (BITS * n);

                                for (size_t pos = 0; pos < n; pos++)
                                {
                                    if (curr_pn & (1 << pos))
                                    {
                                        new_c[pos] = 1;
                                    }
                                    else
                                    {
                                        new_c[pos] = 0;
                                    }

                                    if (last_pn & (1 << pos))
                                    {
                                        old_c[pos] = 1;
                                    }
                                    else
                                    {
                                        old_c[pos] = 0;
                                    }

                                    old_v[pos] = (old_val & (7 << (BITS * pos))) >> (BITS * pos);
                                    new_v[pos] = -1;

                                    old_group.insert(old_v[pos]);

                                    if (old_c[pos] == new_c[pos])
                                    {
                                        toNext.insert(old_v[pos]);
                                    }
                                }

                                for (size_t pos = 0; pos < n; pos++)
                                {
                                    if (0 == pos)
                                    {
                                        if (old_c[pos] == new_c[pos])
                                        {
                                            new_v[pos] = old_v[pos];
                                            new_group.insert(new_v[pos]);
                                        }
                                    }
                                    else
                                    {
                                        if (new_c[pos] == new_c[pos - 1])
                                        {
                                            if (0 <= new_v[pos - 1])
                                            {
                                                // 连续相同
                                                if (new_c[pos] == old_c[pos])
                                                {
                                                    if (old_v[pos] == new_v[pos - 1])
                                                    {
                                                        new_v[pos] = old_v[pos];
                                                    }
                                                    else
                                                    {
                                                        if (new_group.find(old_v[pos]) != new_group.end())
                                                        {
                                                            // old_v[pos] 已经存在
                                                            for (int p = pos + 1; p < n; p++)
                                                            {
                                                                if (old_v[p] == new_v[pos - 1])
                                                                {
                                                                    old_v[p] = old_v[pos];
                                                                }
                                                            }

                                                            new_group.erase(new_v[pos - 1]);
                                                            new_v[pos] = old_v[pos];
                                                            for (int p = 0; p <= pos - 1; p++)
                                                            {
                                                                if (new_v[p] == new_v[pos - 1])
                                                                {
                                                                    new_v[p] = new_v[pos];
                                                                }
                                                            }
                                                        }
                                                        else
                                                        {
                                                            new_v[pos] = new_v[pos - 1];
                                                            for (int p = pos + 1; p < n; p++)
                                                            {
                                                                if (old_v[p] == old_v[pos])
                                                                {
                                                                    old_v[p] = new_v[pos];
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    new_v[pos] = new_v[pos - 1];
                                                }
                                            }
                                            else
                                            {
                                                if (old_c[pos] == new_c[pos])
                                                {
                                                    new_v[pos] = old_v[pos];
                                                    new_group.insert(new_v[pos]);
                                                    for (int p = pos - 1; p >= 0; p--)
                                                    {
                                                        if (new_c[p] != new_c[pos])
                                                        {
                                                            break;
                                                        }
                                                        else
                                                        {
                                                            new_v[p] = new_v[pos];
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            if (old_c[pos] == new_c[pos])
                                            {
                                                new_v[pos] = old_v[pos];
                                                new_group.insert(new_v[pos]);
                                            }
                                        }
                                    }
                                }

                                for (unsigned int p = 0, v = 0; p < n; p++)
                                {
                                    if (0 > new_v[p])
                                    {
                                        while (new_group.find(v) != new_group.end())
                                        {
                                            v ++;
                                        }

                                        new_group.insert(v);

                                        // no use
                                        while (0 > new_v[p])
                                        {
                                            new_v[p] = v;
                                            p++;

                                            if (p >= n)
                                            {
                                                break;
                                            }

                                            if (new_c[p] != new_c[p - 1])
                                            {
                                                p --;
                                                break;
                                            }
                                        }
                                    }
                                }

                                already_end += old_group.size() - toNext.size();

                                if (1 < already_end)
                                {
                                    continue;
                                }
                                else if (1 == already_end)
                                {
                                    if (1 < new_group.size())
                                    {
                                        continue;
                                    }
                                }

                                if (i_m == m - 1)
                                {
                                    if (2 < new_group.size() + already_end)
                                    {
                                    }
                                    else
                                    {
                                        if (m * n - k <= difference + offset && m * n + k >= difference + offset)
                                        {
                                            ret += it->second;
                                        }
                                    }
                                    continue;
                                }

                                char v = 0;
                                char fv[n];
                                for (size_t pos = 0; pos < n; pos++)
                                {
                                    if (0 <= new_v[pos])
                                    {
                                        for (size_t p = pos + 1; p < n; p++)
                                        {
                                            if (new_v[p] == new_v[pos])
                                            {
                                                fv[p] = v;
                                                new_v[p] = -1;
                                            }
                                        }

                                        fv[pos] = v;
                                        new_v[pos] = -1;

                                        v ++;
                                    }
                                }

                                for (size_t p = 0; p < n; p++)
                                {
                                    new_val |= fv[p] << (BITS * p);
                                }

                                new_val |= already_end << (BITS * n);

                                if (!cnt[index][curr_pn][difference + offset][new_val])
                                {
                                    cnt[index][curr_pn][difference + offset][new_val] = it->second;
                                }
                                else
                                {
                                    cnt[index][curr_pn][difference + offset][new_val] += it->second;
                                }
                            }
                        }
                    }
                }
            }
        }

        index = 1 - index;
    }

    cout << ret << endl;

#if DEBUG
    inFile.close();
#endif

    return 0;
}

<commit_msg>250.00 points<commit_after>#include <cmath>
#include <cstdio>
#include <vector>
#include <deque>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <limits.h>

#define DEBUG   0
#define MAX_MN  8
#define BITS    3

char c[MAX_MN][MAX_MN];
int flag[256][256];

using namespace std;

int main()
{
#if DEBUG
    ifstream inFile;
    inFile.open("input.txt");
#endif

    unsigned int m, n, k;
#if DEBUG
    inFile >> m >> n >> k;
#else
    cin >> m >> n >> k;
#endif

    for (size_t i = 0; i < m; i++)
    {
        for (size_t j = 0; j < n; j++)
        {
#if DEBUG
            inFile >> c[i][j];
#else
            cin >> c[i][j];
#endif
        }
    }

    int pn = pow(2, n);

    for (size_t i = 0; i < pn; i++)
    {
        for (size_t j = 0; j < pn; j++)
        {
            flag[i][j] = -1;
        }
    }

    unsigned int ret = 0;
    map<unsigned int, unsigned int> cnt[2][pn][2 * m * n + 1]; // cnt[index][pn][difference]
    int index = 0;

    map<unsigned int, int> vtv[pn][pn];
    map<unsigned int, bool> canAdd[pn][pn];

    for (size_t i_m = 0; i_m < m; i_m++)
    {
        if (1 < i_m)
        {
            // clear all maps
            for (size_t i_pn = 0; i_pn < pn; i_pn++)
            {
                for (size_t difference = 0; difference < 2 * m * n + 1; difference++)
                {
                    cnt[index][i_pn][difference].clear();
                }
            }
        }

        for (size_t curr_pn = 0; curr_pn < pn; curr_pn++)
        {
            // i - new
            // 'D' - 0, 'T' - 1, 'U'
            bool nextI = false;
            for (size_t mask = 1, pos = 0; mask < pn; mask = mask << 1, pos++)
            {
                if ((curr_pn & mask) && 'D' == c[i_m][pos])
                {
                    nextI = true;
                    break;
                }

                if (0 == (curr_pn & mask) && 'T' == c[i_m][pos])
                {
                    nextI = true;
                    break;
                }
            }

            if (nextI)
            {
                continue;
            }

            if (0 == i_m)
            {
                unsigned int group = 0;
                unsigned int val = 0;
                int offset = 0;
                unsigned int difference = 0;
                set<unsigned int> new_group;
                for (size_t pos = 0, mask = 3; pos < n; pos++)
                {
                    if (curr_pn & (1 << pos))
                    {
                        offset++;
                    }
                    else
                    {
                        offset--;
                    }

                    if (0 == pos)
                    {
                        val = group;
                        new_group.insert(group);
                    }
                    else
                    {
                        if ((curr_pn & mask) == mask || 0 == (curr_pn & mask))
                        {
                            // 11 or 00
                            val |= group << (pos * BITS);
                        }
                        else
                        {
                            group++;
                            val |= group << (pos * BITS);
                            new_group.insert(group);
                        }

                        mask <<= 1;
                    }
                }

                difference = m * n + offset;

                if (0 == m - 1 && 2 < new_group.size())
                {
                }
                else
                {
                    if (0 == m - 1)
                    {
                        ret++;
                    }
                    else
                    {
                        cnt[index][curr_pn][difference].insert(pair<unsigned int, unsigned int>(val, 1));
                    }
                }
            }
            else
            {
                int offset = 0;
                for (size_t pos = 0; pos < n; pos++)
                {
                    if (curr_pn & (1 << pos))
                    {
                        offset++;
                    }
                    else
                    {
                        offset--;
                    }
                }

                for (size_t last_pn = 0; last_pn < pn; last_pn++)
                {
                    if (0 <= flag[last_pn][curr_pn])
                    {
                        if (0 == flag[last_pn][curr_pn])
                        {
                            continue;
                        }
                    }
                    else
                    {
                        bool nextJ = false;
                        // j for 1 - index
                        for (size_t pos = 1, mask = 3; pos < n; pos++, mask <<= 1)
                        {
                            if (0 == (curr_pn & mask) || mask == (curr_pn & mask))
                            {
                                if ((curr_pn & mask) == (last_pn & mask))
                                {
                                    // have 2x2 square
                                    nextJ = true;
                                    flag[last_pn][curr_pn] = 0;
                                    flag[curr_pn][last_pn] = 0;
                                    break;
                                }
                            }
                        }

                        if (nextJ)
                        {
                            continue;
                        }

                        flag[last_pn][curr_pn] = 1;
                        flag[curr_pn][last_pn] = 1;
                    }

                    for (size_t difference = 0; difference < 2 * m * n + 1; difference++)
                    {
                        if (0 < cnt[1 - index][last_pn][difference].size())
                        {
                            for (map<unsigned int, unsigned int>::iterator it = cnt[1 - index][last_pn][difference].begin(); it != cnt[1 - index][last_pn][difference].end(); it++)
                            {
                                unsigned int old_val = it->first;
                                unsigned int new_val = 0;

                                if (vtv[last_pn][curr_pn].find(old_val) == vtv[last_pn][curr_pn].end())
                                {
                                    unsigned char old_c[n];
                                    unsigned char new_c[n];
                                    char old_v[n];
                                    char new_v[n];
                                    set<unsigned int> old_group;
                                    set<unsigned int> toNext;
                                    set<unsigned int> new_group;
                                    unsigned int already_end = old_val >> (BITS * n);

                                    for (size_t pos = 0; pos < n; pos++)
                                    {
                                        if (curr_pn & (1 << pos))
                                        {
                                            new_c[pos] = 1;
                                        }
                                        else
                                        {
                                            new_c[pos] = 0;
                                        }

                                        if (last_pn & (1 << pos))
                                        {
                                            old_c[pos] = 1;
                                        }
                                        else
                                        {
                                            old_c[pos] = 0;
                                        }

                                        old_v[pos] = (old_val & (7 << (BITS * pos))) >> (BITS * pos);
                                        new_v[pos] = -1;

                                        old_group.insert(old_v[pos]);

                                        if (old_c[pos] == new_c[pos])
                                        {
                                            toNext.insert(old_v[pos]);
                                        }
                                    }

                                    for (size_t pos = 0; pos < n; pos++)
                                    {
                                        if (0 == pos)
                                        {
                                            if (old_c[pos] == new_c[pos])
                                            {
                                                new_v[pos] = old_v[pos];
                                                new_group.insert(new_v[pos]);
                                            }
                                        }
                                        else
                                        {
                                            if (new_c[pos] == new_c[pos - 1])
                                            {
                                                if (0 <= new_v[pos - 1])
                                                {
                                                    // 连续相同
                                                    if (new_c[pos] == old_c[pos])
                                                    {
                                                        if (old_v[pos] == new_v[pos - 1])
                                                        {
                                                            new_v[pos] = old_v[pos];
                                                        }
                                                        else
                                                        {
                                                            if (new_group.find(old_v[pos]) != new_group.end())
                                                            {
                                                                // old_v[pos] 已经存在
                                                                for (int p = pos + 1; p < n; p++)
                                                                {
                                                                    if (old_v[p] == new_v[pos - 1])
                                                                    {
                                                                        old_v[p] = old_v[pos];
                                                                    }
                                                                }

                                                                new_group.erase(new_v[pos - 1]);
                                                                new_v[pos] = old_v[pos];
                                                                for (int p = 0; p <= pos - 1; p++)
                                                                {
                                                                    if (new_v[p] == new_v[pos - 1])
                                                                    {
                                                                        new_v[p] = new_v[pos];
                                                                    }
                                                                }
                                                            }
                                                            else
                                                            {
                                                                new_v[pos] = new_v[pos - 1];
                                                                for (int p = pos + 1; p < n; p++)
                                                                {
                                                                    if (old_v[p] == old_v[pos])
                                                                    {
                                                                        old_v[p] = new_v[pos];
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        new_v[pos] = new_v[pos - 1];
                                                    }
                                                }
                                                else
                                                {
                                                    if (old_c[pos] == new_c[pos])
                                                    {
                                                        new_v[pos] = old_v[pos];
                                                        new_group.insert(new_v[pos]);
                                                        for (int p = pos - 1; p >= 0; p--)
                                                        {
                                                            if (new_c[p] != new_c[pos])
                                                            {
                                                                break;
                                                            }
                                                            else
                                                            {
                                                                new_v[p] = new_v[pos];
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                if (old_c[pos] == new_c[pos])
                                                {
                                                    new_v[pos] = old_v[pos];
                                                    new_group.insert(new_v[pos]);
                                                }
                                            }
                                        }
                                    }

                                    for (unsigned int p = 0, v = 0; p < n; p++)
                                    {
                                        if (0 > new_v[p])
                                        {
                                            while (new_group.find(v) != new_group.end())
                                            {
                                                v++;
                                            }

                                            new_group.insert(v);

                                            // no use
                                            while (0 > new_v[p])
                                            {
                                                new_v[p] = v;
                                                p++;

                                                if (p >= n)
                                                {
                                                    break;
                                                }

                                                if (new_c[p] != new_c[p - 1])
                                                {
                                                    p--;
                                                    break;
                                                }
                                            }
                                        }
                                    }

                                    already_end += old_group.size() - toNext.size();

                                    if (1 < already_end)
                                    {
                                        vtv[last_pn][curr_pn].insert(pair<unsigned int, int>(old_val, -1));
                                        continue;
                                    }
                                    else if (1 == already_end)
                                    {
                                        if (1 < new_group.size())
                                        {
                                            vtv[last_pn][curr_pn].insert(pair<unsigned int, int>(old_val, -1));
                                            continue;
                                        }
                                    }

                                    if (2 >= new_group.size() + already_end)
                                    {
                                        canAdd[last_pn][curr_pn].insert(pair<unsigned int, bool>(old_val, true));
                                    }

                                    if (i_m == m - 1)
                                    {
                                        if (2 < new_group.size() + already_end)
                                        {
                                        }
                                        else
                                        {
                                            if (m * n - k <= difference + offset && m * n + k >= difference + offset)
                                            {
                                                ret += it->second;
                                            }
                                        }
                                        continue;
                                    }

                                    char v = 0;
                                    char fv[n];
                                    for (size_t pos = 0; pos < n; pos++)
                                    {
                                        if (0 <= new_v[pos])
                                        {
                                            for (size_t p = pos + 1; p < n; p++)
                                            {
                                                if (new_v[p] == new_v[pos])
                                                {
                                                    fv[p] = v;
                                                    new_v[p] = -1;
                                                }
                                            }

                                            fv[pos] = v;
                                            new_v[pos] = -1;

                                            v++;
                                        }
                                    }

                                    for (size_t p = 0; p < n; p++)
                                    {
                                        new_val |= fv[p] << (BITS * p);
                                    }

                                    new_val |= already_end << (BITS * n);

                                    vtv[last_pn][curr_pn].insert(pair<unsigned int, int>(old_val, new_val));
                                }
                                else
                                {
                                    if (0 > vtv[last_pn][curr_pn].find(old_val)->second)
                                    {
                                        continue;
                                    }
                                    else
                                    {
                                        if (i_m == m - 1)
                                        {
                                            if (canAdd[last_pn][curr_pn].find(old_val) != canAdd[last_pn][curr_pn].end())
                                            {
                                                if (m * n - k <= difference + offset && m * n + k >= difference + offset)
                                                {
                                                    ret += it->second;
                                                }
                                            }
                                            continue;
                                        }
                                        else
                                        {
                                            new_val = vtv[last_pn][curr_pn].find(old_val)->second;
                                        }
                                    }
                                }

                                if (!cnt[index][curr_pn][difference + offset][new_val])
                                {
                                    cnt[index][curr_pn][difference + offset][new_val] = it->second;
                                }
                                else
                                {
                                    cnt[index][curr_pn][difference + offset][new_val] += it->second;
                                }
                            }
                        }
                    }
                }
            }
        }

        index = 1 - index;
    }

    cout << ret << endl;

#if DEBUG
    inFile.close();
#endif

    return 0;
}
<|endoftext|>


<commit_before>#include "SoloFeature.h"
#include "streamFuns.h"
#include "TimeFunctions.h"
#include "serviceFuns.cpp"

#define def_MarkNoColor  (uint32) -1

void collapseUMIwith1MMlowHalf(uint32 *rGU, uint32 umiArrayStride, uint32 umiMaskLow, uint32 nU0, uint32 &nU1, uint32 &nU2, uint32 &nC, vector<array<uint32,2>> &vC)
{
    const uint32 bitTop=1<<31;
    const uint32 bitTopMask=~bitTop;

    for (uint32 iu=0; iu<umiArrayStride*nU0; iu+=umiArrayStride) {//each UMI
        uint32 iuu=iu+umiArrayStride;
        for (; iuu<umiArrayStride*nU0; iuu+=umiArrayStride) {//compare to all UMIs down

            uint32 uuXor=rGU[iu] ^ rGU[iuu];

            if ( uuXor > umiMaskLow)
                break; //upper half is different

            if (uuXor >> (__builtin_ctz(uuXor)/2)*2 > 3) //shift by even number of trailing zeros
                continue;//>1MM

            //1MM UMI

            //graph coloring
            if ( rGU[iu+2] == def_MarkNoColor && rGU[iuu+2] == def_MarkNoColor ) {//no color
                //new color
                rGU[iu+2] = nC;
                rGU[iuu+2] = nC;
                ++nC;
                nU1 -= 2;//subtract the duplicated UMIs
            } else if ( rGU[iu+2] == def_MarkNoColor ) {
                rGU[iu+2] = rGU[iuu+2];
                --nU1;//subtract the duplicated UMIs
            } else if ( rGU[iuu+2] == def_MarkNoColor ) {
                rGU[iuu+2] = rGU[iu+2];
                --nU1;//subtract the duplicated UMIs
            } else {//both color
                if (rGU[iuu+2] != rGU[iu+2]) {//color conflict
                    //uint32 p[2]={rGU[iu+2],rGU[iuu+2]};
                    vC.push_back({rGU[iu+2],rGU[iuu+2]});
                    //vC.push_back({rGU[iuu+2],rGU[iu+2]});
                };
            };

            //directional collapse
            if ( (rGU[iuu+1] & bitTop) == 0 && (rGU[iu+1] & bitTopMask)>(2*(rGU[iuu+1] & bitTopMask)-1) ) {//iuu is duplicate of iu
                rGU[iuu+1] |= bitTop;
                --nU2;//subtract the duplicated UMIs
            } else if ( (rGU[iu+1] & bitTop) == 0 && (rGU[iuu+1] & bitTopMask)>(2*(rGU[iu+1] & bitTopMask)-1) ) {//iu is duplicate of iuu
                rGU[iu+1] |= bitTop;
                --nU2;//subtract the duplicated UMIs
            };
        };
    };
};

void graphDepthFirstSearch(uint32 n, vector<bool> &nodeVisited, vector<vector<uint32>> &nodeEdges) {
    for (const auto &nn : nodeEdges[n]) {
        if (!nodeVisited[nn]) {
            nodeVisited[nn]=true;
            graphDepthFirstSearch(nn,nodeVisited,nodeEdges);
        };
    };
};

uint32 graphNumberOfConnectedComponents(uint32 N, vector<array<uint32,2>> V) {//find number of connected components
    //N=number of nodes
    //V=edges, list of connected nodes, each pair of nodes listed once
    //simple recursive DFS

    //sort
//     qsort(V.data(),V.size(),2*sizeof(uint32),funCompareNumbers<uint32>);
    if (V.size()==0)
        return N;

    vector<vector<uint32>> nodeEdges (N);
    for (uint32 ii=0; ii<V.size(); ii++) {
        nodeEdges[V[ii][0]].push_back(V[ii][1]);
        nodeEdges[V[ii][1]].push_back(V[ii][0]);
    };

    vector<bool> nodeVisited(N,false);

    uint32 nConnComp=0;
    for (uint32 ii=0; ii<N; ii++) {
        //if (V[ii].size()==0) {//this node is not connected, no need to check. Save time beacuse this happens often
        //wrong: should be
        if (nodeEdges[ii].size()==0) {//this node is not connected, no need to check. Save time beacuse this happens often
           ++nConnComp;
           continue;
        };
        if (!nodeVisited[ii]) {
            nodeVisited[ii]=true;
            ++nConnComp;
            graphDepthFirstSearch(ii,nodeVisited,nodeEdges);
        };
    };
    return nConnComp;
};

void SoloFeature::collapseUMI(uint32 *rGU, uint32 rN, uint32 &nGenes, uint32 &nUtot, uint32 *umiArray) {//iCB = CB to collapse, nReads=number of reads for this CB

    rGUarrayStride=2; //

    qsort(rGU,rN,rGUarrayStride*sizeof(uint32),funCompareNumbers<uint32>); //sort by gene number

    //compact reads per gene
    uint32 gid1=-1;//current gID
    nGenes=0; //number of genes
    uint32 *gID = new uint32[min(Trans.nGe,rN)+1]; //gene IDS
    uint32 *gReadS = new uint32[min(Trans.nGe,rN)+1]; //start of gene reads TODO: allocate this array in the 2nd half of rGU
    for (uint32 iR=0; iR<rN*rGUarrayStride; iR+=rGUarrayStride) {
        if (rGU[iR]!=gid1) {//record gene boundary
            gReadS[nGenes]=iR;
            gid1=rGU[iR];
            gID[nGenes]=gid1;
            ++nGenes;
        };
        //rGU[iR]=rGU[iR+1]; //shift UMIs
        //rGU[iR+1] storage this will be used later for counting
    };
    gReadS[nGenes]=rGUarrayStride*rN;//so that gReadS[nGenes]-gReadS[nGenes-1] is the number of reads for nGenes, see below in qsort

    uint32 *nUg = new uint32[nGenes*3];//3 types of counts
    nUtot=0;
    for (uint32 iG=0; iG<nGenes; iG++) {//collapse UMIs for each gene
        uint32 *rGU1=rGU+gReadS[iG];

//         qsort(rGU1+1, (gReadS[iG+1]-gReadS[iG])/rGUarrayStride, rGUarrayStride*sizeof(uint32), funCompareNumbers<uint32>);
        //        +1 to point to UMIs
        qsort(rGU1, (gReadS[iG+1]-gReadS[iG])/rGUarrayStride, rGUarrayStride*sizeof(uint32), funCompareTypeShift<uint32,1>);

        //exact collapse
        uint32 iR1=-umiArrayStride; //number of distinct UMIs for this gene
        uint32 u1=-1;
        for (uint32 iR=1; iR<gReadS[iG+1]-gReadS[iG]; iR+=rGUarrayStride) {//count and collapse identical UMIs
            if (rGU1[iR]!=u1) {
                iR1 += umiArrayStride;
                u1=rGU1[iR];
                umiArray[iR1]=u1;
                umiArray[iR1+1]=0;
                umiArray[iR1+2]=def_MarkNoColor; //marks no color for graph
            };
            umiArray[iR1+1]++;
            //if ( umiArray[iR1+1]>nRumiMax) nRumiMax=umiArray[iR1+1];
        };
        uint32 nU0=(iR1+umiArrayStride)/umiArrayStride;

        //collapse with 1MM
        uint32 nU1=nU0, nU2=nU0;//2 types of 1MM collapsing
        uint32 nC=0; //graph colors
        vector<array<uint32,2>> vC;//color connections

        collapseUMIwith1MMlowHalf(umiArray, umiArrayStride, pSolo.umiMaskLow, nU0, nU1, nU2, nC, vC);

        //exchange low and high half of UMIs, re-sort, and look for 1MM again
        for (uint32 iu=0; iu<umiArrayStride*nU0; iu+=umiArrayStride) {
            uint32 high=umiArray[iu]>>(pSolo.umiL);
            umiArray[iu] &= pSolo.umiMaskLow; //remove high
            umiArray[iu] <<= (pSolo.umiL); //move low to high
            umiArray[iu] |= high; //add high
        };
        qsort(umiArray, nU0, umiArrayStride*sizeof(uint32), funCompareNumbers<uint32>);
        collapseUMIwith1MMlowHalf(umiArray, umiArrayStride, pSolo.umiMaskLow, nU0, nU1, nU2, nC, vC);

        nUg[3*iG]=nU0;
        nUg[3*iG+1]=nU1+graphNumberOfConnectedComponents(nC,vC);
        nUg[3*iG+2]=nU2;
        nUtot+=nUg[3*iG+1];
    };

    uint32 *rGUp=rGU;//first place where rGU is overwritten with gene counts. Before it's intact though sorted differently.
    for (uint32 iG=0; iG<nGenes; iG++) {//output for all genes
        rGUp[0]=gID[iG];
        rGUp[1]=nUg[3*iG];
        if (nUg[3*iG]>1) {//record 2 more counts
            rGUp[2]=nUg[3*iG+1];
            rGUp[3]=nUg[3*iG+2];
            rGUp += 4;
        } else {//only one count recorded, save space
            rGUp += 2;
        };
    };
    //cout << nRumiMax << '\n';

};
<commit_msg>Collapse UMI: Added tracking of the connected components common color.<commit_after>#include "SoloFeature.h"
#include "streamFuns.h"
#include "TimeFunctions.h"
#include "serviceFuns.cpp"

#define def_MarkNoColor  (uint32) -1

void collapseUMIwith1MMlowHalf(uint32 *rGU, uint32 umiArrayStride, uint32 umiMaskLow, uint32 nU0, uint32 &nU1, uint32 &nU2, uint32 &nC, vector<array<uint32,2>> &vC)
{
    const uint32 bitTop=1<<31;
    const uint32 bitTopMask=~bitTop;

    for (uint32 iu=0; iu<umiArrayStride*nU0; iu+=umiArrayStride) {//each UMI
        uint32 iuu=iu+umiArrayStride;
        for (; iuu<umiArrayStride*nU0; iuu+=umiArrayStride) {//compare to all UMIs down

            uint32 uuXor=rGU[iu] ^ rGU[iuu];

            if ( uuXor > umiMaskLow)
                break; //upper half is different

            if (uuXor >> (__builtin_ctz(uuXor)/2)*2 > 3) //shift by even number of trailing zeros
                continue;//>1MM

            //1MM UMI

            //graph coloring
            if ( rGU[iu+2] == def_MarkNoColor && rGU[iuu+2] == def_MarkNoColor ) {//no color
                //new color
                rGU[iu+2] = nC;
                rGU[iuu+2] = nC;
                ++nC;
                nU1 -= 2;//subtract the duplicated UMIs
            } else if ( rGU[iu+2] == def_MarkNoColor ) {
                rGU[iu+2] = rGU[iuu+2];
                --nU1;//subtract the duplicated UMIs
            } else if ( rGU[iuu+2] == def_MarkNoColor ) {
                rGU[iuu+2] = rGU[iu+2];
                --nU1;//subtract the duplicated UMIs
            } else {//both color
                if (rGU[iuu+2] != rGU[iu+2]) {//color conflict
                    //uint32 p[2]={rGU[iu+2],rGU[iuu+2]};
                    vC.push_back({rGU[iu+2],rGU[iuu+2]});
                    //vC.push_back({rGU[iuu+2],rGU[iu+2]});
                };
            };

            //directional collapse
            if ( (rGU[iuu+1] & bitTop) == 0 && (rGU[iu+1] & bitTopMask)>(2*(rGU[iuu+1] & bitTopMask)-1) ) {//iuu is duplicate of iu
                rGU[iuu+1] |= bitTop;
                --nU2;//subtract the duplicated UMIs
            } else if ( (rGU[iu+1] & bitTop) == 0 && (rGU[iuu+1] & bitTopMask)>(2*(rGU[iu+1] & bitTopMask)-1) ) {//iu is duplicate of iuu
                rGU[iu+1] |= bitTop;
                --nU2;//subtract the duplicated UMIs
            };
        };
    };
};

void graphDepthFirstSearch(uint32 n, vector<bool> &nodeVisited, vector<vector<uint32>> &nodeEdges, vector <uint32> &nodeColor) {
    for (const auto &nn : nodeEdges[n]) {
        if (!nodeVisited[nn]) {
            nodeVisited[nn]=true;
            nodeColor[nn]=nodeColor[n];
            graphDepthFirstSearch(nn,nodeVisited,nodeEdges,nodeColor);
        };
    };
};

uint32 graphNumberOfConnectedComponents(uint32 N, vector<array<uint32,2>> V) {//find number of connected components
    //N=number of nodes
    //V=edges, list of connected nodes, each pair of nodes listed once
    //simple recursive DFS

    //sort
//     qsort(V.data(),V.size(),2*sizeof(uint32),funCompareNumbers<uint32>);
    if (V.size()==0)
        return N;

    vector<vector<uint32>> nodeEdges (N);
    for (uint32 ii=0; ii<V.size(); ii++) {
        nodeEdges[V[ii][0]].push_back(V[ii][1]);
        nodeEdges[V[ii][1]].push_back(V[ii][0]);
    };

    vector<bool> nodeVisited(N,false);
    vector<uint32> nodeColor(N); //new color (connected component) for each node (each original color)

    uint32 nConnComp=0;
    for (uint32 ii=0; ii<N; ii++) {
        //if (V[ii].size()==0) {//this node is not connected, no need to check. Save time beacuse this happens often
        //wrong: should be
        if (nodeEdges[ii].size()==0) {//this node is not connected, no need to check. Save time beacuse this happens often
            ++nConnComp;
            continue;
        };
        if (!nodeVisited[ii]) {
            nodeVisited[ii]=true;
            ++nConnComp;
            nodeColor[ii]=ii;
            graphDepthFirstSearch(ii,nodeVisited,nodeEdges,nodeColor);
        };
    };
    return nConnComp;
};

void SoloFeature::collapseUMI(uint32 *rGU, uint32 rN, uint32 &nGenes, uint32 &nUtot, uint32 *umiArray) {//iCB = CB to collapse, nReads=number of reads for this CB

    rGUarrayStride=2; //

    qsort(rGU,rN,rGUarrayStride*sizeof(uint32),funCompareNumbers<uint32>); //sort by gene number

    //compact reads per gene
    uint32 gid1=-1;//current gID
    nGenes=0; //number of genes
    uint32 *gID = new uint32[min(Trans.nGe,rN)+1]; //gene IDS
    uint32 *gReadS = new uint32[min(Trans.nGe,rN)+1]; //start of gene reads TODO: allocate this array in the 2nd half of rGU
    for (uint32 iR=0; iR<rN*rGUarrayStride; iR+=rGUarrayStride) {
        if (rGU[iR]!=gid1) {//record gene boundary
            gReadS[nGenes]=iR;
            gid1=rGU[iR];
            gID[nGenes]=gid1;
            ++nGenes;
        };
        //rGU[iR]=rGU[iR+1]; //shift UMIs
        //rGU[iR+1] storage this will be used later for counting
    };
    gReadS[nGenes]=rGUarrayStride*rN;//so that gReadS[nGenes]-gReadS[nGenes-1] is the number of reads for nGenes, see below in qsort

    uint32 *nUg = new uint32[nGenes*3];//3 types of counts
    nUtot=0;
    for (uint32 iG=0; iG<nGenes; iG++) {//collapse UMIs for each gene
        uint32 *rGU1=rGU+gReadS[iG];

//         qsort(rGU1+1, (gReadS[iG+1]-gReadS[iG])/rGUarrayStride, rGUarrayStride*sizeof(uint32), funCompareNumbers<uint32>);
        //        +1 to point to UMIs
        qsort(rGU1, (gReadS[iG+1]-gReadS[iG])/rGUarrayStride, rGUarrayStride*sizeof(uint32), funCompareTypeShift<uint32,1>);

        //exact collapse
        uint32 iR1=-umiArrayStride; //number of distinct UMIs for this gene
        uint32 u1=-1;
        for (uint32 iR=1; iR<gReadS[iG+1]-gReadS[iG]; iR+=rGUarrayStride) {//count and collapse identical UMIs
            if (rGU1[iR]!=u1) {
                iR1 += umiArrayStride;
                u1=rGU1[iR];
                umiArray[iR1]=u1;
                umiArray[iR1+1]=0;
                umiArray[iR1+2]=def_MarkNoColor; //marks no color for graph
            };
            umiArray[iR1+1]++;
            //if ( umiArray[iR1+1]>nRumiMax) nRumiMax=umiArray[iR1+1];
        };
        uint32 nU0=(iR1+umiArrayStride)/umiArrayStride;

        //collapse with 1MM
        uint32 nU1=nU0, nU2=nU0;//2 types of 1MM collapsing
        uint32 nC=0; //graph colors
        vector<array<uint32,2>> vC;//color connections

        collapseUMIwith1MMlowHalf(umiArray, umiArrayStride, pSolo.umiMaskLow, nU0, nU1, nU2, nC, vC);

        //exchange low and high half of UMIs, re-sort, and look for 1MM again
        for (uint32 iu=0; iu<umiArrayStride*nU0; iu+=umiArrayStride) {
            uint32 high=umiArray[iu]>>(pSolo.umiL);
            umiArray[iu] &= pSolo.umiMaskLow; //remove high
            umiArray[iu] <<= (pSolo.umiL); //move low to high
            umiArray[iu] |= high; //add high
        };
        qsort(umiArray, nU0, umiArrayStride*sizeof(uint32), funCompareNumbers<uint32>);
        collapseUMIwith1MMlowHalf(umiArray, umiArrayStride, pSolo.umiMaskLow, nU0, nU1, nU2, nC, vC);

        nUg[3*iG]=nU0;
        nUg[3*iG+1]=nU1+graphNumberOfConnectedComponents(nC,vC);
        nUg[3*iG+2]=nU2;
        nUtot+=nUg[3*iG+1];
    };

    uint32 *rGUp=rGU;//first place where rGU is overwritten with gene counts. Before it's intact though sorted differently.
    for (uint32 iG=0; iG<nGenes; iG++) {//output for all genes
        rGUp[0]=gID[iG];
        rGUp[1]=nUg[3*iG];
        if (nUg[3*iG]>1) {//record 2 more counts
            rGUp[2]=nUg[3*iG+1];
            rGUp[3]=nUg[3*iG+2];
            rGUp += 4;
        } else {//only one count recorded, save space
            rGUp += 2;
        };
    };
    //cout << nRumiMax << '\n';

};
<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id:

#include <BALL/VIEW/DIALOGS/atomOverview.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/common.h>
#include <BALL/VIEW/KERNEL/message.h>
#include <BALL/KERNEL/PTE.h>

namespace BALL
{
	namespace VIEW
	{

AtomOverview::AtomOverview(QWidget* parent, const char* name)
	:	QDialog(parent),
		Ui_AtomOverviewData(),
		parent_(0),
		only_selection_(false)
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "new AtomOverview " << this << std::endl;
#endif
	setupUi(this);

	setObjectName(name);
	setModal(true);
	setSizeGripEnabled(true);
	processor_.setTable(table);
	apply_processor_.setTable(table);
	apply_processor_.setMainControl(VIEW::getMainControl());

	connect(table, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(itemChanged(QTableWidgetItem*)));
	connect(table, SIGNAL(itemClicked(QTableWidgetItem*)), this, SLOT(itemActivated(QTableWidgetItem*)));

	hide();
}

AtomOverview::~AtomOverview()
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "deleting AtomOverview " << this << std::endl;
#endif
}

void AtomOverview::setParent(AtomContainer* ac)
{
	parent_ = ac;

	if (parent_ == 0 ||
			VIEW::getMainControl() == 0)
	{
		BALLVIEW_DEBUG;
		return;
	}

	table->clear();
	table->setColumnCount(6);
	table->setHorizontalHeaderItem(0, new QTableWidgetItem("Atom"));
	table->setHorizontalHeaderItem(1, new QTableWidgetItem("Element"));
	table->setHorizontalHeaderItem(2, new QTableWidgetItem("Type"));
	table->setHorizontalHeaderItem(3, new QTableWidgetItem("Radius"));
	table->setHorizontalHeaderItem(4, new QTableWidgetItem("Charge"));
	table->setHorizontalHeaderItem(5, new QTableWidgetItem("FCharge"));
	ignore_ = true;
	processor_.showOnlySelection(only_selection_);
	parent_->apply(processor_);
	ignore_ = false;
	showMaximized();
}

void AtomOverview::accept()
{
	QDialog::accept();
	apply_processor_.showOnlySelection(only_selection_);
	parent_->apply(apply_processor_);
	VIEW::getMainControl()->update(*parent_);
	VIEW::getMainControl()->sendMessage(*new NewSelectionMessage());
	VIEW::getMainControl()->setStatusbarText("Applied values", true);
}

AtomOverview::OverviewProcessor::OverviewProcessor()
	: UnaryProcessor<Composite>(),
	  table_(0)
{
}

AtomOverview::OverviewProcessor::OverviewProcessor(const OverviewProcessor&)
	: UnaryProcessor<Composite>(),
		table_(0)
{
}

AtomOverview::OverviewProcessor::~OverviewProcessor()
{
}

Processor::Result AtomOverview::OverviewProcessor::operator() (Composite& composite)
{
	if (RTTI::isKindOf<Atom>(composite))
	{
		Atom* atom = dynamic_cast<Atom*>(&composite);
		if (only_selection_ && !atom->isSelected()) return Processor::CONTINUE;

		Position r = table_->rowCount();
		table_->setRowCount(r + 1);

		// Name
		Position c = 0;
		String s = atom->getFullName(Atom::ADD_VARIANT_EXTENSIONS_AND_ID);
		QTableWidgetItem* item = new QTableWidgetItem(s.c_str());
		table_->setItem(r, c, item);
		item->setCheckState(Qt::Checked);
		if (!atom->isSelected()) item->setCheckState(Qt::Unchecked);

		// Element
		s = atom->getElement().getSymbol();
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));
		if (atom->getElement().isUnknown()) table_->item(c, r)->setBackgroundColor(Qt::red);

		// Type
		s = atom->getType();
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));
 		if (atom->getType() == -1) table_->item(r, c)->setBackgroundColor(Qt::red);

		// Radius
		float f = atom->getRadius();
		s = String(f);
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));
		if (f <= 0.0 || f > 4.0) table_->item(r, c)->setBackgroundColor(Qt::red);

		// Charge
		f = atom->getCharge();
		s = String(f);
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));

		// calculate min and max possible charge
		Position p = (Position) atom->getElement().getGroup();
		Index min = -8;
		Index max = 8;

		// HauptGruppe
		if (p< 3 || p > 13)
		{
			if (p > 12) p-= 10;
			min = -p;
			max = 8 - p;
		}

		if (f > (float) max ||
				f < (float) min)
		{
			table_->item(r, c)->setBackgroundColor(Qt::red);
		}

		// FCharge
		f = atom->getFormalCharge();
		s = String(f);
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));

	}

	return Processor::CONTINUE;
}

void AtomOverview::itemChanged(QTableWidgetItem* item)
{
	if (ignore_ | item == 0) return;
  Index c = table->column(item);

	String s = ascii(item->text());
	if (c == 1)
	{
		Element e = PTE.getElement(s);
		if (e.isUnknown()) restoreItem_(item);
		return;
	}

	try
	{
		// Atom Type
		if (c == 2)
		{
			Index i = s.toInt();
			if (i < -1) restoreItem_(item);
			return;
		}

		float f = s.toFloat();

		// Radius
		if (c == 3 && (f <= 0.0))
		{
			restoreItem_(item);
			return;
		}

		// c == 4: charge already cared by toFloat!
	}
	catch(...)
	{
		restoreItem_(item);
	}
}

void AtomOverview::restoreItem_(QTableWidgetItem* item)
{
	if (item == 0 || table->column(item) <= 0) return;
	item->setText(item_backup_.c_str());
}

void AtomOverview::itemActivated(QTableWidgetItem* item)
{
	if (item == 0 || table->column(item) <= 0)
	{
		return;
	}

	item_backup_ = ascii(item->text());
}

AtomOverview::ApplyProcessor::ApplyProcessor()
	: UnaryProcessor<Composite>(),
	  table_(0)
{
}

AtomOverview::ApplyProcessor::ApplyProcessor(const ApplyProcessor&)
	: UnaryProcessor<Composite>(),
		table_(0)
{
}

AtomOverview::ApplyProcessor::~ApplyProcessor()
{
}

Processor::Result AtomOverview::ApplyProcessor::operator() (Composite& composite)
{
	if (RTTI::isKindOf<Atom>(composite))
	{
		Atom* atom = dynamic_cast<Atom*>(&composite);

		if (only_selection_ && !atom->isSelected()) return Processor::CONTINUE;

		String s;

		bool selected = (table_->item(row_, 0)->checkState() == Qt::Checked);
		if (selected != atom->isSelected())
		{
			if (selected) main_control_->selectCompositeRecursive(atom, true);
			else 					main_control_->deselectCompositeRecursive(atom, true);
		}

		s = ascii(table_->item(row_, 1)->text());
		atom->setElement(PTE.getElement(s));

		s = ascii(table_->item(row_, 2)->text());
		atom->setType(s.toInt());

		s = ascii(table_->item(row_, 3)->text());
		atom->setRadius(s.toFloat());

		s = ascii(table_->item(row_, 4)->text());
		atom->setCharge(s.toFloat());

		s = ascii(table_->item(row_, 5)->text());
		atom->setFormalCharge(s.toInt());

		row_ ++;
	}

	return Processor::CONTINUE;
}

} } // namespaces
<commit_msg>Fix a compiler warning in AtomOverview<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id:

#include <BALL/VIEW/DIALOGS/atomOverview.h>
#include <BALL/VIEW/KERNEL/mainControl.h>
#include <BALL/VIEW/KERNEL/common.h>
#include <BALL/VIEW/KERNEL/message.h>
#include <BALL/KERNEL/PTE.h>

namespace BALL
{
	namespace VIEW
	{

AtomOverview::AtomOverview(QWidget* parent, const char* name)
	:	QDialog(parent),
		Ui_AtomOverviewData(),
		parent_(0),
		only_selection_(false)
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "new AtomOverview " << this << std::endl;
#endif
	setupUi(this);

	setObjectName(name);
	setModal(true);
	setSizeGripEnabled(true);
	processor_.setTable(table);
	apply_processor_.setTable(table);
	apply_processor_.setMainControl(VIEW::getMainControl());

	connect(table, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(itemChanged(QTableWidgetItem*)));
	connect(table, SIGNAL(itemClicked(QTableWidgetItem*)), this, SLOT(itemActivated(QTableWidgetItem*)));

	hide();
}

AtomOverview::~AtomOverview()
{
#ifdef BALL_VIEW_DEBUG
	Log.error() << "deleting AtomOverview " << this << std::endl;
#endif
}

void AtomOverview::setParent(AtomContainer* ac)
{
	parent_ = ac;

	if (parent_ == 0 ||
			VIEW::getMainControl() == 0)
	{
		BALLVIEW_DEBUG;
		return;
	}

	table->clear();
	table->setColumnCount(6);
	table->setHorizontalHeaderItem(0, new QTableWidgetItem("Atom"));
	table->setHorizontalHeaderItem(1, new QTableWidgetItem("Element"));
	table->setHorizontalHeaderItem(2, new QTableWidgetItem("Type"));
	table->setHorizontalHeaderItem(3, new QTableWidgetItem("Radius"));
	table->setHorizontalHeaderItem(4, new QTableWidgetItem("Charge"));
	table->setHorizontalHeaderItem(5, new QTableWidgetItem("FCharge"));
	ignore_ = true;
	processor_.showOnlySelection(only_selection_);
	parent_->apply(processor_);
	ignore_ = false;
	showMaximized();
}

void AtomOverview::accept()
{
	QDialog::accept();
	apply_processor_.showOnlySelection(only_selection_);
	parent_->apply(apply_processor_);
	VIEW::getMainControl()->update(*parent_);
	VIEW::getMainControl()->sendMessage(*new NewSelectionMessage());
	VIEW::getMainControl()->setStatusbarText("Applied values", true);
}

AtomOverview::OverviewProcessor::OverviewProcessor()
	: UnaryProcessor<Composite>(),
	  table_(0)
{
}

AtomOverview::OverviewProcessor::OverviewProcessor(const OverviewProcessor&)
	: UnaryProcessor<Composite>(),
		table_(0)
{
}

AtomOverview::OverviewProcessor::~OverviewProcessor()
{
}

Processor::Result AtomOverview::OverviewProcessor::operator() (Composite& composite)
{
	if (RTTI::isKindOf<Atom>(composite))
	{
		Atom* atom = dynamic_cast<Atom*>(&composite);
		if (only_selection_ && !atom->isSelected()) return Processor::CONTINUE;

		Position r = table_->rowCount();
		table_->setRowCount(r + 1);

		// Name
		Position c = 0;
		String s = atom->getFullName(Atom::ADD_VARIANT_EXTENSIONS_AND_ID);
		QTableWidgetItem* item = new QTableWidgetItem(s.c_str());
		table_->setItem(r, c, item);
		item->setCheckState(Qt::Checked);
		if (!atom->isSelected()) item->setCheckState(Qt::Unchecked);

		// Element
		s = atom->getElement().getSymbol();
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));
		if (atom->getElement().isUnknown()) table_->item(c, r)->setBackgroundColor(Qt::red);

		// Type
		s = atom->getType();
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));
 		if (atom->getType() == -1) table_->item(r, c)->setBackgroundColor(Qt::red);

		// Radius
		float f = atom->getRadius();
		s = String(f);
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));
		if (f <= 0.0 || f > 4.0) table_->item(r, c)->setBackgroundColor(Qt::red);

		// Charge
		f = atom->getCharge();
		s = String(f);
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));

		// calculate min and max possible charge
		Position p = (Position) atom->getElement().getGroup();
		Index min = -8;
		Index max = 8;

		// HauptGruppe
		if (p< 3 || p > 13)
		{
			if (p > 12) p-= 10;
			min = -p;
			max = 8 - p;
		}

		if (f > (float) max ||
				f < (float) min)
		{
			table_->item(r, c)->setBackgroundColor(Qt::red);
		}

		// FCharge
		f = atom->getFormalCharge();
		s = String(f);
		c++;
		table_->setItem(r, c, new QTableWidgetItem(s.c_str()));

	}

	return Processor::CONTINUE;
}

void AtomOverview::itemChanged(QTableWidgetItem* item)
{
	if (ignore_ || (item == 0)) return;
	Index c = table->column(item);

	String s = ascii(item->text());
	if (c == 1)
	{
		Element e = PTE.getElement(s);
		if (e.isUnknown()) restoreItem_(item);
		return;
	}

	try
	{
		// Atom Type
		if (c == 2)
		{
			Index i = s.toInt();
			if (i < -1) restoreItem_(item);
			return;
		}

		float f = s.toFloat();

		// Radius
		if (c == 3 && (f <= 0.0))
		{
			restoreItem_(item);
			return;
		}

		// c == 4: charge already cared by toFloat!
	}
	catch(...)
	{
		restoreItem_(item);
	}
}

void AtomOverview::restoreItem_(QTableWidgetItem* item)
{
	if (item == 0 || table->column(item) <= 0) return;
	item->setText(item_backup_.c_str());
}

void AtomOverview::itemActivated(QTableWidgetItem* item)
{
	if (item == 0 || table->column(item) <= 0)
	{
		return;
	}

	item_backup_ = ascii(item->text());
}

AtomOverview::ApplyProcessor::ApplyProcessor()
	: UnaryProcessor<Composite>(),
	  table_(0)
{
}

AtomOverview::ApplyProcessor::ApplyProcessor(const ApplyProcessor&)
	: UnaryProcessor<Composite>(),
		table_(0)
{
}

AtomOverview::ApplyProcessor::~ApplyProcessor()
{
}

Processor::Result AtomOverview::ApplyProcessor::operator() (Composite& composite)
{
	if (RTTI::isKindOf<Atom>(composite))
	{
		Atom* atom = dynamic_cast<Atom*>(&composite);

		if (only_selection_ && !atom->isSelected()) return Processor::CONTINUE;

		String s;

		bool selected = (table_->item(row_, 0)->checkState() == Qt::Checked);
		if (selected != atom->isSelected())
		{
			if (selected) main_control_->selectCompositeRecursive(atom, true);
			else 					main_control_->deselectCompositeRecursive(atom, true);
		}

		s = ascii(table_->item(row_, 1)->text());
		atom->setElement(PTE.getElement(s));

		s = ascii(table_->item(row_, 2)->text());
		atom->setType(s.toInt());

		s = ascii(table_->item(row_, 3)->text());
		atom->setRadius(s.toFloat());

		s = ascii(table_->item(row_, 4)->text());
		atom->setCharge(s.toFloat());

		s = ascii(table_->item(row_, 5)->text());
		atom->setFormalCharge(s.toInt());

		row_ ++;
	}

	return Processor::CONTINUE;
}

} } // namespaces
<|endoftext|>