小春网

 找回密码
 注册账号
查看: 1610|回复: 14
收起左侧

[IT 交流] [原创]C++/CLI 画箭头

[复制链接]
发表于 2013-3-30 23:36:24 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册账号

x
.net类库里面有现成的画箭头的类  但是,当我想自由的控制箭头的高度,宽度的时候,它可能就不能用了
为了将来灵活画出各种高度,宽度的箭头,需要自己实现箭头的类。

矢印を描画する点を自分で計算する方法







肝は、矢印の部分の座標を計算する方法である

----プログラム抜粋-----
/******************************************************************************
*JdrArrow.h
*****************************************************************************/
#pragma once

using namespace System;
using namespace System::Drawing;

namespace DevTech
{
namespace Arrow
{
    ///
    ///2つの点で決まる直線の方向性格納
    ///*x軸の場合:
    ///     x座標がプラスの方向を正方向、逆を負方向とする
    ///*y軸の場合:
    ///    y座標プラスの方向を正方向、逆を負方向とする
    ///
    public enum class JdrArrowDirection : char
    {
        NEGATIVE = -1,        //負方向
        POSITIVE = 0,         //正方向
    };

    ///
    ///直線の座標軸との平行性
    ///
    public enum class Parallelism : char
    {
        DONOT_PARALLEL = 0,   //座標軸と平行しない
        PARALLEL_WITH_X = 1,  //X軸と平行
        PARALLEL_WITH_Y = 2   //y軸と平行
    };

    ///
    ///直線の方向性(座標軸との平行性,各軸に沿う方向性)
    ///
    public ref struct LineDirection
    {
        //座標軸との平行性
        Parallelism       Parallelism;

        ///
        ///線の方向
        ///*x軸と平行線の場合:x軸に沿う方向
        ///  y軸と平行線の場合:y軸に沿う方向
        ///  座標軸と平行しない場合:x軸に沿う方向
        ///
        JdrArrowDirection ArrowDirection;
    };

    ///
    ///矢印を管理するクラス
    ///2つの点を設定されると、矢印を生成し保持する
    ///
    public ref class JdrArrow
    {
    private:
        PointF m_start;   //起点
        PointF m_end;     //終点
        PointF m_endTo1;  //矢印の点1
        PointF m_endTo2;  //矢印の点2
        LineDirection m_lineDirection;

        //将来設定できるようにする
        int m_d;   //矢印の高さ
        int m_d2;  //矢印の幅

        ///
        ///矢印の両点を計算する
        ///
        void getArrowPoint();

    public:

        ///
        ///起点を返す
        ///
        property PointF StartPoint
        {
            PointF get(){return m_start;}
        }

        ///
        ///終点を返す
        ///
        property PointF EndPoint
        {
            PointF get(){return m_end;}
        }

        ///
        ///矢印の点を返す
        ///
        property PointF EndTo1
        {
            PointF get(){return m_endTo1;}
        }

        ///
        ///矢印の点を返す
        ///
        property PointF EndTo2
        {
            PointF get(){return m_endTo2;}
        }

        ///
        ///コンストラクタ
        ///起点
        ///終点
        ///
        JdrArrow(PointF i_st,PointF i_ed);
    };

}
}
--------------------------------------------
/******************************************************************************
*JdrArrow.cpp
*****************************************************************************/
#include "JdrArrow.h"

