1. 说明

基本的 Jig 拖动支持在创建/编辑一个实体的过程中,移动光标的同时实体的外观同步变化,但是很多情况下我们希望能有多个实体同时变化.

本节介绍一个例子, 沿一个圆弧实体等间距放置若干个图块,用户拖动光标时圆弧的形状发生变化,同时插入的块参照的位置也会随之变化.

2. 思路

Jig 一拖多可以考虑两种实现思路:

(1) 在entity 函数中返回一个长度为0的直线(欺骗AutoCAD,让AutoCAD更新这条直线的行为不会影响到图形窗口中的显示),在 update 函数中,根据需要打开多个需要同步变化的实体,对其参数进行修改,然后关闭它。

(2) 创建一个自定义实体,entity 函数中返回这个自定义实体的指针,在update函数中,修改自定义实体的一些参数,引起自定义实体的重新操作,在自定义实体的 worldDraw 函数中调用子实体(子实体就是需要拖动的多个实体)完成拖动绘制。

3. 步骤

(1) 添加 CArcBlockJigEntity 新类, 父类设置为 AcDbEntity

MyWorldDraw函数               完成自定义实体的绘制
SetEndPoint函数                 函数在拖动过程中动态修改圆弧的终点,它会引发自定义实体的绘                                                  制,也就是 MyWorldDraw 函数被调用
PostToModelSpace函数      函数能将动态显示的子实体添加到模型空间
GetBlkRefIds函数                将PostToModelSpace函数中添加的块参照ID集合返回到外部调用函数
DrawOrAddSubEnts函数    将worldDraw和PostModelSpace中公用的代码封装起来便于重用

class CArcBlockJigEntity : public AcDbEntity
{
public:// 参数:startPoint:起始点;endPoint:终止点;thirdPoint:第三点;// blockId:块的id;  count:插入块的个数CArcBlockJigEntity(const AcGePoint3d &startPoint, const AcGePoint3d &thirdPoint, const AcGePoint3d &endPoint, AcDbObjectId blkDefId, int count);virtual ~CArcBlockJigEntity();// 自定义实体的绘制函数virtual Adesk::Boolean MyWorldDraw(AcGiWorldDraw* mode);// 设置圆弧终点的位置void SetEntPoint(const AcGePoint3d &pt);// 将圆弧和块添加到模型空间void PostToModelSpace();// 获得添加的块参照集合AcDbObjectIdArray GetBlkRefIds();private://绘制实体或添加到模型空间void DrawOrAddSubEnts(AcGiWorldDraw* mode);private:AcGePoint3d m_startPoint, m_endPoint, m_thirdPoint;// 圆弧的起点、终点和第三点(圆弧上位于起点和终点中间的一点)AcDbObjectId m_blkDefId; // 块定义IDint m_blockCount;  // 要布置的块参照的数量AcDbObjectIdArray m_blkRefIds;  // 添加的块参照集合};

(2) 构造函数初始化

CArcBlockJigEntity::CArcBlockJigEntity(const AcGePoint3d &startPoint, const AcGePoint3d &thirdPoint, const AcGePoint3d &endPoint, AcDbObjectId blkDefId, int count)
{m_startPoint = startPoint;m_thirdPoint = thirdPoint;m_endPoint = endPoint;m_blkDefId = blkDefId;m_blockCount = count;
}CArcBlockJigEntity::~CArcBlockJigEntity(void)
{
}

(3) 绘制

MyWorldDraw 函数会在图形窗口中显示圆弧和块参照子实体,负责拖动过程中的显示更新,

PostToModelSpace函数则会将这些子实体添加到模型空间,负责拖动完整之后将子实体添加到模型空间。

这两个函数的处理逻辑完全一致,不同的在于结果体现不一样,一个是在图形窗口中绘制,另外一个添加到模型空间.DrawOrAddSubEnts 函数封装了两个函数中公用的代码,这样就可以将相同的逻辑用一个函数来体现.

A . 判断给定的三点是否共线,如果共线,就要用直线段来代替圆弧

