Path: blob/master/thirdparty/jolt_physics/Jolt/Geometry/ClipPoly.h
9913 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#pragma once56#include <Jolt/Geometry/AABox.h>78JPH_NAMESPACE_BEGIN910/// Clip inPolygonToClip against the positive halfspace of plane defined by inPlaneOrigin and inPlaneNormal.11/// inPlaneNormal does not need to be normalized.12template <class VERTEX_ARRAY>13void ClipPolyVsPlane(const VERTEX_ARRAY &inPolygonToClip, Vec3Arg inPlaneOrigin, Vec3Arg inPlaneNormal, VERTEX_ARRAY &outClippedPolygon)14{15JPH_ASSERT(inPolygonToClip.size() >= 2);16JPH_ASSERT(outClippedPolygon.empty());1718// Determine state of last point19Vec3 e1 = inPolygonToClip[inPolygonToClip.size() - 1];20float prev_num = (inPlaneOrigin - e1).Dot(inPlaneNormal);21bool prev_inside = prev_num < 0.0f;2223// Loop through all vertices24for (typename VERTEX_ARRAY::size_type j = 0; j < inPolygonToClip.size(); ++j)25{26// Check if second point is inside27Vec3Arg e2 = inPolygonToClip[j];28float num = (inPlaneOrigin - e2).Dot(inPlaneNormal);29bool cur_inside = num < 0.0f;3031// In -> Out or Out -> In: Add point on clipping plane32if (cur_inside != prev_inside)33{34// Solve: (X - inPlaneOrigin) . inPlaneNormal = 0 and X = e1 + t * (e2 - e1) for X35Vec3 e12 = e2 - e1;36float denom = e12.Dot(inPlaneNormal);37if (denom != 0.0f)38outClippedPolygon.push_back(e1 + (prev_num / denom) * e12);39else40cur_inside = prev_inside; // Edge is parallel to plane, treat point as if it were on the same side as the last point41}4243// Point inside, add it44if (cur_inside)45outClippedPolygon.push_back(e2);4647// Update previous state48prev_num = num;49prev_inside = cur_inside;50e1 = e2;51}52}5354/// Clip polygon versus polygon.55/// Both polygons are assumed to be in counter clockwise order.56/// @param inClippingPolygonNormal is used to create planes of all edges in inClippingPolygon against which inPolygonToClip is clipped, inClippingPolygonNormal does not need to be normalized57/// @param inClippingPolygon is the polygon which inClippedPolygon is clipped against58/// @param inPolygonToClip is the polygon that is clipped59/// @param outClippedPolygon will contain clipped polygon when function returns60template <class VERTEX_ARRAY>61void ClipPolyVsPoly(const VERTEX_ARRAY &inPolygonToClip, const VERTEX_ARRAY &inClippingPolygon, Vec3Arg inClippingPolygonNormal, VERTEX_ARRAY &outClippedPolygon)62{63JPH_ASSERT(inPolygonToClip.size() >= 2);64JPH_ASSERT(inClippingPolygon.size() >= 3);6566VERTEX_ARRAY tmp_vertices[2];67int tmp_vertices_idx = 0;6869for (typename VERTEX_ARRAY::size_type i = 0; i < inClippingPolygon.size(); ++i)70{71// Get edge to clip against72Vec3 clip_e1 = inClippingPolygon[i];73Vec3 clip_e2 = inClippingPolygon[(i + 1) % inClippingPolygon.size()];74Vec3 clip_normal = inClippingPolygonNormal.Cross(clip_e2 - clip_e1); // Pointing inward to the clipping polygon7576// Get source and target polygon77const VERTEX_ARRAY &src_polygon = (i == 0)? inPolygonToClip : tmp_vertices[tmp_vertices_idx];78tmp_vertices_idx ^= 1;79VERTEX_ARRAY &tgt_polygon = (i == inClippingPolygon.size() - 1)? outClippedPolygon : tmp_vertices[tmp_vertices_idx];80tgt_polygon.clear();8182// Clip against the edge83ClipPolyVsPlane(src_polygon, clip_e1, clip_normal, tgt_polygon);8485// Break out if no polygon left86if (tgt_polygon.size() < 3)87{88outClippedPolygon.clear();89break;90}91}92}9394/// Clip inPolygonToClip against an edge, the edge is projected on inPolygonToClip using inClippingEdgeNormal.95/// The positive half space (the side on the edge in the direction of inClippingEdgeNormal) is cut away.96template <class VERTEX_ARRAY>97void ClipPolyVsEdge(const VERTEX_ARRAY &inPolygonToClip, Vec3Arg inEdgeVertex1, Vec3Arg inEdgeVertex2, Vec3Arg inClippingEdgeNormal, VERTEX_ARRAY &outClippedPolygon)98{99JPH_ASSERT(inPolygonToClip.size() >= 3);100JPH_ASSERT(outClippedPolygon.empty());101102// Get normal that is perpendicular to the edge and the clipping edge normal103Vec3 edge = inEdgeVertex2 - inEdgeVertex1;104Vec3 edge_normal = inClippingEdgeNormal.Cross(edge);105106// Project vertices of edge on inPolygonToClip107Vec3 polygon_normal = (inPolygonToClip[2] - inPolygonToClip[0]).Cross(inPolygonToClip[1] - inPolygonToClip[0]);108float polygon_normal_len_sq = polygon_normal.LengthSq();109Vec3 v1 = inEdgeVertex1 + polygon_normal.Dot(inPolygonToClip[0] - inEdgeVertex1) * polygon_normal / polygon_normal_len_sq;110Vec3 v2 = inEdgeVertex2 + polygon_normal.Dot(inPolygonToClip[0] - inEdgeVertex2) * polygon_normal / polygon_normal_len_sq;111Vec3 v12 = v2 - v1;112float v12_len_sq = v12.LengthSq();113114// Determine state of last point115Vec3 e1 = inPolygonToClip[inPolygonToClip.size() - 1];116float prev_num = (inEdgeVertex1 - e1).Dot(edge_normal);117bool prev_inside = prev_num < 0.0f;118119// Loop through all vertices120for (typename VERTEX_ARRAY::size_type j = 0; j < inPolygonToClip.size(); ++j)121{122// Check if second point is inside123Vec3 e2 = inPolygonToClip[j];124float num = (inEdgeVertex1 - e2).Dot(edge_normal);125bool cur_inside = num < 0.0f;126127// In -> Out or Out -> In: Add point on clipping plane128if (cur_inside != prev_inside)129{130// Solve: (inEdgeVertex1 - X) . edge_normal = 0 and X = e1 + t * (e2 - e1) for X131Vec3 e12 = e2 - e1;132float denom = e12.Dot(edge_normal);133Vec3 clipped_point = denom != 0.0f? e1 + (prev_num / denom) * e12 : e1;134135// Project point on line segment v1, v2 so see if it falls outside if the edge136float projection = (clipped_point - v1).Dot(v12);137if (projection < 0.0f)138outClippedPolygon.push_back(v1);139else if (projection > v12_len_sq)140outClippedPolygon.push_back(v2);141else142outClippedPolygon.push_back(clipped_point);143}144145// Update previous state146prev_num = num;147prev_inside = cur_inside;148e1 = e2;149}150}151152/// Clip polygon vs axis aligned box, inPolygonToClip is assume to be in counter clockwise order.153/// Output will be stored in outClippedPolygon. Everything inside inAABox will be kept.154template <class VERTEX_ARRAY>155void ClipPolyVsAABox(const VERTEX_ARRAY &inPolygonToClip, const AABox &inAABox, VERTEX_ARRAY &outClippedPolygon)156{157JPH_ASSERT(inPolygonToClip.size() >= 2);158159VERTEX_ARRAY tmp_vertices[2];160int tmp_vertices_idx = 0;161162for (int coord = 0; coord < 3; ++coord)163for (int side = 0; side < 2; ++side)164{165// Get plane to clip against166Vec3 origin = Vec3::sZero(), normal = Vec3::sZero();167if (side == 0)168{169normal.SetComponent(coord, 1.0f);170origin.SetComponent(coord, inAABox.mMin[coord]);171}172else173{174normal.SetComponent(coord, -1.0f);175origin.SetComponent(coord, inAABox.mMax[coord]);176}177178// Get source and target polygon179const VERTEX_ARRAY &src_polygon = tmp_vertices_idx == 0? inPolygonToClip : tmp_vertices[tmp_vertices_idx & 1];180tmp_vertices_idx++;181VERTEX_ARRAY &tgt_polygon = tmp_vertices_idx == 6? outClippedPolygon : tmp_vertices[tmp_vertices_idx & 1];182tgt_polygon.clear();183184// Clip against the edge185ClipPolyVsPlane(src_polygon, origin, normal, tgt_polygon);186187// Break out if no polygon left188if (tgt_polygon.size() < 3)189{190outClippedPolygon.clear();191return;192}193194// Flip normal195normal = -normal;196}197}198199JPH_NAMESPACE_END200201202