程序员也是会浪漫的->打造浪漫的Android表白程序

2023-05-16

一年前,看到过有个牛人用HTML5绘制了浪漫的爱心表白动画,后来又在华超的这篇文章上看到大神用Android写出了相同的效果,于是也动手写了一下,并加了一些功能,感谢大神的指引,写给女票看她很开心呢。地址在这:浪漫程序员 HTML5爱心表白动画。发现原来程序员也是可以很浪……漫…..的。那么在Android怎么打造如此这个效果呢?参考了一下前面Html5的算法,在Android中实现了类似的效果。先贴上最终效果图:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述


生成心形线

心形线的表达式可以参考:桃心线。里面对桃心线的表达式解析的挺好。可以通过使用极坐标的方式,传入角度和距离(常量)计算出对应的坐标点。其中距离是常量值,不需改变,变化的是角度。
桃心线极坐标方程式为:

x=16×sin3α
y=13×cosα−5×cos2α−2×cos3α−cos4α

如果生成的桃心线不够大,可以把x、y乘以一个常数,使之变大。考虑到大部分人都不愿去研究具体的数学问题,我们直接把前面HTML5的JS代码直接翻译成Java代码就好。代码如下:

public Point getHeartPoint(float angle) {
  float t = (float) (angle / Math.PI);
  float x = (float) (19.5 * (16 * Math.pow(Math.sin(t), 3)));
  float y = (float) (-20 * (13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t))); 
   return new Point(offsetX + (int) x, offsetY + (int) y);
 }

其中offsetX和offsetY是偏移量。使用偏移量主要是为了能让心形线处于中央。offsetX和offsetY的值分别为:

offsetX = width / 2;
 offsetY = height / 2 - 55;

通过这个函数,我们可以将角度从(0,180)变化,不断取点并画点将这个心形线显示出来。好了,我们自定义一个View,然后把这个心形线画出来吧!

 @Override
  protected void onDraw(Canvas canvas) {
       float angle = 10;
       while (angle < 180) {
           Point p = getHeartPoint(angle);
           canvas.drawPoint(p.x, p.y, paint);
           angle = angle + 0.02f;
        }
   }

运行结果如下:
这里写图片描述


绘制花瓣原理

我们想要的并不是简单绘制一个桃心线,要的是将花朵在桃心线上摆放。首先,得要知道怎么绘制花朵,而花朵是由一个个花瓣组成。因此绘制花朵的核心是绘制花瓣。绘制花瓣的原理是:3次贝塞尔曲线。三次贝塞尔曲线是由两个端点和两个控制点决定。假设花芯是一个圆,有n个花瓣,那么两个端点与花芯的圆心连线之间的夹角即为360/n。因此可以根据花瓣数量和花芯半径确定每个花瓣的位置。将两个端点与花芯的圆心连线的延长线分别确定另外两个控制点。通过随机生成花芯半径、每个花瓣的起始角以及随机确定延长线得到两个控制点,可以绘制一个随机的花朵。参数的改变如下图所示:

这里写图片描述


将花朵绘制到桃心线上

首先定义花瓣类Petal:

 package com.example.administrator.testheart;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;

public class Petal {
    private float stretchA;//第一个控制点延长线倍数
    private float stretchB;//第二个控制点延长线倍数
    private float startAngle;//起始旋转角,用于确定第一个端点
    private float angle;//两条线之间夹角,由起始旋转角和夹角可以确定第二个端点
    private int radius = 2;//花芯的半径
    private float growFactor;//增长因子,花瓣是有开放的动画效果,这个参数决定花瓣展开速度
    private int color;//花瓣颜色
    private boolean isFinished = false;//花瓣是否绽放完成
    private Path path = new Path();//用于保存三次贝塞尔曲线
    private Paint paint = new Paint();//画笔
    //构造函数,由花朵类调用
    public Petal(float stretchA, float stretchB, float startAngle, float angle, int color, float growFactor) {
        this.stretchA = stretchA;
        this.stretchB = stretchB;
        this.startAngle = startAngle;
        this.angle = angle;
        this.color = color;
        this.growFactor = growFactor;
        paint.setColor(color);
    }
    //用于渲染花瓣,通过不断更改半径使得花瓣越来越大
    public void render(Point p, int radius, Canvas canvas) {
        if (this.radius <= radius) {
            this.radius += growFactor; // / 10;
        } else {
            isFinished = true;
        }
        this.draw(p, canvas);
    }