    // 判断给定的三点是否共线static bool ThreePointIsCollinear(const AcGePoint2d &pt1, const AcGePoint2d &pt2, const AcGePoint2d &pt3); // 判断给定的三点是否共线
// 判断给定的三点是否共线
bool CGeometryOper::ThreePointIsCollinear(const AcGePoint2d &pt1, const AcGePoint2d &pt2, const AcGePoint2d &pt3)
{double xy = pt1.x * pt1.x + pt1.y * pt1.y;double xyse = xy - pt3.x * pt3.x - pt3.y * pt3.y;double xysm = xy - pt2.x * pt2.x - pt2.y * pt2.y;xy = (pt1.x - pt2.x) * (pt1.y - pt3.y) - (pt1.x - pt3.x) * (pt1.y - pt2.y);return (fabs(xy) < 1.0E-5);
}

B. 在图形窗口中直接绘制圆弧/直线段的方法:

mode->geometry().polyline(2, verts);
mode->geometry().circularArc(m_startPoint, m_thirdPoint, m_endPoint);

C. 为了计算圆弧或直线段的等分点, 我们使用AcDbCurve提供的一些成员函数,如果三点共线,创建一条直线段,否则就创建圆弧实体.

创建直线段的代码为:

pCurve = new AcDbLine(m_startPoint, m_endPoint);

D. 判断顺时针还是逆时针(AcDbArc对象构建时默认是逆时针)

判断方式: 终点在起点-中间点连线的左侧还是右侧

    // 判断绘画圆弧时是顺时针还是逆时针static int PtInLeftOfLine(const AcGePoint3d &ptStart, const AcGePoint3d &ptEnd, const AcGePoint3d &pt, double tol = 1.0E-7);static int PtInLeftOfLine(const AcGePoint2d &ptStart, const AcGePoint2d &ptEnd, const AcGePoint2d &pt, double tol = 1.0E-7);static int PtInLeftOfLine(double x1, double y1, double x2, double y2, double x3, double y3, double tol = 1.0E-7);
// 判断绘画圆弧时是顺时针还是逆时针
int CGeometryOper::PtInLeftOfLine(const AcGePoint3d &ptStart, const AcGePoint3d &ptEnd, const AcGePoint3d &pt, double tol)
{return PtInLeftOfLine(ptStart.x, ptStart.y, ptEnd.x, ptEnd.y, pt.x, pt.y, tol);
}int CGeometryOper::PtInLeftOfLine(const AcGePoint2d &ptStart, const AcGePoint2d &ptEnd, const AcGePoint2d &pt, double tol)
{return PtInLeftOfLine(ptStart.x, ptStart.y, ptEnd.x, ptEnd.y, pt.x, pt.y, tol);
}int CGeometryOper::PtInLeftOfLine(double x1, double y1, double x2, double y2, double x3, double y3, double tol)
{// 两个矢量的叉乘结果是一个,矢量的行列式值是这两个矢量确定的平行四边形的面积double a = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);if (fabs(a) < tol){return 0;}else if (a > 0){return 1;}else{return -1;}
}

E. 二维三维点转换

