3维空间下按平面和圆柱面上排版设计

AR空间中将若干平面窗口排列在指定平面或圆柱体面上

平面排版思路

指定平面方向向量layout_centre ,平面上的一点作为排版版面的中心layout_position

float3 layout_position = float3(0,0,-10);
float3 layout_centre = float3(0,0,1);

每排版完成一个窗口,计算总版面的外包围盒边界

float4 left_top_right_bottom = float4(0, 0, 0, 0);
auto updateBound = [](float4& box, float2 pos, float w, float h) {
    auto half_w = w / 2.0;
    auto half_h = h / 2.0;
    box.x = std::fmin(box.x, pos.x - half_w);
    box.y = std::fmax(box.y, pos.y + half_h);
    box.z = std::fmax(box.z, pos.x + half_w);
    box.w = std::fmin(box.w, pos.y - half_h);
};
auto getNewCentre = [](const float4& box)->float2 {
    return float2((box.z + box.x) / 2.0, (box.y + box.w) / 2.0);
};
先在x0y平面内,将所有窗口在以原点为中心做好排版

这里任意按需求排列好(x,y)坐标

int index = 0;
for (auto element : mLayoutElements) {
    element->mWidth += LAYOUT_PADDING;
    element->mHeight += LAYOUT_PADDING;
    float3 module_tran = float3(0, 0, 0);
    if (index == 0) {
        module_tran.x = -element->mWidth / 2.0;
        module_tran.y = -element->mHeight / 2.0;
    }
    else if (index == 1) {
        module_tran.x = element->mWidth / 2.0;
        module_tran.y = -element->mHeight / 2.0;
    }
    else if (index == 2) {
        module_tran.x = 0;
        module_tran.y = element->mHeight / 2.0;
    }
    updateBound(left_top_right_bottom, module_tran.xy, element->mWidth, element->mHeight); //每加一个排版,更新下外包围盒
    element->mPosition = module_tran;
    index++;
}

将x0y平面下的排版转换到目标平面

//根据外包围盒计算排版的中心基于原点的偏移
float2 centre = getNewCentre(left_top_right_bottom);

for (auto element : mLayoutElements) {
    float3 module_tran = element->mPosition;
    module_tran.xy -= centre; //整个版面移到正中心
    quatf rot_new = quatf::fromDirectedRotation(LAYOUT_LOOK_DIRECTION, normalize(layout_centre));
    float4 tmp = mat4f::translation(layout_position)
        * mat4f(rot_new)
        * module_tran;
    module_tran = tmp.xyz / tmp.w;
    LOGD("rot_new :[%f,%f,%f,%f]", rot_new.x, rot_new.y, rot_new.z, rot_new.w);
    mLayoutResults[element->mID] = LayoutResult::NEW(module_tran, rot_new);
}

上面LAYOUT_LOOK_DIRECTION=float3(0,0,1),为x0y平面朝向Z轴正向的方向,fromDirectedRotation(源码在filement)计算从原始方向LAYOUT_LOOK_DIRECTION转到目标方向layout_centre的旋转四元数,四元素相关知识可自行找资料学习,mat4f::translation(layout_position)将平面位置从原始原点移到目标位置,module_tran和rot_new为最终的位移和旋转

圆柱体表面排版思路

指定圆柱中心轴向量layout_axis ,中心轴经过的一个点layout_axis_point ,圆柱表面上的一点作为排版版面的中心layout_position

例如

float3 layout_position = float3(0,0,-10);
float3 layout_axis = float3(0,1,0);
float3 layout_axis_point = float3(0,0,0);

圆柱型也先将所有窗口在X0Y平面内先排好版,然后将X0Y平面内的版面转换到目标圆柱体面上,具体见下:

layoutGrid->doForeachResult(mLayoutResults,[&](LayoutElement::Ptr element, LayoutResult::Ptr result) {
            float3 module_tran = float3(element->mPosition.xy - newCentre,  0);

            float3 pedal = GetPedalOnLine(layout_axis_point,layout_axis_point+layout_axis,layout_position);
            float3 position_normal = pedal-layout_position;  
            quatf rot_new = quatf::fromDirectedRotation(LAYOUT_LOOK_DIRECTION, normalize(position_normal));

            float4 tmp = mat4f::translation(layout_position)
                         * mat4f(rot_new)
                         * module_tran;
            module_tran = tmp.xyz / tmp.w;

            float radius = distance(pedal, layout_position);
            auto normal = normalize(cross(position_normal,layout_axis));
            auto normal_len =  sphere::projectedLengthAtoB(module_tran-layout_position,normal);
            auto tmp_pos = layout_position + normal *normal_len;

            // module_tran= pedal + normalize(tmp_pos-pedal)*radius+normalize(layout_axis)*abs(sphere::projectedLengthAtoB(module_tran-layout_position,layout_axis));
            // quatf rot_roll= quatf::fromDirectedRotation(normalize(position_normal),normalize(pedal-tmp_pos));

            LOGD("pedal:[%f,%f,%f]",pedal.x,pedal.y,pedal.z);
            float angle_y = 0;
            if(!FuzzyIsZero(radius)) {
                angle_y = normal_len / radius;
            }
            quatf rot_roll = quatf::fromAxisAngle(normalize(layout_axis),angle_y);
            module_tran = pedal + rot_roll * (layout_position-pedal) + normalize(layout_axis)*sphere::projectedLengthAtoB(module_tran-layout_position,layout_axis);
            result->position = module_tran;
            result->rotation = rot_roll * rot_new;
         });

GetPedalOnLine为计算点到一条直线的垂足坐标

[[maybe_unused]] inline float3 GetPedalOnLine(float3 line_start,float3 line_end,  float3 point) {
    float3 v1 = { line_end.x - line_start.x, line_end.y - line_start.y, line_end.z - line_start.z };
    float3 v2 = { point.x - line_start.x, point.y - line_start.y, point.z - line_start.z };
    double t = dot(v2, v1) / dot(v1, v1);
    float3 foot = { line_start.x + t * v1.x, line_start.y + t * v1.y, line_start.z + t * v1.z };
    return foot;
}

圆柱型版面的转换思路为:先把X0Y平面的版面旋转到目标版面的中心layout_position到圆柱轴垂足的方向,然后平移到layout_position,然后将整个版面绕着轴layout_axis 卷起来,有空补个图,搬砖好饿!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值