zoukankan      html  css  js  c++  java
  • 卡片翻页算法

    1、描述:计算翻开的卡片到平面的投影来模拟卡片打开的效果 。视点位于卡片上边缘中点正上方。

      以w、h表示原卡片的宽高,w1、h1表示投影的宽高,H表示视点高度 , a为翻开的卡片与平面上的卡片夹角,有以下公式:

    h1 = h*cosa *H /(H-h*sina)
    w1 = w*H/(H-h*sina)

    投影计算算法(这里仅考虑了第一象限)为:

        public ImageBuffer openCard(int[] pixels, int width, int height, double pi)
        {
            final int H = width * 3;
            double sina = Math.sin(pi);
            double cosa = Math.cos(pi);
    
            int newHeight = (int) (height * cosa * H / (H - height * sina));
            int newWidth = (int) (width * H / (H - height * sina));
            int[] newPixels = new int[newHeight * newWidth];
            int length = newPixels.length;
    
            for (int i = 0; i < height; i++)
            {
                double temp = H / (H - i * sina);
                int di = (int) (i * cosa * temp);
                int pre = i * width;
                int dPre = di * newWidth;
                int curWidth = (int) (width * temp);
                int dPos = (newWidth - curWidth) >> 1;
                for (int j = 0; j < width; j++)
                {
                    int dj = (int) (j * temp);
                    int index = dPre + dj + dPos;
                    if (index >= length)
                    {
                        index = length - 1;
                    }
                    newPixels[index] = pixels[pre + j];
                }
            }
    
            ImageBuffer ib = new ImageBuffer();
            ib.height = newHeight;
            ib.width = newWidth;
            ib.pixels = newPixels;
            return ib;
        }
    
    
    public class ImageBuffer
    {
        public int[] pixels;
        public int width;
        public int height;
    
        
        public String toString()
        {
            return "width : " + width + " height : " + height;
        }
    }

    2、上述算法会出现一个问题,不能保证卡片投影的每一个点都被设值。例如 如果投影面积大于原卡片面积,上述算法有部分点透明,效果比较查

          故改进算法,根据公式给每个投影上的点,找到原图上面的对应的点。公式为:

    h = h1 * H / ( H*cosa +h1*sina)
    w = w1 * H * cosa /( H* cosa + h1 *sina )

    具体算法(这里已经考虑了第一、第二象限)为:

    public static ImageBuffer reopenCard(int[] pixels, int width, int height, double pi)
        {
            final int H = width * 3;
            final double PI = 3.14; 
            final double HPI = PI/2;
            pi = pi%PI;
            double a = pi>HPI ? PI-pi : pi;
            
            double sina = Math.sin(a);
            double cosa = Math.cos(a);
    
            int newHeight = (int) (height * cosa * H / (H - height * sina));
            int newWidth = (int) (width * H / (H - height * sina));
            int[] newPixels = new int[newHeight * newWidth];
    
            for (int i = 0; i < newHeight; i++)
            {
                int h = pi>HPI ?newHeight -i : i;
                double temph = H * cosa + h * sina;
                int dh = (int) (h * H / temph);
                double tempw = H * cosa / temph;
    
                int curWidth = (int) (width * H / (H - dh * sina));
                int offset = (newWidth - curWidth) >> 1;
                int end = newWidth - offset;
    
                int pre = i * newWidth;
                int dPre = dh * width;
                for (int j = offset; j < end; j++)
                {                
                    int dw = (int) ((j - offset) * tempw);
                    newPixels[pre + j] = pixels[dPre + dw];
                }
            }
    
            ImageBuffer ib = new ImageBuffer();
            ib.height = newHeight;
            ib.width = newWidth;
            ib.pixels = newPixels;
            return ib;
        }

    3、尝试使用NDK,希望能提升效率,但是测试发现效率反而有所下降,猜测可能是像素数组在java类型和c之间转换导致效率耗损:

    #define HPI 1.57
    
    JNIEXPORT jobject JNICALL
    Java_com_xyl_bitmap_filter_FlipBitmap_openCard(JNIEnv *env , jobject jobj , jintArray pixels , jint width , jint height , jdouble pi )
    {
      
      jdouble PI = 3.14;
      jint H = width *3;
      //pi = pi%PI;
      jdouble a = pi>HPI ? PI-pi : pi;
    
      jdouble sina = sin(a);
      jdouble cosa = cos(a);
      jint newHeight = (jint) (height * cosa * H / (H - height * sina));
      jint newWidth = (jint) (width * H / (H - height * sina));
    
      jint length = width*height;
      jint newLength = newHeight*newWidth;
      jint *jpixels ,* newPixels;
    
      jpixels = malloc(sizeof(jint)*length);
      (*env)->GetIntArrayRegion(env , pixels , 0 , length , jpixels);
    
      newPixels = malloc(sizeof(jint) *newLength);
      jint i=0,j=0;
      for (; i < newHeight; i++)
      {
        jint h = pi>HPI ?newHeight -i : i;
        jdouble temph = H * cosa + h * sina;
        jint dh = (jint) (h * H / temph);
        jdouble tempw = H * cosa / temph;
        jint curWidth = (jint) (width * H / (H - dh * sina));
        jint offset = (newWidth - curWidth) >> 1;
        jint end = newWidth - offset;
        jint pre = i * newWidth;
        jint dPre = dh * width;
        j = offset;
        for (; j < end; j++)
        {
          jint dw = (jint) ((j - offset) * tempw);
          newPixels[pre + j] = jpixels[dPre + dw];
        }
      }
      
      jintArray resultPixels = (*env)->NewIntArray(env , newLength);
      (*env)->SetIntArrayRegion(env , resultPixels , 0 ,newLength , newPixels);
      jclass imageBufferClass = (*env)->FindClass(env , "com/xyl/bitmap/filter/ImageBuffer");
      if(imageBufferClass == NULL)
      {
        return;
      }
    
      jmethodID cid = (*env)->GetMethodID(env , imageBufferClass ,"<init>" , "()V");
      if(cid == NULL)
      {
         return ;
      }
      jobject imageBuffer = (*env)->NewObject(env , imageBufferClass , cid );
      jfieldID widthId , heightId , pixelsId;
      widthId = (*env)->GetFieldID(env ,imageBufferClass,"width" ,"I");
      heightId = (*env)->GetFieldID(env ,imageBufferClass,"height" ,"I");
      pixelsId = (*env)->GetFieldID(env ,imageBufferClass,"pixels" ,"[I");
      if(widthId == NULL || heightId == NULL || pixelsId == NULL)
      {
        return;
      }
    
      (*env)->SetIntField(env , imageBuffer , widthId , newWidth);
      (*env)->SetIntField(env , imageBuffer , heightId , newHeight);
      (*env)->SetObjectField(env , imageBuffer , pixelsId , resultPixels);
    
      free(newPixels);
      free(jpixels);
      return imageBuffer;
    }
  • 相关阅读:
    委托的另一种写法
    List集合基于某个字段排序
    js进阶
    DBlink与同义词
    iOS汤姆猫素材
    Objective-C 变量和基本的数据类型
    OC基础语法之方法
    16进制数
    kmp算法原理自我理解
    bfs广度遍历搜索模版
  • 原文地址:https://www.cnblogs.com/lipeil/p/2807382.html
Copyright © 2011-2022 走看看