    //绘制花瓣,参数p是花芯的圆心的坐标
    private void draw(Point p, Canvas canvas) {
        if (!isFinished) {

            path = new Path();
            //将向量(0,radius)旋转起始角度,第一个控制点根据这个旋转后的向量计算
            Point t = new Point(0, this.radius).rotate(MyUtil.degrad(this.startAngle));
            //第一个端点,为了保证圆心不会随着radius增大而变大这里固定为3
            Point v1 = new Point(0, 3).rotate(MyUtil.degrad(this.startAngle));
            //第二个端点
            Point v2 = t.clone().rotate(MyUtil.degrad(this.angle));
            //延长线,分别确定两个控制点
            Point v3 = t.clone().mult(this.stretchA);
            Point v4 = v2.clone().mult(this.stretchB);
            //由于圆心在p点,因此,每个点要加圆心坐标点
            v1.add(p);
            v2.add(p);
            v3.add(p);
            v4.add(p);
            path.moveTo(v1.x, v1.y);
            //参数分别是:第一个控制点,第二个控制点,终点
            path.cubicTo(v3.x, v3.y, v4.x, v4.y, v2.x, v2.y);
        }
        canvas.drawPath(path, paint);
    }

} 

花瓣类是最重要的类,因为真正绘制在屏幕上的是一个个小花瓣。每个花朵包含一系列花瓣,花朵类Bloom如下:

package com.example.administrator.testheart;

import android.graphics.Canvas;

import java.util.ArrayList;

public class Bloom {
    private int color;//整个花朵的颜色
    private Point point;//花芯圆心
    private int radius; //花芯半径
    private ArrayList<Petal> petals;//用于保存花瓣

    public Point getPoint() {
        return point;
    }


    public Bloom(Point point, int radius, int color, int petalCount) {
        this.point = point;
        this.radius = radius;
        this.color = color;
        petals = new ArrayList<>(petalCount);


        float angle = 360f / petalCount;
        int startAngle = MyUtil.randomInt(0, 90);
        for (int i = 0; i < petalCount; i++) {
            //随机产生第一个控制点的拉伸倍数
            float stretchA = MyUtil.random(Garden.Options.minPetalStretch, Garden.Options.maxPetalStretch);
            //随机产生第二个控制地的拉伸倍数
            float stretchB = MyUtil.random(Garden.Options.minPetalStretch, Garden.Options.maxPetalStretch);
            //计算每个花瓣的起始角度
            int beginAngle = startAngle + (int) (i * angle);
            //随机产生每个花瓣的增长因子(即绽放速度)
            float growFactor = MyUtil.random(Garden.Options.minGrowFactor, Garden.Options.maxGrowFactor);
            //创建一个花瓣,并添加到花瓣列表中
            this.petals.add(new Petal(stretchA, stretchB, beginAngle, angle, color, growFactor));
        }
    }

    //绘制花朵
    public void draw(Canvas canvas) {
        Petal p;
        for (int i = 0; i < this.petals.size(); i++) {
            p = petals.get(i);
            //渲染每朵花朵
            p.render(point, this.radius, canvas);

        }

    }

    public int getColor() {
        return color;
    }
}

接下来是花园类Garden,主要用于创建花朵以及一些相关配置:

package com.example.administrator.testheart;

import java.util.ArrayList;

public class Garden { 

    //创建一个随机的花朵
    public Bloom createRandomBloom(int x, int y) {
        //创建一个随机的花朵半径
        int radius = MyUtil.randomInt(Options.minBloomRadius, Options.maxBloomRadius);
        //创建一个随机的花朵颜色
        int color = MyUtil.randomrgba(Options.minRedColor, Options.maxRedColor, Options.minGreenColor, Options.maxGreenColor, Options.minBlueColor, Options.maxBlueColor, Options.opacity);
        //创建随机的花朵中花瓣个数
        int petalCount = MyUtil.randomInt(Options.minPetalCount, Options.maxPetalCount);
        return createBloom(x, y, radius, color, petalCount);
    }