    static AcGePoint2d ToPoint2d(const AcGePoint3d &point3d);static AcGePoint3d ToPoint3d(const AcGePoint2d &point2d, double z = 0)
AcGePoint2d CGeometryOper::ToPoint2d(const AcGePoint3d &point3d)
{return AcGePoint2d(point3d.x, point3d.y);
}AcGePoint3d CGeometryOper::ToPoint3d(const AcGePoint2d &point2d, double z)
{return AcGePoint3d(point2d.x, point2d.y, z);
}

F. 准备函数完成,

//绘制实体或添加到模型空间,封装
void CArcBlockJigEntity::DrawOrAddSubEnts(AcGiWorldDraw* mode)
{//绘制圆弧AcDbCurve *pCurve = NULL;  //计算等分点的曲线AcGePoint2d startPoint2d = CGeometryOper::ToPoint2d(m_startPoint);AcGePoint2d thirdPoint2d = CGeometryOper::ToPoint2d(m_thirdPoint);AcGePoint2d endPoint2d = CGeometryOper::ToPoint2d(m_endPoint);if (CGeometryOper::ThreePointIsCollinear(startPoint2d, thirdPoint2d, endPoint2d)){AcGePoint3d verts[2];verts[0] = m_startPoint;verts[1] = m_endPoint;if (mode != NULL){mode->geometry().polyline(2, verts);}pCurve = new AcDbLine(m_startPoint, m_endPoint);//创建直线段}else{if (mode != NULL){mode->geometry().circularArc(m_startPoint, m_thirdPoint, m_endPoint);}AcGeCircArc2d geArc(startPoint2d, thirdPoint2d, endPoint2d);//geArc的起始角度始终是0,因此单独计算起始角度和终止角度AcGeVector2d vecStart = startPoint2d - geArc.center();AcGeVector2d vecEnd = endPoint2d - geArc.center();//AcGeArc必须是逆时针,因此需要根据三点的旋转方向,确定正确的起始角度double startAngle = 0;if (CGeometryOper::PtInLeftOfLine(startPoint2d, thirdPoint2d, endPoint2d) > 0)//逆时针{startAngle = vecStart.angle();}else{startAngle = vecEnd.angle();}double endAngle = startAngle + (geArc.endAng() - geArc.startAng());pCurve = new AcDbArc(CGeometryOper::ToPoint3d(geArc.center()), geArc.radius(),startAngle, endAngle);//计算等分点,获得块参照插入的位置double startParam = 0, endParam = 0;   //曲线的起点和终点参数pCurve->getStartParam(startParam);pCurve->getEndParam(endParam);int intervalCount = m_blockCount + 1;  //等分间距份数比块参照数量大1double paramInterval = (endParam - startParam) / intervalCount;AcGePoint3dArray blkRefPoints;  //块参照插入点的集合for (int i = 1; i < intervalCount; i++) //曲线的起点和终点不需要放置图块{double param = startParam + i * paramInterval;AcGePoint3d pt;pCurve->getPointAtParam(param, pt);blkRefPoints.append(pt);}if (mode != NULL) //显示子实体{delete pCurve; //动态分配的实体,不加入模型空间,使用完毕之后需要释放}else  //添加子实体的方式{CCreateEnt::PostToModelSpace(pCurve);}//绘制几个图块m_blkRefIds.setLogicalLength(0);for (int i = 0; i < blkRefPoints.length(); i++){AcDbBlockReference *pBlkRef = new AcDbBlockReference(blkRefPoints[i], m_blkDefId);if (mode != NULL){pBlkRef->worldDraw(mode);delete pBlkRef;}else{m_blkRefIds.append(CCreateEnt::PostToModelSpace(pBlkRef));}}}
}

(4) MyWorldDraw() 函数 PostToModelSpace() 函数

// 自定义实体的绘制函数
Adesk::Boolean CArcBlockJigEntity::MyWorldDraw(AcGiWorldDraw* mode)
{DrawOrAddSubEnts(mode);return Adesk::kTrue;
}// 将圆弧和块添加到模型空间
void CArcBlockJigEntity::PostToModelSpace()
{DrawOrAddSubEnts(NULL);
}

(5) 设置圆弧终点的位置 用于修改自定义实体中的圆弧终点

// 设置圆弧终点的位置 用于修改自定义实体中的圆弧终点
void CArcBlockJigEntity::SetEntPoint(const AcGePoint3d &pt)
{//这句代码能引发MyWorldDraw函数的调用assertWriteEnabled();m_endPoint = pt;
}

(6) 将PostToModelSpace 中添加到模型空间的块参照集合返回到外部调用函数
        获得添加的块参照集合

// 将PostToModelSpace 中添加到模型空间的块参照集合返回到外部调用函数
// 获得添加的块参照集合
AcDbObjectIdArray CArcBlockJigEntity::GetBlkRefIds()
{return m_blkRefIds;
}

(7) 添加新类 CArcBlockJig , 从 AcEdJig 类继承而来

#include "ArcBlockJigEntity.h"
class CArcBlockJig : public AcEdJig
{
public:CArcBlockJig(void);virtual ~CArcBlockJig(void);//参数startPoint:起始点;endPoint:终止点;thirdPoint第三点;//blkDefId块的Id; blockCount:插入块的个数bool doIt(const AcGePoint3d &startPoint, AcGePoint3d &thirdPoint,AcGePoint3d &endPoint, AcDbObjectId blkDefId, int blockCount);//此函数将被drag函数调用以获得一个输入virtual AcEdJig::DragStatus sampler();virtual Adesk::Boolean update();virtual AcDbEntity* entity() const;//制定了Jig所操作的对象//获得Jig操作成功后插入的块的参照集合AcDbObjectIdArray GetBlkRefIds();private:CArcBlockJigEntity* m_pJigEnt;AcGePoint3d m_curPoint;AcDbObjectIdArray m_blkRefIds;};

(8) 构造函数中, 对自定义实体的指针进行初始化,

析构函数中, 销毁自定义实体,

CArcBlockJig::CArcBlockJig(void)
{m_pJigEnt = NULL;
}CArcBlockJig::~CArcBlockJig(void)
{if (m_pJigEnt){delete m_pJigEnt;m_pJigEnt = NULL;}
}

(9) doIt() 函数

// 处理拖动的整个流程
// 参数startPoint:起始点;endPoint:终止点;thirdPoint第三点;
// blkDefId块的Id; blockCount:插入块的个数
bool CArcBlockJig::doIt(const AcGePoint3d &startPoint, AcGePoint3d &thirdPoint, AcGePoint3d &endPoint, AcDbObjectId blkDefId, int blockCount)
{//拖动之前:创建自定义实体if (m_pJigEnt != NULL){delete m_pJigEnt;m_pJigEnt = NULL;}m_pJigEnt = new CArcBlockJigEntity(startPoint, thirdPoint, endPoint, blkDefId, blockCount);//执行拖动绘制CString prompt = _T("\n指定下一点:");setDispPrompt(prompt);AcEdJig::DragStatus stat = drag();//执行之后:根据需要确定自己的处理方式bool bRet = false;if (stat == kNormal){//添加子实体到模型空间m_pJigEnt->PostToModelSpace();bRet = true;}m_blkRefIds = m_pJigEnt->GetBlkRefIds();delete m_pJigEnt;m_pJigEnt = NULL;return bRet;
}

(10) sampler() 函数

// 此函数将被drag函数调用以获得一个输入
AcEdJig::DragStatus CArcBlockJig::sampler()
{setUserInputControls((UserInputControls)( AcEdJig::kAccept3dCoordinates| AcEdJig::kNoNegativeResponseAccepted| AcEdJig::kNullResponseAccepted ));// 一定要判断一下点是否发生了变化,否则update函数不停地被调用,实体反而不能被绘制出来static AcGePoint3d pointTemp;DragStatus stat = acquirePoint(m_curPoint);if (pointTemp != m_curPoint){pointTemp = m_curPoint;}else if (stat == AcEdJig::kNormal){return AcEdJig::kNoChange;}return stat;
}

(11) update() 函数

// 更新自定义实体
Adesk::Boolean CArcBlockJig::update()
{m_pJigEnt->SetEntPoint(m_curPoint);return Adesk::kTrue;
}

(12) entity() 函数

// 返回 AutoCAD 需要动态更新的实体
AcDbEntity* CArcBlockJig::entity() const
{return m_pJigEnt;
}

(13) GetBlkRefIds() 函数

// 将Jig过程中创建的块参照集合返回给外部调用函数
AcDbObjectIdArray CArcBlockJig::GetBlkRefIds()
{return m_blkRefIds;
}

(14) 添加一个测试函数进行测试