///
///矢印の両点を計算する
///*m_start,m_end両点で決まる直線の終点に描画する矢印の両点を計算し、
///  m_endTo1,m_endTo2に設定する
///
void DevTech::Arrow::JdrArrow::getArrowPoint()
{
    //座標軸と平行する直線の矢印は簡単に計算できる
    if(m_lineDirection.Parallelism==Parallelism::PARALLEL_WITH_X)  //x軸と平行
    {
        if(m_lineDirection.ArrowDirection==JdrArrowDirection::POSITIVE)  //正方向
        {
            m_endTo1.X = m_end.X - m_d;
            m_endTo2.X = m_endTo1.X;

            m_endTo1.Y = m_end.Y - m_d2;
            m_endTo2.Y = m_end.Y + m_d2;
        }
        else  //負方向
        {
            m_endTo1.X = m_end.X + m_d;
            m_endTo2.X = m_endTo1.X;

            m_endTo1.Y = m_end.Y - m_d2;
            m_endTo2.Y = m_end.Y + m_d2;
        }//end if

        return;
    }
    else if(m_lineDirection.Parallelism==Parallelism::PARALLEL_WITH_Y)  //y軸と平行
    {
        if(m_lineDirection.ArrowDirection==JdrArrowDirection::POSITIVE)  //正方向
        {
            m_endTo1.Y = m_end.Y - m_d;
            m_endTo2.Y = m_endTo1.Y;

            m_endTo1.X = m_end.X + m_d2;
            m_endTo2.X = m_end.X - m_d2;
        }
        else  //負方向
        {
            m_endTo1.Y = m_end.Y + m_d;
            m_endTo2.Y = m_endTo1.Y;

            m_endTo1.X = m_end.X + m_d2;
            m_endTo2.X = m_end.X - m_d2;
        }//end if

        return;
    }//end if

    //座標軸と平行しない直線の矢印の両点を計算する>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    float m1 = (m_end.Y-m_start.Y) / (m_end.X-m_start.X);

    float x3 = 0;
    float y3 = 0;
    if(m_lineDirection.ArrowDirection==JdrArrowDirection::POSITIVE)  //正方向
    {
        x3 = m_end.X - (float)Math::Sqrt((m_d*m_d)/(1+m1*m1));
    }
    else
    {
        x3 = m_end.X + (float)Math::Sqrt((m_d*m_d)/(1+m1*m1));
    }//end if

    y3 = m1 * (x3-m_end.X) + m_end.Y;

    float m2 = -1 / m1;

    m_endTo1.X = x3 + (float)Math::Sqrt((m_d2*m_d2)/(1+m2*m2));
    m_endTo2.X = x3 - (float)Math::Sqrt((m_d2*m_d2)/(1+m2*m2));

    m_endTo1.Y = m2 * (m_endTo1.X-x3) + y3;
    m_endTo2.Y = m2 * (m_endTo2.X-x3) + y3;
    //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}

///
///コンストラクタ
///起点
///終点
///
DevTech::Arrow::JdrArrow::JdrArrow(PointF i_st,PointF i_ed)
{
    m_start = i_st;
    m_end = i_ed;

    //直線の平行性・方向性を判定
    if(m_end.X==m_start.X)  //y軸と平行
    {
        m_lineDirection.Parallelism = Parallelism::PARALLEL_WITH_Y;

        if(m_end.Y>=m_start.Y)  //正方向
            m_lineDirection.ArrowDirection = JdrArrowDirection::POSITIVE;
        else  //負方向
            m_lineDirection.ArrowDirection = JdrArrowDirection::NEGATIVE;
    }
    else  //y軸と平行しない
    {
        if(m_end.Y==m_start.Y)  //x軸と平行
            m_lineDirection.Parallelism = Parallelism::PARALLEL_WITH_X;
        else
            m_lineDirection.Parallelism = Parallelism::DONOT_PARALLEL;

        if(m_end.X>=m_start.X)  //正方向
            m_lineDirection.ArrowDirection = JdrArrowDirection::POSITIVE;
        else
            m_lineDirection.ArrowDirection = JdrArrowDirection::NEGATIVE;
    }//end if

    //矢印の大きさはとりあえず固定値を取る(将来設定可能に)
    m_d = 10;  //高さ
    m_d2 = 5;  //幅

    //矢印の両点を計算
    getArrowPoint();
}

矢印を描画する点座標を計算するクラスは↑の通りである。
使い方:
JdrArrow^ pArrow = gcnew JdrArrow(start Point, end Point);

g->DrawLine(Pens::Red,m_pArrow->StartPoint,m_pArrow->EndPoint);
g->DrawLine(Pens::Red,m_pArrow->EndPoint,m_pArrow->EndTo1);
g->DrawLine(Pens::Red,m_pArrow->EndPoint,m_pArrow->EndTo2);

矢印を描画するクラス(たとえば ref class DrawXXX)を作成するのも一つの案である。

评分

参与人数 1 +88 收起 理由
憨吃迷糊睡 + 88 赞一个

查看全部评分

发表于 2013-4-2 18:40:58 | 显示全部楼层
简单搂了一下代码,感觉除法运算前最好判断一下分母是否为0

另外,要是能把完整的程序放到哪个地方,比如谷歌代码里,共享一下就好了
回复

使用道具 举报

 楼主| 发表于 2013-4-3 14:12:52 | 显示全部楼层
憨吃迷糊睡 发表于 2013-4-2 18:40
简单搂了一下代码,感觉除法运算前最好判断一下分母是否为0

另外,要是能把完整的程序放到哪个地方,比如 ...

是啊  这个我苦恼过了几分钟

当且仅当 直线平行于坐标轴的时候 分母才是零  其他时候不可能为零

而且,在上面已经判断了平行的情况都作了处理了  所以,到了下面绝对不可能是零    ---- 不用判断

但是, 如果上面的代码除了问题,没有控制住而且跑到了下面,分母为零  出异常  (当然,这是bug,最终是需要修改的) ,但是 按照程序不能让他抛异常的思路  ---  用判断

。。。  也没有人商量, 而且反正是自己的小科研  所以姑且这样了  嘿嘿      不愧是楼主, 一下子就看出重点了!

这个类可以直接拿去到自己的工程里用, 什么都不用修改, 也挺方便的   况且,我也没有那些账号,就不放上去了   其实我还是怕麻烦。。。   请见谅

不过, 欢迎感兴趣的朋友们交流   比如,那个公式是怎么导出的阿? 等等。。。 也许数学天才们一下子也就看明白了
回复

使用道具 举报

发表于 2013-4-3 14:43:05 | 显示全部楼层
等待UFO 发表于 2013-4-3 14:12
是啊  这个我苦恼过了几分钟

当且仅当 直线平行于坐标轴的时候 分母才是零  其他时候不可能为零

再逐渐追加些功能吧,比如矢量平移,在平行的位置再画一个箭头

总之,赞一个先
回复

使用道具 举报

发表于 2013-7-7 21:51:01 | 显示全部楼层
CLI有点冷门啊 这个的实现 还是用标准的Win32 GDI做更能广泛的被include吧 另外我有个想法 调用你的函数那一方 仅仅给出坐标 窗口句柄 RGB值等 自己就设计个算法 用什么SetPixel()实现也可以吧
回复

使用道具 举报

 楼主| 发表于 2013-7-17 22:50:50 | 显示全部楼层
queryer 发表于 2013-7-7 21:51
CLI有点冷门啊 这个的实现 还是用标准的Win32 GDI做更能广泛的被include吧 另外我有个想法 调用你的函数那 ...


CLI不是有点 而是完全冷门阿     害我浪费那么多时间来掌握   全白费了  我已经放弃C++/CLI了
回复

使用道具 举报

 楼主| 发表于 2013-7-17 22:52:27 | 显示全部楼层
我再也不发关于 C++/CLI的帖子了
回复

使用道具 举报

发表于 2013-7-20 21:47:16 | 显示全部楼层
等待UFO 发表于 2013-7-17 22:50
CLI不是有点 而是完全冷门阿     害我浪费那么多时间来掌握   全白费了  我已经放弃C++/CLI ...

其实。。。 恩 说话要留余地才说有点。 看目前形式 越来越不敢跟随微软的标准啊 以前那IE6 VC++6的编译器。。。 现在都是被人鄙视的对象了 还有最新的Surface RT 微软肯定很苦恼。。。
回复

使用道具 举报

发表于 2013-7-20 21:54:25 | 显示全部楼层
等待UFO 发表于 2013-7-17 22:50
CLI不是有点 而是完全冷门阿     害我浪费那么多时间来掌握   全白费了  我已经放弃C++/CLI ...

我之前想表达的是 算法 思路什么的不变 但是 不是CLI 是基于Win API基础进行封装, 比如 提供给invoker类似Win API或MFC风格的接口 或封装的类里能设定窗口句柄 关键还应该封装进去GDI绘图的那个device context; 这样传给了DC结构参数 就可以实现设定线的粗细 颜色 线条风格(dashdot solid) 这就更灵活了吧?
回复

使用道具 举报

发表于 2013-7-20 22:55:40 | 显示全部楼层
queryer 发表于 2013-7-20 21:54
我之前想表达的是 算法 思路什么的不变 但是 不是CLI 是基于Win API基础进行封装, 比如 提供给invoker类 ...

迷糊做的项目,底层都被PF屏蔽了,根本不让直接操作OS的API,所以感觉不到差异,(⊙_⊙)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小春网
常务客服微信
微信订阅号
手机客户端
扫一扫,查看更方便! 快速回复 返回顶部 返回列表