    //创建花朵
    public Bloom createBloom(int x, int y, int radius, int color, int petalCount) {
        return new Bloom(new Point(x, y), radius, color, petalCount);
    }

    static class Options {
        //用于控制产生随机花瓣个数范围
        public static int minPetalCount = 8;
        public static int maxPetalCount = 15;
        //用于控制产生延长线倍数范围
        public static float minPetalStretch = 2f;
        public static float maxPetalStretch = 3.5f;
        //用于控制产生随机增长因子范围,增长因子决定花瓣绽放速度
        public static float minGrowFactor = 1f;
        public static float maxGrowFactor = 1.1f;
        //用于控制产生花朵半径随机数范围
        public static int minBloomRadius = 8;
        public static int maxBloomRadius = 10;
        //用于产生随机颜色
        public static int minRedColor = 128;
        public static int maxRedColor = 255;
        public static int minGreenColor = 0;
        public static int maxGreenColor = 128;
        public static int minBlueColor = 0;
        public static int maxBlueColor = 128;
        //花瓣的透明度
        public static int opacity = 50;//0.1
    }
}

考虑到刷新的比较频繁,选择使用SurfaceView作为显示视图。自定义一个HeartView继承SurfaceView。代码如下:

package com.example.administrator.testheart;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.ArrayList;

public class HeartView extends SurfaceView implements SurfaceHolder.Callback {
    SurfaceHolder surfaceHolder;
    int offsetX;
    int offsetY;
    private Garden garden;
    private int width;
    private int height;
    private Paint backgroundPaint;
    private boolean isDrawing = false;
    private Bitmap bm;
    private Canvas canvas;
    private int heartRadio = 1;

    public HeartView(Context context) {
        super(context);
        init();
    }