    static void ArcBlockJig(); //测试函数
// 测试
void CArcBlockJig::ArcBlockJig()
{//选择一个块参照,用于沿圆弧插入AcDbEntity *pEnt = NULL;AcDbObjectId blkDefId;AcGePoint3d pickPoint;if (CArcBlockJig::PromptSelectEntity(_T("\n 选择一个块参照用于沿圆弧插入:"), AcDbBlockReference::desc(), pEnt, pickPoint)){AcDbBlockReference *pBlkRef = AcDbBlockReference::cast(pEnt);blkDefId = pBlkRef->blockTableRecord();pEnt->close();}if (blkDefId.isNull()){return;}//提示用户拾取第一点AcGePoint3d startPoint;if (!CArcBlockJig::GetPoint(_T("\n拾取第一点:"), startPoint)){return;}//提示用户拾取第二点AcGePoint3d secondPoint;if (!CArcBlockJig::GetPoint(startPoint, _T("\n拾取第二点:"), secondPoint)){return;}//开始拖动CArcBlockJig jig;int blockCount = 4;jig.doIt(startPoint, secondPoint, secondPoint, blkDefId, blockCount);
}

(15) 需要的函数

    static bool PromptSelectEntity(const TCHAR* prompt, AcRxClass* classDesc, AcDbEntity *&pEnt,AcGePoint3d &pickPoint, bool bOpenForWrite = true);static bool PromptSelectEntity(const TCHAR* prompt, const std::vector<AcRxClass*> &classDescs, AcDbEntity *&pEnt,AcGePoint3d &pickPoint, bool bOpenForWrite = true);// 提示用户选择一个点(无论当前是否在UCS中工作,直接返回该点的WCS坐标)// basePoint: 基于WCS的点坐标// 返回值:与acedGetPoint函数相同static int GetPointReturnCode(const AcGePoint3d &basePoint, const TCHAR* prompt, AcGePoint3d &point);static bool GetPoint(const AcGePoint3d &basePoint, const TCHAR* prompt, AcGePoint3d &point);static int GetPointReturnCode(const TCHAR* prompt, AcGePoint3d &point);static bool GetPoint(const TCHAR* prompt, AcGePoint3d &point);// 将一个点从用户坐标系坐标转换到世界坐标系static AcGePoint3d UcsToWcsPoint(const AcGePoint3d &point);// 将一个点从世界坐标系坐标转换到显示坐标系static AcGePoint3d WcsToUcsPoint(const AcGePoint3d &point);
bool CArcBlockJig::PromptSelectEntity(const TCHAR* prompt, AcRxClass* classDesc, AcDbEntity *&pEnt,AcGePoint3d &pickPoint, bool bOpenForWrite /*= true*/)
{std::vector<AcRxClass*> descs;  //#include <vector>descs.push_back(classDesc);return PromptSelectEntity(prompt, descs, pEnt, pickPoint, bOpenForWrite);
}bool CArcBlockJig::PromptSelectEntity(const TCHAR* prompt, const std::vector<AcRxClass*> &classDescs, AcDbEntity *&pEnt,AcGePoint3d &pickPoint, bool bOpenForWrite /*= true*/)
{ads_name ename;
RETRY:if (acedEntSel(prompt, ename, asDblArray(pickPoint)) != RTNORM){pEnt = NULL;return false;}AcDbObjectId entId;acdbGetObjectId(entId, ename);// 判断选择的实体是否是指定类型的实体Acad::ErrorStatus es;if (bOpenForWrite){es = acdbOpenObject(pEnt, entId, AcDb::kForWrite);}else{es = acdbOpenObject(pEnt, entId, AcDb::kForRead);}assert(es == Acad::eOk);bool bRet = false;for (int i = 0; i < (int)classDescs.size(); i++){if (pEnt->isKindOf(classDescs[i])){bRet = true;break;}}if (bRet){return true;}else{pEnt->close();acutPrintf(_T("\n选择的实体类型不合要求, 请再次选择..."));goto RETRY;}
}int CArcBlockJig::GetPointReturnCode(const AcGePoint3d &basePoint, const TCHAR* prompt, AcGePoint3d &point)
{// 将基点转换为UCS坐标AcGePoint3d ucsBasePoint = CArcBlockJig::WcsToUcsPoint(basePoint);int nReturn = acedGetPoint(asDblArray(ucsBasePoint), prompt, asDblArray(point));if (nReturn == RTNORM){// acedGetPoint得到UCS坐标,转换为WCSpoint = CArcBlockJig::UcsToWcsPoint(point);}return nReturn;
}int CArcBlockJig::GetPointReturnCode(const TCHAR* prompt, AcGePoint3d &point)
{int nReturn = acedGetPoint(NULL, prompt, asDblArray(point));if (nReturn == RTNORM){point = CArcBlockJig::UcsToWcsPoint(point);}return nReturn;
}bool CArcBlockJig::GetPoint(const AcGePoint3d &basePoint, const TCHAR* prompt, AcGePoint3d &point)
{return (GetPointReturnCode(basePoint, prompt, point) == RTNORM);
}bool CArcBlockJig::GetPoint(const TCHAR* prompt, AcGePoint3d &point)
{return (GetPointReturnCode(prompt, point) == RTNORM);
}AcGePoint3d CArcBlockJig::UcsToWcsPoint(const AcGePoint3d &point)
{// 转换成世界坐标 AcGePoint3d pt;struct resbuf rbFrom, rbTo;rbFrom.restype = RTSHORT;rbFrom.resval.rint = 1; // from UCSrbTo.restype = RTSHORT;rbTo.resval.rint = 0; // to WCSacedTrans(asDblArray(point), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(pt));return pt;
}AcGePoint3d CArcBlockJig::WcsToUcsPoint(const AcGePoint3d &point)
{// 转换成世界坐标 AcGePoint3d pt;struct resbuf rbFrom, rbTo;rbFrom.restype = RTSHORT;rbFrom.resval.rint = 0; // from WCSrbTo.restype = RTSHORT;rbTo.resval.rint = 1; // to UCSacedTrans(asDblArray(point), &rbFrom, &rbTo, Adesk::kFalse, asDblArray(pt));return pt;
}

(16) 在acrxEntryPoint.cpp中

ACED_ARXCOMMAND_ENTRY_AUTO(CArxConfigApp, MidasMyGroup, MyArcBlockJig, MyArcBlockJig, ACRX_CMD_MODAL, NULL) //Jig圆弧上分段画选择的块
    //当前项目中注册命令 ArcBlockJig (Jig圆弧上分段画选择的块)static void MidasMyGroupMyArcBlockJig(){CDrawSquareJig::DrawSequareJig();}

效果展示:

1. 创建块

2. 输入命令MyArcBlockJig

(42)ObjectARX2015 + vs2012 JIG-一拖多相关推荐

