예제 #1
0
void ColorPalette::draw_selected_color_value( void )
{
    const kvs::RGBColor current_color = this->color();
    const int r = static_cast<int>( current_color.r() );
    const int g = static_cast<int>( current_color.g() );
    const int b = static_cast<int>( current_color.b() );
    const float h = this->get_H_value();
    const float s = this->get_S_value();
    const float v = this->get_V_value();

    char R[10]; sprintf( R, "R: %3d", r );
    char G[10]; sprintf( G, "G: %3d", g );
    char B[10]; sprintf( B, "B: %3d", b );

    char H[10]; sprintf( H, "H: %3d", static_cast<int>( h * 255.0f + 0.5f ) );
    char S[10]; sprintf( S, "S: %3d", static_cast<int>( s * 255.0f + 0.5f ) );
    char V[10]; sprintf( V, "V: %3d", static_cast<int>( v * 255.0f + 0.5f ) );

    int x = m_selected_color_box.x0();
    int y = m_selected_color_box.y1() + 10;
    BaseClass::draw_text( x, y += BaseClass::characterHeight(), R );
    BaseClass::draw_text( x, y += BaseClass::characterHeight(), G );
    BaseClass::draw_text( x, y += BaseClass::characterHeight(), B );
    BaseClass::draw_text( x, y += BaseClass::characterHeight(), "" );
    BaseClass::draw_text( x, y += BaseClass::characterHeight(), H );
    BaseClass::draw_text( x, y += BaseClass::characterHeight(), S );
    BaseClass::draw_text( x, y += BaseClass::characterHeight(), V );
}
예제 #2
0
/*===========================================================================*/
void SphereGlyph::draw_element( const kvs::RGBColor& color, const kvs::UInt8 opacity )
{
    KVS_GL_CALL( glColor4ub( color.r(), color.g(), color.b(), opacity ) );

    const GLdouble radius = 0.5;
    gluSphere( m_sphere, radius, static_cast<GLint>(m_nslices), static_cast<GLint>(m_nstacks) );
}
예제 #3
0
/*===========================================================================*/
void ColorMapPalette::mouseMoveEvent( kvs::MouseEvent* event )
{
    if ( !BaseClass::isShown() ) return;

    if ( BaseClass::isActive() )
    {
        if ( m_palette.isActive() )
        {
            // Color map palette geometry.
            const int x0 = m_palette.x0();
            const int x1 = m_palette.x1();
            const int y0 = m_palette.y0();
            const int y1 = m_palette.y1();

            // Current mouse cursor position.
            const int x = event->x();
            const int y = event->y();
            const int old_x = kvs::Math::Clamp( m_pressed_position.x(), x0, x1 );
            const int old_y = kvs::Math::Clamp( m_pressed_position.y(), y0, y1 );
            const int new_x = kvs::Math::Clamp( x,  x0, x1 );
            const int new_y = kvs::Math::Clamp( y,  y0, y1 );
            m_pressed_position.set( x, y );

            const float old_ratio = static_cast<float>( y1 - old_y ) / ( y1 - y0 );
            const float new_ratio = static_cast<float>( y1 - new_y ) / ( y1 - y0 );
            const float diff_ratio = new_ratio - old_ratio;

            const float resolution = static_cast<float>( m_color_map.resolution() );
            const int old_index = static_cast<int>( ( old_x - x0 ) * resolution / ( x1 - x0 ) + 0.5f );
            const int new_index = static_cast<int>( ( new_x - x0 ) * resolution / ( x1 - x0 ) + 0.5f );
            const float diff_index = static_cast<float>( new_index - old_index );

            if ( m_color_palette ) m_drawing_color = m_color_palette->color();
            const kvs::RGBColor drawing_color = m_drawing_color;
            const int begin_index = kvs::Math::Min( old_index, new_index );
            const int end_index = kvs::Math::Max( old_index, new_index );
            kvs::UInt8* data = const_cast<kvs::UInt8*>( m_color_map.table().data() );
            kvs::UInt8* pdata = data + begin_index * 3;
            for ( int i = begin_index; i < end_index; i++, pdata += 3 )
            {
                const float ratio = ( i - old_index ) * diff_ratio / diff_index + old_ratio;
                pdata[0] = static_cast<kvs::UInt8>( drawing_color.r() * ratio + pdata[0] * ( 1 - ratio ) );
                pdata[1] = static_cast<kvs::UInt8>( drawing_color.g() * ratio + pdata[1] * ( 1 - ratio ) );
                pdata[2] = static_cast<kvs::UInt8>( drawing_color.b() * ratio + pdata[2] * ( 1 - ratio ) );
            }

            const size_t width = m_color_map.resolution();
            m_texture.bind();
            m_texture.load( width, data );
            m_texture.unbind();
        }

        BaseClass::screen()->redraw();
    }
}
예제 #4
0
/*===========================================================================*/
void SphereGlyph::attach_point( const kvs::PointObject* point )
{
    m_point = point;

    const size_t nvertices = point->numberOfVertices();

    BaseClass::setCoords( point->coords() );

    if ( BaseClass::directionMode() == BaseClass::DirectionByNormal )
    {
        if ( point->numberOfNormals() != 0 )
        {
            BaseClass::setDirections( point->normals() );
        }
    }

    if ( point->numberOfSizes() == 1 )
    {
        const kvs::Real32 size = point->size();
        kvs::ValueArray<kvs::Real32> sizes( nvertices );
        for ( size_t i = 0; i < nvertices; i++ ) sizes[i] = size;
        BaseClass::setSizes( sizes );
    }
    else
    {
        BaseClass::setSizes( point->sizes() );
    }

    if ( point->numberOfColors() == 1 )
    {
        const kvs::RGBColor color = point->color();
        kvs::ValueArray<kvs::UInt8> colors( nvertices * 3 );
        for ( size_t i = 0, j = 0; i < nvertices; i++, j += 3 )
        {
            colors[j]   = color.r();
            colors[j+1] = color.g();
            colors[j+2] = color.b();
        }
        BaseClass::setColors( colors );
    }
    else
    {
        BaseClass::setColors( point->colors() );
    }

    const kvs::UInt8 opacity = static_cast<kvs::UInt8>( 255 );
    kvs::ValueArray<kvs::UInt8> opacities( nvertices );
    for ( size_t i = 0; i < nvertices; i++ ) opacities[i] = opacity;
    BaseClass::setOpacities( opacities );
}
예제 #5
0
/*===========================================================================*/
void ColorMapPalette::mousePressEvent( kvs::MouseEvent* event )
{
    if ( !BaseClass::isShown() ) return;

    if ( BaseClass::contains( event->x(), event->y() ) )
    {
        BaseClass::screen()->disable();
        BaseClass::activate();

        if ( m_palette.contains( event->x(), event->y(), true ) )
        {
            m_palette.activate();

            // Color map palette geometry.
            const int x0 = m_palette.x0();
            const int x1 = m_palette.x1();
            const int y0 = m_palette.y0();
            const int y1 = m_palette.y1();

            // Current mouse cursor position.
            const int x = event->x();
            const int y = event->y();
            m_pressed_position.set( x, y );

            const float resolution = static_cast<float>( m_color_map.resolution() );
            const float ratio = static_cast<float>( y1 - y ) / ( y1 - y0 );
            const int index = static_cast<int>( ( x - x0 ) * resolution / ( x1 - x0 ) + 0.5f );

            // Update the color data.
            if ( m_color_palette ) m_drawing_color = m_color_palette->color();
            const kvs::RGBColor drawing_color = m_drawing_color;
            kvs::UInt8* data = const_cast<kvs::UInt8*>( m_color_map.table().data() );
            kvs::UInt8* pdata = data;
            pdata = data + index * 3;
            pdata[0] = static_cast<kvs::UInt8>( drawing_color.r() * ratio + pdata[0] * ( 1 - ratio ) );
            pdata[1] = static_cast<kvs::UInt8>( drawing_color.g() * ratio + pdata[1] * ( 1 - ratio ) );
            pdata[2] = static_cast<kvs::UInt8>( drawing_color.b() * ratio + pdata[2] * ( 1 - ratio ) );

            const size_t width = m_color_map.resolution();
            m_texture.bind();
            m_texture.load( width, data );
            m_texture.unbind();
        }

        BaseClass::screen()->redraw();
    }
}
예제 #6
0
kvs::ColorMap DivergingColorMap::Create(
    const kvs::RGBColor& rgb1,
    const kvs::RGBColor& rgb2,
    const size_t resolution )
{
    kvs::ColorMap::Table table( 3 * resolution );
    kvs::UInt8* color = table.data();
    for ( size_t i = 0; i < resolution; i++ )
    {
        const kvs::Real32 ratio = kvs::Real32(i) / ( resolution - 1 );
        const kvs::RGBColor rgb = ::Interpolate( rgb1, rgb2, ratio );
        *( color++ ) = rgb.r();
        *( color++ ) = rgb.g();
        *( color++ ) = rgb.b();
    }

    return kvs::ColorMap( table );
}
예제 #7
0
void ColorPalette::draw_selected_color_box( void )
{
    const int x0 = m_selected_color_box.x0();
    const int y0 = m_selected_color_box.y0();
    const int x1 = m_selected_color_box.x1();
    const int y1 = m_selected_color_box.y1();

    const kvs::RGBColor current_color = this->color();

    glBegin( GL_QUADS );
    glColor3ub( current_color.r(), current_color.g(), current_color.b() );
    glVertex2i( x1, y1 );
    glVertex2i( x0, y1 );
    glVertex2i( x0, y0 );
    glVertex2i( x1, y0 );
    glEnd();

    // Draw border.
    ::DrawRectangle( m_selected_color_box, 1, m_upper_edge_color, m_lower_edge_color );
}
예제 #8
0
void ColorPalette::draw_selected_color_value()
{
    const kvs::RGBColor current_color = this->color();
    const int r = static_cast<int>( current_color.r() );
    const int g = static_cast<int>( current_color.g() );
    const int b = static_cast<int>( current_color.b() );

    char R[10]; sprintf( R, "R: %3d", r );
    char G[10]; sprintf( G, "G: %3d", g );
    char B[10]; sprintf( B, "B: %3d", b );

    int x = m_selected_color_box.x0();
    int y = m_selected_color_box.y1() + 10;
    const float height = BaseClass::painter().fontMetrics().height();
    const kvs::Font font = BaseClass::painter().font();
    BaseClass::painter().font().setStyleToRegular();
    BaseClass::painter().drawText( kvs::Vec2( x, y += height ), R );
    BaseClass::painter().drawText( kvs::Vec2( x, y += height ), G );
    BaseClass::painter().drawText( kvs::Vec2( x, y += height ), B );
    BaseClass::painter().setFont( font );
}
예제 #9
0
/*===========================================================================*/
void ScatterPlotRenderer::exec( kvs::ObjectBase* object, kvs::Camera* camera, kvs::Light* light )
{
    kvs::IgnoreUnusedVariable( light );

    kvs::TableObject* table = kvs::TableObject::DownCast( object );
    if ( !m_has_point_color ) if ( table->numberOfColumns() < 3 ) m_has_point_color = true;

    BaseClass::startTimer();

    glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );

    ::BeginDraw();

    glDisable( GL_LIGHTING );
    glEnable( GL_POINT_SMOOTH );

    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    // X and Y values.
    const kvs::AnyValueArray& x_values = table->column(0);
    const kvs::AnyValueArray& y_values = table->column(1);
    const kvs::Real64 x_min_value = table->minValue(0);
    const kvs::Real64 x_max_value = table->maxValue(0);
    const kvs::Real64 y_min_value = table->minValue(1);
    const kvs::Real64 y_max_value = table->maxValue(1);

    const int x0 = m_left_margin;
    const int x1 = camera->windowWidth() - m_right_margin;
    const int y0 = m_top_margin;
    const int y1 = camera->windowHeight() - m_bottom_margin;

    // Draw background.
    if ( m_background_color.a() > 0.0f )
    {
        const GLubyte r = static_cast<GLubyte>( m_background_color.r() );
        const GLubyte g = static_cast<GLubyte>( m_background_color.g() );
        const GLubyte b = static_cast<GLubyte>( m_background_color.b() );
        const GLubyte a = static_cast<GLubyte>( m_background_color.a() * 255.0f );
        glBegin( GL_QUADS );
        glColor4ub( r, g, b, a );
        glVertex2i( x0, y0 );
        glVertex2i( x1, y0 );
        glVertex2i( x1, y1 );
        glVertex2i( x0, y1 );
        glEnd();
    }

    const kvs::UInt8 opacity = m_point_opacity;
    const kvs::Real32 size = m_point_size;
    if ( m_has_point_color )
    {
        const kvs::RGBColor color = m_point_color;

        glPointSize( size );
        glBegin( GL_POINTS );
        glColor4ub( color.r(), color.g(), color.b(), opacity );
        const kvs::Real64 x_ratio = kvs::Real64( x1 - x0 ) / ( x_max_value - x_min_value );
        const kvs::Real64 y_ratio = kvs::Real64( y1 - y0 ) / ( y_max_value - y_min_value );
        const size_t nrows = table->numberOfRows();
        for ( size_t i = 0; i < nrows; i++ )
        {
            if ( !table->insideRange( i ) ) continue;

            const kvs::Real64 x_value = x_values[i].to<kvs::Real64>();
            const kvs::Real64 y_value = y_values[i].to<kvs::Real64>();
            const double x = x0 + ( x_value - x_min_value ) * x_ratio;
            const double y = y1 - ( y_value - y_min_value ) * y_ratio;
            glVertex2d( x, y );
        }
        glEnd();
    }
    else
    {
        const float color_axis_min_value = static_cast<float>( table->minValue(2) );
        const float color_axis_max_value = static_cast<float>( table->maxValue(2) );
        const kvs::AnyValueArray& color_axis_values = table->column(2);
        m_color_map.setRange( color_axis_min_value, color_axis_max_value );

        glPointSize( size );
        glBegin( GL_POINTS );
        const kvs::Real64 x_ratio = kvs::Real64( x1 - x0 ) / ( x_max_value - x_min_value );
        const kvs::Real64 y_ratio = kvs::Real64( y1 - y0 ) / ( y_max_value - y_min_value );
        const size_t nrows = table->numberOfRows();
        for ( size_t i = 0; i < nrows; i++ )
        {
            if ( !table->insideRange( i ) ) continue;

            const kvs::Real64 color_value = color_axis_values[i].to<kvs::Real64>();
            const kvs::RGBColor color = m_color_map.at( static_cast<float>( color_value) );
            glColor4ub( color.r(), color.g(), color.b(), opacity );

            const kvs::Real64 x_value = x_values[i].to<kvs::Real64>();
            const kvs::Real64 y_value = y_values[i].to<kvs::Real64>();
            const double x = x0 + ( x_value - x_min_value ) * x_ratio;
            const double y = y1 - ( y_value - y_min_value ) * y_ratio;
            glVertex2d( x, y );
        }
        glEnd();
    }

    ::EndDraw();

    glPopAttrib();

    BaseClass::stopTimer();
}
예제 #10
0
/*===========================================================================*/
void ParallelCoordinatesRenderer::exec( kvs::ObjectBase* object, kvs::Camera* camera, kvs::Light* light )
{
    kvs::IgnoreUnusedVariable( light );

    kvs::TableObject* table = kvs::TableObject::DownCast( object );

    BaseClass::startTimer();

    kvs::OpenGL::WithPushedAttrib attrib( GL_ALL_ATTRIB_BITS );

    // Anti-aliasing.
    if ( m_enable_anti_aliasing )
    {
#if defined ( GL_MULTISAMPLE )
        if ( m_enable_multisample_anti_aliasing )
        {
            GLint buffers = 0;
            GLint samples = 0;
            kvs::OpenGL::GetIntegerv( GL_SAMPLE_BUFFERS, &buffers );
            kvs::OpenGL::GetIntegerv( GL_SAMPLES, &samples );
            if ( buffers > 0 && samples > 1 ) kvs::OpenGL::Enable( GL_MULTISAMPLE );
        }
        else
#endif
        {
            kvs::OpenGL::Enable( GL_LINE_SMOOTH );
            KVS_GL_CALL( glHint( GL_LINE_SMOOTH_HINT, GL_NICEST ) );
        }
    }

    kvs::OpenGL::Enable( GL_BLEND );
    kvs::OpenGL::SetBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    ::BeginDraw();

    const float color_axis_min_value = static_cast<float>( table->minValue( m_active_axis ) );
    const float color_axis_max_value = static_cast<float>( table->maxValue( m_active_axis ) );
    const kvs::AnyValueArray& color_axis_values = table->column( m_active_axis );
    m_color_map.setRange( color_axis_min_value, color_axis_max_value );

    const int x0 = m_left_margin;
    const int x1 = camera->windowWidth() - m_right_margin;
    const int y0 = m_top_margin;
    const int y1 = camera->windowHeight() - m_bottom_margin;

    const size_t nrows = table->column(0).size();
    const size_t naxes = table->numberOfColumns();
    const float stride = float( x1 - x0 ) / ( naxes - 1 );
    for ( size_t i = 0; i < nrows; i++ )
    {
        if ( !table->insideRange( i ) ) continue;

        KVS_GL_CALL( glLineWidth( m_line_width ) );
        KVS_GL_CALL_BEG( glBegin( GL_LINE_STRIP ) );

        const kvs::Real64 color_value = color_axis_values[i].to<kvs::Real64>();
        const kvs::RGBColor color = m_color_map.at( static_cast<float>( color_value ) );
        KVS_GL_CALL_VER( glColor4ub( color.r(), color.g(), color.b(), m_line_opacity ) );

        for ( size_t j = 0; j < naxes; j++ )
        {
            const kvs::Real64 min_value = table->minValue(j);
            const kvs::Real64 max_value = table->maxValue(j);
            const kvs::Real64 value = table->column(j)[i].to<kvs::Real64>();

            const kvs::Real64 x = m_left_margin + stride * j;
            const kvs::Real64 y = y1 - ( y1 - y0 ) * ( value - min_value ) / ( max_value - min_value );
            KVS_GL_CALL_VER( glVertex2d( x, y ) );
        }

        KVS_GL_CALL_END( glEnd() );
    }

    ::EndDraw();

    BaseClass::stopTimer();
}
예제 #11
0
void ColorPalette::draw_SV_palette( void )
{
    const int x0 = m_SV_palette.x0();
    const int y0 = m_SV_palette.y0();
    const int x1 = m_SV_palette.x1();
    const int y1 = m_SV_palette.y1();

    const float h = this->get_H_value();
    const kvs::RGBColor c0( kvs::HSVColor( h, 1, 1 ) ); // top-right
    const kvs::RGBColor c1( kvs::HSVColor( h, 0, 1 ) ); // top-left
    const kvs::RGBColor c2( kvs::HSVColor( h, 0, 0 ) ); // bottom-left
    const kvs::RGBColor c3( kvs::HSVColor( h, 1, 0 ) ); // bottom-right

    // Draw SV palette.
    glBegin( GL_QUADS );
    glColor3ub( c0.r(), c0.g(), c0.b() ); glVertex2i( x1, y0 );
    glColor3ub( c1.r(), c1.g(), c1.b() ); glVertex2i( x0, y0 );
    glColor3ub( c2.r(), c2.g(), c2.b() ); glVertex2i( x0, y1 );
    glColor3ub( c3.r(), c3.g(), c3.b() ); glVertex2i( x1, y1 );
    glEnd();

    // Draw the cross lines.
    {
        const int margin = 4;
        const float color = 1.0f;
        const int cursor_x0 = kvs::Math::Max( m_S_indicator - margin, m_SV_palette.x0() );
        const int cursor_y0 = kvs::Math::Max( m_V_indicator - margin, m_SV_palette.y0() );
        const int cursor_x1 = kvs::Math::Min( m_S_indicator + margin, m_SV_palette.x1() );
        const int cursor_y1 = kvs::Math::Min( m_V_indicator + margin, m_SV_palette.y1() );

        glLineWidth( 1 );
        glBegin( GL_LINES );
        glColor3f( color, color, color );
        glVertex2i( cursor_x0, cursor_y0 ); glVertex2i( cursor_x1, cursor_y0 );     // top
        glVertex2i( cursor_x0, cursor_y1 ); glVertex2i( cursor_x1, cursor_y1 );     // bottom
        glVertex2i( cursor_x0, cursor_y0 ); glVertex2i( cursor_x0, cursor_y1 + 1 ); // left
        glVertex2i( cursor_x1, cursor_y0 ); glVertex2i( cursor_x1, cursor_y1 + 1 ); // right
        glEnd();

        glLineWidth( 1 );
        glBegin( GL_LINES );
        glColor3f( color, color, color );
        // Horizontal lines.
        glVertex2i( x0, m_V_indicator ); glVertex2i( cursor_x0, m_V_indicator );
        glVertex2i( cursor_x1, m_V_indicator ); glVertex2i( x1, m_V_indicator );
        // Vertical lines.
        glVertex2i( m_S_indicator, y0 ); glVertex2i( m_S_indicator, cursor_y0 );
        glVertex2i( m_S_indicator, cursor_y1 ); glVertex2i( m_S_indicator, y1 );
        glEnd();
    }

    // Draw border.
    ::DrawRectangle( m_SV_palette, 1, m_upper_edge_color, m_lower_edge_color );
}
예제 #12
0
/*===========================================================================*/
void PointObject::add( const PointObject& other )
{
    if ( this->coords().size() == 0 )
    {
        // Copy the object.
        BaseClass::setCoords( other.coords() );
        BaseClass::setNormals( other.normals() );
        BaseClass::setColors( other.colors() );
        this->setSizes( other.sizes() );

        BaseClass::setMinMaxObjectCoords(
            other.minObjectCoord(),
            other.maxObjectCoord() );
        BaseClass::setMinMaxExternalCoords(
            other.minExternalCoord(),
            other.maxExternalCoord() );
    }
    else
    {
        if ( !BaseClass::hasMinMaxObjectCoords() )
        {
            BaseClass::updateMinMaxCoords();
        }

        kvs::Vec3 min_object_coord( BaseClass::minObjectCoord() );
        kvs::Vec3 max_object_coord( BaseClass::maxObjectCoord() );

        min_object_coord.x() = kvs::Math::Min( min_object_coord.x(), other.minObjectCoord().x() );
        min_object_coord.y() = kvs::Math::Min( min_object_coord.y(), other.minObjectCoord().y() );
        min_object_coord.z() = kvs::Math::Min( min_object_coord.z(), other.minObjectCoord().z() );

        max_object_coord.x() = kvs::Math::Max( max_object_coord.x(), other.maxObjectCoord().x() );
        max_object_coord.y() = kvs::Math::Max( max_object_coord.y(), other.maxObjectCoord().y() );
        max_object_coord.z() = kvs::Math::Max( max_object_coord.z(), other.maxObjectCoord().z() );

        BaseClass::setMinMaxObjectCoords( min_object_coord, max_object_coord );
        BaseClass::setMinMaxExternalCoords( min_object_coord, max_object_coord );

        // Integrate the coordinate values.
        kvs::ValueArray<kvs::Real32> coords;
        const size_t ncoords = this->coords().size() + other.coords().size();
        coords.allocate( ncoords );
        kvs::Real32* pcoords = coords.data();

        // x,y,z, ... + x,y,z, ... = x,y,z, ... ,x,y,z, ...
        memcpy( pcoords, this->coords().data(), this->coords().byteSize() );
        memcpy( pcoords + this->coords().size(), other.coords().data(), other.coords().byteSize() );
        BaseClass::setCoords( coords );

        // Integrate the normal vectors.
        kvs::ValueArray<kvs::Real32> normals;
        if ( this->normals().size() > 0 )
        {
            if ( other.normals().size() > 0 )
            {
                // nx,ny,nz, ... + nx,ny,nz, ... = nx,ny,nz, ... ,nx,ny,nz, ...
                const size_t nnormals = this->normals().size() + other.normals().size();
                normals.allocate( nnormals );
                kvs::Real32* pnormals = normals.data();
                memcpy( pnormals, this->normals().data(), this->normals().byteSize() );
                memcpy( pnormals + this->normals().size(), other.normals().data(), other.normals().byteSize() );
            }
            else
            {
                // nx,ny,nz, ... + (none) = nx,ny,nz, ... ,0,0,0, ...
                const size_t nnormals = this->normals().size() + other.coords().size();
                normals.allocate( nnormals );
                kvs::Real32* pnormals = normals.data();
                memcpy( pnormals, this->normals().data(), this->normals().byteSize() );
                memset( pnormals + this->normals().size(), 0, other.coords().byteSize() );
            }
        }
        else
        {
            if ( other.normals().size() > 0 )
            {
                const size_t nnormals = this->coords().size() + other.normals().size();
                normals.allocate( nnormals );
                kvs::Real32* pnormals = normals.data();
                // (none) + nx,ny,nz, ... = 0,0,0, ... ,nz,ny,nz, ...
                memset( pnormals, 0, this->coords().byteSize() );
                memcpy( pnormals + this->coords().size(), other.normals().data(), other.normals().byteSize() );
            }
        }
        BaseClass::setNormals( normals );

        // Integrate the color values.
        kvs::ValueArray<kvs::UInt8> colors;
        if ( this->colors().size() > 1 )
        {
            if ( other.colors().size() > 1 )
            {
                // r,g,b, ... + r,g,b, ... = r,g,b, ... ,r,g,b, ...
                const size_t ncolors = this->colors().size() + other.colors().size();
                colors.allocate( ncolors );
                kvs::UInt8* pcolors = colors.data();
                memcpy( pcolors, this->colors().data(), this->colors().byteSize() );
                memcpy( pcolors + this->colors().size(), other.colors().data(), other.colors().byteSize() );
            }
            else
            {
                // r,g,b, ... + R,G,B = r,g,b, ... ,R,G,B, ... ,R,G,B
                const size_t ncolors = this->colors().size() + other.coords().size();
                colors.allocate( ncolors );
                kvs::UInt8* pcolors = colors.data();
                memcpy( pcolors, this->colors().data(), this->colors().byteSize() );
                pcolors += this->colors().size();
                const kvs::RGBColor color = other.color();
                for ( size_t i = 0; i < other.coords().size(); i += 3 )
                {
                    *(pcolors++) = color.r();
                    *(pcolors++) = color.g();
                    *(pcolors++) = color.b();
                }
            }
        }
        else
        {
            if ( other.colors().size() > 1 )
            {
                // R,G,B + r,g,b, ... = R,G,B, ... ,R,G,B, r,g,b, ...
                const size_t ncolors = this->coords().size() + other.colors().size();
                colors.allocate( ncolors );
                kvs::UInt8* pcolors = colors.data();
                const kvs::RGBColor color = this->color();
                for ( size_t i = 0; i < this->coords().size(); i += 3 )
                {
                    *(pcolors++) = color.r();
                    *(pcolors++) = color.g();
                    *(pcolors++) = color.b();
                }
                memcpy( pcolors, other.colors().data(), other.colors().byteSize() );
            }
            else
            {
                const kvs::RGBColor color1 = this->color();
                const kvs::RGBColor color2 = other.color();
                if ( color1 == color2 )
                {
                    // R,G,B + R,G,B = R,G,B
                    const size_t ncolors = 3;
                    colors.allocate( ncolors );
                    kvs::UInt8* pcolors = colors.data();
                    *(pcolors++) = color1.r();
                    *(pcolors++) = color1.g();
                    *(pcolors++) = color1.b();
                }
                else
                {
                    // R,G,B + R,G,B = R,G,B, ... ,R,G,B, ...
                    const size_t ncolors = this->coords().size() + other.coords().size();
                    colors.allocate( ncolors );
                    kvs::UInt8* pcolors = colors.data();
                    for ( size_t i = 0; i < this->coords().size(); i += 3 )
                    {
                        *(pcolors++) = color1.r();
                        *(pcolors++) = color1.g();
                        *(pcolors++) = color1.b();
                    }
                    for ( size_t i = 0; i < other.coords().size(); i += 3 )
                    {
                        *(pcolors++) = color2.r();
                        *(pcolors++) = color2.g();
                        *(pcolors++) = color2.b();
                    }
                }
            }
        }
        BaseClass::setColors( colors );

        // Integrate the size values.
        kvs::ValueArray<kvs::Real32> sizes;
        if ( this->sizes().size() > 1 )
        {
            if ( other.sizes().size() > 1 )
            {
                // s, ... + s, ... = s, ... ,s, ...
                const size_t nsizes = this->sizes().size() + other.sizes().size();
                sizes.allocate( nsizes );
                kvs::Real32* psizes = sizes.data();
                memcpy( psizes, this->sizes().data(), this->sizes().byteSize() );
                memcpy( psizes + this->sizes().size(), other.sizes().data(), other.sizes().byteSize() );
            }
            else
            {
                // s, ... + S = s, ... ,S, ... ,S
                const size_t nsizes = this->sizes().size() + other.coords().size();
                sizes.allocate( nsizes );
                kvs::Real32* psizes = sizes.data();
                memcpy( psizes, this->sizes().data(), this->sizes().byteSize() );
                psizes += this->colors().size();
                const kvs::Real32 size = other.size();
                for ( size_t i = 0; i < other.coords().size(); i++ )
                {
                    *(psizes++) = size;
                }
            }
        }
        else
        {
            if ( other.sizes().size() > 1 )
            {
                // S + s, ... = S, ... ,S, s, ...
                const size_t nsizes = this->coords().size() + other.sizes().size();
                sizes.allocate( nsizes );
                kvs::Real32* psizes = sizes.data();
                const kvs::Real32 size = this->size();
                for ( size_t i = 0; i < this->coords().size(); i++ )
                {
                    *(psizes++) = size;
                }
                memcpy( psizes, other.sizes().data(), other.sizes().byteSize() );
            }
            else
            {
                const kvs::Real32 size1 = this->size();
                const kvs::Real32 size2 = other.size();
                if ( size1 == size2 )
                {
                    // S + S = S
                    const size_t nsizes = 1;
                    sizes.allocate( nsizes );
                    kvs::Real32* psizes = sizes.data();
                    *(psizes++) = size1;
                }
                else
                {
                    // S + S = S, ... , S, ...
                    const size_t nsizes = this->coords().size() + other.coords().size();
                    sizes.allocate( nsizes );
                    kvs::Real32* psizes = sizes.data();
                    for ( size_t i = 0; i < this->coords().size(); i++ )
                    {
                        *(psizes++) = size1;
                    }
                    for ( size_t i = 0; i < other.coords().size(); i++ )
                    {
                        *(psizes++) = size2;
                    }
                }
            }
        }
        this->setSizes( sizes );
    }
}