    public HeartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }


    private void init() {
        surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);
        garden = new Garden();
        backgroundPaint = new Paint();
        backgroundPaint.setColor(Color.rgb(0xff, 0xff, 0xe0));


    }

    ArrayList<Bloom> blooms = new ArrayList<>();

    public Point getHeartPoint(float angle) {
        float t = (float) (angle / Math.PI);
        float x = (float) (heartRadio * (16 * Math.pow(Math.sin(t), 3)));
        float y = (float) (-heartRadio * (13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t)));

        return new Point(offsetX + (int) x, offsetY + (int) y);
    }


    //绘制列表里所有的花朵
    private void drawHeart() {
        canvas.drawRect(0, 0, width, height, backgroundPaint);
        for (Bloom b : blooms) {
            b.draw(canvas);
        }
        Canvas c = surfaceHolder.lockCanvas();

        c.drawBitmap(bm, 0, 0, null);

        surfaceHolder.unlockCanvasAndPost(c);

    }

    public void reDraw() {
        blooms.clear();


        drawOnNewThread();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

    }

    //开启一个新线程绘制
    private void drawOnNewThread() {
        new Thread() {
            @Override
            public void run() {
                if (isDrawing) return;
                isDrawing = true;

                float angle = 10;
                while (true) {

                    Bloom bloom = getBloom(angle);
                    if (bloom != null) {
                        blooms.add(bloom);
                    }
                    if (angle >= 30) {
                        break;
                    } else {
                        angle += 0.2;
                    }
                    drawHeart();
                    try {
                        sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                isDrawing = false;
            }
        }.start();
    }


    private Bloom getBloom(float angle) {

        Point p = getHeartPoint(angle);

        boolean draw = true;
        /**循环比较新的坐标位置是否可以创建花朵,
         * 为了防止花朵太密集
         * */
        for (int i = 0; i < blooms.size(); i++) {

            Bloom b = blooms.get(i);
            Point bp = b.getPoint();
            float distance = (float) Math.sqrt(Math.pow(p.x - bp.x, 2) + Math.pow(p.y - bp.y, 2));
            if (distance < Garden.Options.maxBloomRadius * 1.5) {
                draw = false;
                break;
            }
        }
        //如果位置间距满足要求,就在该位置创建花朵并将花朵放入列表
        if (draw) {
            Bloom bloom = garden.createRandomBloom(p.x, p.y);
            return bloom;
        }
        return null;
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {


    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        this.width = width;
        this.height = height;
        //我的手机宽度像素是1080,发现参数设置为30比较合适,这里根据不同的宽度动态调整参数
        heartRadio = width * 30 / 1080;

        offsetX = width / 2;
        offsetY = height / 2 - 55;
        bm = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        canvas = new Canvas(bm);
        drawOnNewThread();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }
}

还有两个比较重要的工具类
Point.java保存点信息,或者说是向量信息。包含向量的基本运算。

package com.example.administrator.testheart;

public class Point {

    public int x;
    public int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    //旋转
    public Point rotate(float theta) {
        int x = this.x;
        int y = this.y;
        this.x = (int) (Math.cos(theta) * x - Math.sin(theta) * y);
        this.y = (int) (Math.sin(theta) * x + Math.cos(theta) * y);
        return this;
    }

    //乘以一个常数
    public Point mult(float f) {
        this.x *= f;
        this.y *= f;
        return this;
    }

    //复制
    public Point clone() {
        return new Point(this.x, this.y);
    }

    //该点与圆心距离
    public float length() {
        return (float) Math.sqrt(this.x * this.x + this.y * this.y);
    }

    //向量相减
    public Point subtract(Point p) {
        this.x -= p.x;
        this.y -= p.y;
        return this;
    }

    //向量相加
    public Point add(Point p) {
        this.x += p.x;
        this.y += p.y;
        return this;
    }

    public Point set(int x, int y) {
        this.x = x;
        this.y = y;
        return this;
    }
}

工具类MyUtil.java主要是产生随机数、颜色等

package com.example.administrator.testheart;

import android.graphics.Color;

public class MyUtil {

    public static float circle = (float) (2 * Math.PI);

    public static int rgba(int r, int g, int b, int a) {
        return Color.argb(a, r, g, b);
    }

    public static int randomInt(int min, int max) {
        return (int) Math.floor(Math.random() * (max - min + 1)) + min;
    }

    public static float random(float min, float max) {
        return (float) (Math.random() * (max - min) + min);
    }

    //产生随机的argb颜色
    public static int randomrgba(int rmin, int rmax, int gmin, int gmax, int bmin, int bmax, int a) {
        int r = Math.round(random(rmin, rmax));
        int g = Math.round(random(gmin, gmax));
        int b = Math.round(random(bmin, bmax));
        int limit = 5;
        if (Math.abs(r - g) <= limit && Math.abs(g - b) <= limit && Math.abs(b - r) <= limit) {
            return rgba(rmin, rmax, gmin, gmax);
        } else {
            return rgba(r, g, b, a);
        }
    }

    //角度转弧度
    public static float degrad(float angle) {
        return circle / 360 * angle;
    }
}

Activity自动跳转及日期计时及打字机效果实现类MainActivity

package com.example.administrator.testheart;

import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    HeartView heartView;
    private TextView tv_text;
    private TextView tv_text_1;
    private TextView tv_text_2;
    private int clo = 0;

    private RelativeLayout countDown;
    // 倒计时
    private TextView daysTv, hoursTv, minutesTv, secondsTv;
    private long mDay = 652;
    private long mHour = 15;
    private long mMin = 37;
    private long mSecond = 00;// 天 ,小时,分钟,秒
    private boolean isRun = true;

    private Handler timeHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what==1) {
                computeTime();
                daysTv.setText(mDay+"");
                hoursTv.setText(mHour+"");
                minutesTv.setText(mMin+"");
                secondsTv.setText(mSecond+"");
                if (mDay==0&&mHour==0&&mMin==0&&mSecond==0) {
                    countDown.setVisibility(View.GONE);
                }
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        heartView = (HeartView) findViewById(R.id.surfaceView);
        tv_text = (TextView) findViewById(R.id.myword);
        tv_text_1 = (TextView) findViewById(R.id.myword_1);
        tv_text_2 = (TextView) findViewById(R.id.myword_2);
        shark();

        countDown = (RelativeLayout) findViewById(R.id.countdown_layout);
        daysTv = (TextView) findViewById(R.id.days_tv);
        hoursTv = (TextView) findViewById(R.id.hours_tv);
        minutesTv = (TextView) findViewById(R.id.minutes_tv);
        secondsTv = (TextView) findViewById(R.id.seconds_tv);

        startRun();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        heartView.reDraw();
        return super.onTouchEvent(event);
    }

    public void reDraw(View v) {

        heartView.reDraw();
    }

    private void shark() {
        Timer timer = new Timer();
        TimerTask taskcc = new TimerTask() {
            public void run() {
                runOnUiThread(new Runnable() {
                    public void run() {
                        if (clo == 0) {
                            clo = 1;
                            tv_text.setTextColor(Color.TRANSPARENT);
                            tv_text_1.setTextColor(Color.TRANSPARENT);
                            tv_text_2.setTextColor(Color.TRANSPARENT);
                        } else {
                            if (clo == 1) {

                                clo = 2;
                                tv_text.setTextColor(Color.YELLOW);
                                tv_text_1.setTextColor(Color.YELLOW);
                                tv_text_2.setTextColor(Color.YELLOW);
                            } else if (clo == 2) {

                                clo = 3;
                                tv_text.setTextColor(Color.RED);
                                tv_text_1.setTextColor(Color.RED);
                                tv_text_2.setTextColor(Color.RED);

                            } else if (clo == 3){

                                clo = 4;
                                tv_text.setTextColor(Color.BLACK);
                                tv_text_1.setTextColor(Color.BLACK);
                                tv_text_2.setTextColor(Color.BLACK);
                            } else if (clo == 4){

                                clo = 5;
                                tv_text.setTextColor(Color.WHITE);
                                tv_text_1.setTextColor(Color.WHITE);
                                tv_text_2.setTextColor(Color.WHITE);
                            }else if (clo == 5){

                                clo = 6;
                                tv_text.setTextColor(Color.GREEN);
                                tv_text_1.setTextColor(Color.GREEN);
                                tv_text_2.setTextColor(Color.GREEN);
                            } else if (clo == 6){

                                clo = 7;
                                tv_text.setTextColor(Color.MAGENTA);
                                tv_text_1.setTextColor(Color.MAGENTA);
                                tv_text_2.setTextColor(Color.MAGENTA);
                            }else if (clo == 7){

                                clo = 8;
                                tv_text.setTextColor(Color.CYAN);
                                tv_text_1.setTextColor(Color.CYAN);
                                tv_text_2.setTextColor(Color.CYAN);
                            }else if (clo == 8){

                                clo = 9;
                                tv_text.setTextColor(Color.DKGRAY);
                                tv_text_1.setTextColor(Color.DKGRAY);
                                tv_text_2.setTextColor(Color.DKGRAY);
                            }
                            else if (clo == 9){

                                clo = 10;
                                tv_text.setTextColor(Color.GRAY);
                                tv_text_1.setTextColor(Color.GRAY);
                                tv_text_2.setTextColor(Color.GRAY);
                            }else if (clo == 10){

                                clo = 11;
                                tv_text.setTextColor(Color.LTGRAY);
                                tv_text_1.setTextColor(Color.LTGRAY);
                                tv_text_2.setTextColor(Color.LTGRAY);
                            }else {
                                clo = 0;
                                    tv_text.setTextColor(Color.BLUE);
                                tv_text_1.setTextColor(Color.BLUE);
                                tv_text_2.setTextColor(Color.BLUE);
                            }
                        }
                    }
                });
            }
        };
        timer.schedule(taskcc, 1, 1500);  //<span style="color: rgb(85, 85, 85); font-family: 'microsoft yahei'; font-size: 15px; line-height: 35px;">第二个参数分别是delay(多长时间后执行),第三个参数是:duration(执行间隔)单位为:ms</span>
    }

    /**
     * 开启计时
     */
    private void startRun() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                while (isRun) {
                    try {
                        Thread.sleep(1000); // sleep 1000ms
                        Message message = Message.obtain();
                        message.what = 1;
                        timeHandler.sendMessage(message);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    /**
     * 倒计时计算
     */
    private void computeTime() {
        mSecond++;
        if (mSecond > 60) {
            mSecond = 0;
            mMin++;
            if (mMin > 60) {
                mMin = 0;
                mHour++;
                if (mHour > 24) {
                    mHour = 0;
                    // 倒计时结束
                    mDay++;
                }
            }
        }
    }
}

到了这一步就可以实现上面的效果了。
源码地址在这。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

程序员也是会浪漫的->打造浪漫的Android表白程序 的相关文章

  • 在ROS中实现基于darknet_ros的目标检测

    最近用自己的渣渣笔记本电脑跑了一下yolo目标检测在ROS中的实现 xff0c 实现了用摄像头进行目标检测的任务 以下为笔记 xff0c 防止遗忘 1 使用的环境和平台 Ubuntu 16 04 LTS 43 ROS 43 Yolo 2 实
  • 01 FreeRTOS任务实例

    FreeRTOS任务实例 一 简要说明1 官方例程下载 二 学习任务的创建1 创建一个任务2 任务中传递参数3 不同优先级的任务 三 任务的延时1 使用阻塞式延时2 精确的任务定时3 低优先级任务无延时 xff0c 高优先级延时 一 简要说
  • opencv 读取相机图像+ros发布图像

    usr bin python2 coding 61 utf 8 import cv2 import numpy as np from std msgs msg import Header from sensor msgs msg impor
  • 无人机小知识:Pitch Yaw Roll的经典解释

    无人机的一个最基本的基础知识就是对Pitch Yaw Roll三个方向的辨别 查了下网上很多资料 xff0c 都采用的下面的几张图进行说明 xff0c 我觉得很直观 xff0c 记录一下 xff0c 当做备忘录 机体坐标系 xff1a 固定
  • 编译警告:warning: Clock skew detected. Your build may be incomplete.

    在编译darknet ros程序时 xff0c 遇到如下警告 xff1a make 2 Warning File 39 darknet ros darknet ros CMakeFiles darknet ros lib dir depen
  • Yolo v4系列学习(四)Yolo v4移植ROS

    目录 1 建立名为catkin ws的工作空间2 下载darknet ros包3 下载Yolo v4源码4 开始编译5 漫长的解决Bug的过程6 配置Yolo v4 43 ROS7 开始使用Yolo v4 43 ROS8 调参参考网址 1
  • C++(14):make_unique

    C 43 43 14增加了make unique xff0c 用于创建unique ptr对象 xff1a include lt iostream gt include lt memory gt using namespace std in
  • Git:修改commit内容

    在提交code xff0c 使用git commit编写注释时 xff0c 如果发现注释的内容不太准确 xff0c 需要修改怎么办 xff1f 比如 xff0c 当前写的注释是 xff1a this is fix for XXX 在git
  • ros安装详细教程+问题解决

    官方英文连接 xff1a melodic Installation Ubuntu ROS Wiki 如果一下命令有疑问 xff1a 见上方官方文档 xff0c 也很简洁 ROS有许多版本 xff0c ubuntu20 04对应的版本Noet
  • 激光slam 理论详解(一)

    什么是slam 技术 slam Simultaneous Localization and Mapping 叫即时定位与建图 xff0c 它主要的作用是让机器人在未知的环境中 xff0c 完成定位 xff08 Localization xf
  • gazebo模型下载以及配置

    最近在学习ROS xff0c 主要是为了结合SLAM仿真使用 启动gazebo命令 roscore 在另一个终端执行 gazebo 就可以进入清爽的gazebo界面 xff08 如果屏幕出现黑屏并不是安装错误可以稍微等待一会 xff09 x
  • ROS中在一个包里引用其他包内的自定义消息或服务

    假设我们要在a package中引用b package里自定义的my message msg 方法1 可直接通过添加依赖的方式解决 首先在创建包时添加b package catkin create pkg std msgs roscpp r
  • 第三篇 视觉里程计(VO)的初始化过程以及openvslam中的相关实现详解

    视觉里程计 xff08 Visual Odometry VO xff09 xff0c 通过使用相机提供的连续帧图像信息 xff08 以及局部地图 xff0c 先不考虑 xff09 来估计相邻帧的相机运动 xff0c 将这些相对运行转换为以第
  • ROS : 参数服务器之动态调参(dynamic_reconfigure)

    另外参考链接 xff1a ROS动态参数配置 xff1a dynparam命令行工具的使用 xff08 示例 43 代码 xff09 肥肥胖胖是太阳的博客 CSDN博客 参数服务器实现的功能 xff1a 修改参数后 xff0c 不需要重新编
  • ROS中static_transform_publisher工具的使用

    static transform publisher的功能是发布两个坐标系之间的静态坐标变换 xff0c 这两个坐标系不会发生相对位置变化 命令格式为 xff1a static transform publisher x y z yaw p
  • Docker 下载redis

    首先去docker hub 获取下载命令Docker Hub 如图 xff1a docker pull redis 为最新版本 也可以 指定版本列如 xff1a docker pull redis 6 2 6 bullseye 下载成功 r
  • VSCode 如何查看git提交的历史记录或逐行记录

    下载两个插件就行了 Git History GitLens 安装成功之后 xff0c 任意选择一个文件 xff0c 你鼠标点击哪一行代码 xff0c 后面都会提示谁在什么时候做了什么 xff0c 鼠标悬浮提示上便会直接显示作者 xff0c
  • 电池、电机、螺旋桨搭配

    电池 电机 螺旋桨搭配 span class hljs number 1 span 电机 span class hljs number 1 span 电机KV值 xff1a 大KV配小桨 xff0c 小KV配大桨 KV值是每1V的电压下电机
  • 为什么指针变量做形参可以改变实参的数据

    形参不能传任何东西给实参 xff0c 实参传过去的东西都是一个副本 下面以一个交换数据的被调函数片段为例 在指针变量由实参传递给形参时传过去的实际是指针变量的值 xff0c 即一个地址 xff0c 在 t 61 p1 p1 61 p2 p2
  • 敲线性表代码时遇到的问题(C++)【exit,return】

    1 xff1a exit OVERFLOW exit简介 为C 43 43 的退出函数 xff0c 声明于stdlib h中 xff0c 对于C 43 43 其标准的头文件为cstdlib 声明为 void exit int value e

随机推荐

  • /etc目录详解

    Linux etc目录详解 etc目录 包含很多文件 许多网络配置文件也在 etc 中 etc rc or etc rc d or etc rc d 启动 或改变运行级时运行的scripts或scripts的目录 etc passwd 用户
  • Tomcat 8.0 Mac 安装与配置

    工具 原料 1 xff0c JDK xff1a 版本为jdk 8u40 macosx x64 dmg 下载地址http www oracle com technetwork java javase downloads jdk8 downlo
  • 2011届移动开发者大会

    2011年11月4号星期五 xff0c 早晨八点我们就早早的来到了会场 xff0c 因为有了上次云计算大会的经验 xff0c 所以我们早早的就来了 xff0c 因为人很多我们必须才能找到一个比较好的位置 由于来的太早工作人员很多都没有就位
  • 第五篇 openvslam建图与优化模块梳理

    建图模块 mapping module在初始化系统的时候进行实例化 xff0c 在构建实例的时候会实例化local map cleaner和local bundle adjuster 系统启动的时候会在另外一个线程中启动该模块 code s
  • 个人安卓学习笔记---java.io.IOException: Unable to open sync connection!

    在使用手机调试程序的时候出现了java io IOException Unable to open sync connection 这样的异常 xff0c 我尝试使用拔掉USB然后重新 xff0c 插入 xff0c 结果失败 再尝试 xff
  • "_OBJC_CLASS_$_Play", referenced from:

    IOS做了这么久也没写过什么博客 xff0c 不好不好 xff0c 今天开始写 遇到的问题 xff1a 34 OBJC CLASS Play 34 referenced from 解决方案 xff1a Tagert Build Phases
  • 树莓派SSH远程连接连接失败的解决办法

    树莓派SSH远程连接 将全新的树莓派系统烧录 xff0c 开机然后用SSH远程连接 xff0c 结果SSH连接提示 connection refused xff0c 导致连接树莓派失败 出现错误的原因是自 2016 11 25 官方发布的新
  • 在树莓派中安装ROS系统(Kinetic)

    在树莓派中安装ROS系统 重新梳理了一下树莓派的安装流程 xff0c 现在我们来开始吧 打开官网教程 http wiki ros org kinetic step1 安装源 xff08 中国 xff09 sudo sh c 39 etc l
  • ROS学习笔记-roscd指令

    对ROS文件系统而言 xff0c ROS中的roscd命令实现利用包的名字直接切换到相应的文件目录下 xff0c 命令使用方法如下 xff1a span class hljs tag roscd span span class hljs a
  • configure it with blueman-service

    用下面这个命令把Linux目录的名字由中文改成英文了 export LANG span class hljs subst 61 span en US xdg span class hljs attribute user span span
  • 关于Ubuntu16.04升级系统后启动报错问题的修复

    关于Ubuntu16 04升级系统后启动报错问题的修复 Ubuntu16 04升级后启动报错为 Failed to start Load Kernel Modules 使用systemctl status systemd modules l
  • Ubuntu Mate 自动登录

    树莓派安装Ubuntu Mate 设置自动启动 需要修改文件 usr share lightdm lightdm conf d 60 lightdm gtk greeter conf sudo vim usr share lightdm l
  • Linux系统调用实现简析

    1 前言 限于作者能力水平 xff0c 本文可能存在谬误 xff0c 因此而给读者带来的损失 xff0c 作者不做任何承诺 2 背景 本篇基于 Linux 4 14 43 ARM 32 43 glibc 2 31 进行分析 3 系统调用的实
  • Docker中容器的备份、恢复和迁移

    1 备份容器 首先 xff0c 为了备份 Docker中的容器 xff0c 我们会想看看我们想要备份的容器列表 要达成该目的 xff0c 我们需要在我们运行着 Docker 引擎 xff0c 并已创建了容器的 Linux 机器中运行 doc
  • 关于OpenCV的那些事——相机姿态更新

    上一节我们使用张正友相机标定法获得了相机内参 xff0c 这一节我们使用 PnP Perspective n Point 算法估计相机初始姿态并更新之 推荐3篇我学习的博客 xff1a 姿态估计 Pose estimation algori
  • Java中接口(Interface)的定义和使用

    有关 Java 中接口的使用相信程序员们都知道 xff0c 但是你们知不知道接口到底有什么用呢 xff1f 毫无疑问 xff0c 接口的重要性远比想象中重要 接下来我们便一起来学习Java中接口使用 Java接口是什么 Java接口是一系列
  • Java中向下转型的意义

    什么是向上转型和向下转型 在Java继承体系中 xff0c 认为基类 xff08 父类 超类 xff09 在上层 xff0c 导出类 xff08 子类 继承类 派生类 xff09 在下层 xff0c 因此向上转型的意思就是把子类对象转成父类
  • Java中单例模式的使用

    什么是单例模式 单例模式 xff0c 也叫单子模式 xff0c 是一种常用的软件设计模式 在应用这个模式时 xff0c 单例对象的类必须保证只有一个实例存在 许多时候整个系统只需要拥有一个的全局对象 xff0c 这样有利于我们协调系统整体的
  • Android RecyclerView完全解析

    什么是RecyclerView xff1f RecyclerView 是谷歌 V7 包下新增的控件 用来替代 ListView 的使用 在 RecyclerView 标准化了 ViewHolder 类似于 ListView 中 conver
  • 程序员也是会浪漫的->打造浪漫的Android表白程序

    一年前 xff0c 看到过有个牛人用HTML5绘制了浪漫的爱心表白动画 xff0c 后来又在华超的这篇文章上看到大神用Android写出了相同的效果 xff0c 于是也动手写了一下 xff0c 并加了一些功能 xff0c 感谢大神的指引 写