  1. (14)ObjectARX2015 + vs2012创建和编辑对象时的动态拖动技术

    提示:看之前的博客(1)(4)和(12),那里已经分析了创建一个图形对象的基本过程,在之前的基础上本节开始就要将着眼点放在创建实体的参数上. (1)ObjectARX2015 + vs2012创建直线 ...

  2. (15)ObjectARX2015 + vs2012创建三维实体

    1. 说明         ObjectARX 中提供了三类创建三维实体的方法:                 (1)创建标准形状的实体                 (2)拉伸面域创建实体    ...

  3. (6)ObjectARX2015 + vs2012创建圆弧

    提示:看之前的博客(1)和(4),那里已经分析了创建一个图形对象的基本过程,在之前的基础上本节开始就要将着眼点放在创建实体的参数上. (1)ObjectARX2015 + vs2012创建直线_qq_ ...

  4. (7)ObjectARX2015 + vs2012创建多段线以及实体的旋转移动放缩

    提示:看之前的博客(1)和(4),那里已经分析了创建一个图形对象的基本过程,在之前的基础上本节开始就要将着眼点放在创建实体的参数上. (1)ObjectARX2015 + vs2012创建直线_qq_ ...

  5. (9)ObjectARX2015 + vs2012创建面域

    提示:看之前的博客(1)和(4),那里已经分析了创建一个图形对象的基本过程,在之前的基础上本节开始就要将着眼点放在创建实体的参数上. (1)ObjectARX2015 + vs2012创建直线_qq_ ...

  6. (12)ObjectARX2015 + vs2012创建尺寸标注

    提示:看之前的博客(1)和(4),那里已经分析了创建一个图形对象的基本过程,在之前的基础上本节开始就要将着眼点放在创建实体的参数上. (1)ObjectARX2015 + vs2012创建直线_qq_ ...

  7. (41)ObjectARX2015 + vs2012 JIG-基本的拖动

    1. 说明 拖动效果在AutoCAD中被广泛应用, 他在创建/修改实体时具有所见即所得的特点.本节介绍AutoCAD提供的最基本的Jig实现, 采用的例子是用拖动的方式来创建一个正方形. 2. 思路 ...

  8. (31)ObjectARX2015 + vs2012选择集

    1. 说明         在 ObjectARX 开发过程中,经常需要用户和 AutoCAD 之间进行交互操作,除了前面介绍的acedGetXX系列函数之外,选择集是AutoCAD和用户交互操作的重 ...

  9. (34)ObjectARX2015 + vs2012组字典

    1. 说明         本篇的实例演示编组的创建和删除.在 AutoCAD 中,可以使用 Group 命令来创建和删除编组,但是在 ObjectARX 中就没有直接的函数来创建和删除组,必须通过组 ...

最新文章

  1. MyBatis处理多参数及原理分析
  2. C++中各种智能指针的实现及弊端(四)
  3. 结对项目——最大子数组
  4. 山东栋梁机器人比赛_谁是最强“移动机器人”?来深技师这场全国大赛一决高下!...
  5. 求字符串中字符的出现的最多次数和最少次数,删除后并获得最终字符
  6. Safari、IE8、iPhone和BlackBerry在Pwn2Own竞赛中被挑落
  7. matlab进阶摸索篇——彩色图直方图均衡化
  8. Linux 进程热升级 共享库的动态替换
  9. 电子学习资料/电子设计/电子竞赛/产品设计/产品开发(吐血推荐)
  10. magisk mask面具自动打卡
  11. linux mysql 视频教程_Linux视频教程基础入门到精通Shell高级编程实战/Nginx/MySQL运维视频教程下载...
  12. 老板开会要用Word文档?立马做了一款无限次且免费的PDF转Word小程序。
  13. SAP 离散,流程,重复制造
  14. win10 matlab打开,win10系统启动matlab出现闪退的处理步骤
  15. Linux v4l2 一 应用层
  16. python电影爬虫背景介绍_Python爬虫入门教程01之爬取豆瓣Top电影
  17. python helper方法_Python io_utils.ImportHelper方法代碼示例
  18. 树莓派使用排线摄像头和远程视频监控
  19. 玩转华为数据中心交换机系列 | 配置基于MAC地址划分VLAN示例
  20. vsimk is exiting with code 211

热门文章

  1. 什么软件可以搜索计算机知识,生活必备电脑知识技巧大全
  2. 程序包无效 “CRX_HEADER_INVALID”
  3. 中文Metalink文档
  4. pyqt5 多线程实时拉流并播放,画面流畅无卡顿
  5. VIM插件安装和配置
  6. Censorship
  7. #考试酷#A9_Bitwise Operators
  8. 我为儿子关云雷命名的出处
  9. 对于iphone X 兼容性处理的css适配方法和js适配方法
  10. Nginx搭建文件服务器实现文件上传