Merge Release 0.6.0

Merge Release 0.6.0
This commit is contained in:
Yousef Khadadeh 2026-06-04 09:35:35 +00:00 • committed by GitHub
commit f82b3185a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
722 changed files with 82971 additions and 1536 deletions

View file

@ -71,6 +71,7 @@ set(sources "src/main.cpp"
"src/RichText/TextBox.cpp"
"src/RichText/TextStyleModifier.cpp"
"src/RichText/ParagraphStyleData.cpp"
"src/DrawingProgram/EditCanvasComponentWorldUndoAction.cpp"
"src/DrawingProgram/ToolConfiguration.cpp"
"src/DrawingProgram/DrawingProgramSelection.cpp"
"src/DrawingProgram/DrawingProgramCache.cpp"
@ -95,7 +96,7 @@ set(sources "src/main.cpp"
"src/DrawingProgram/Tools/EditTools/EllipseDrawEditTool.cpp"
"src/DrawingProgram/Tools/EditTools/RectDrawEditTool.cpp"
"src/DrawingProgram/Tools/EditTools/TextBoxEditTool.cpp"
"src/DrawingProgram/Tools/EditTools/BrushEditTool.cpp"
"src/DrawingProgram/Tools/EditTools/MeshEditTool.cpp"
"src/DrawingProgram/Layers/DrawingProgramLayerManagerGUI.cpp"
"src/DrawingProgram/Layers/DrawingProgramLayerManager.cpp"
"src/DrawingProgram/Layers/DrawingProgramLayerListItem.cpp"
@ -104,11 +105,12 @@ set(sources "src/main.cpp"
"src/DrawingProgram/Layers/SerializedBlendMode.cpp"
"src/CanvasComponents/CanvasComponentContainer.cpp"
"src/CanvasComponents/CanvasComponentAllocator.cpp"
"src/CanvasComponents/BrushStrokeCanvasComponent.cpp"
"src/CanvasComponents/MeshCanvasComponent.cpp"
"src/CanvasComponents/RectangleCanvasComponent.cpp"
"src/CanvasComponents/TextBoxCanvasComponent.cpp"
"src/CanvasComponents/EllipseCanvasComponent.cpp"
"src/CanvasComponents/ImageCanvasComponent.cpp"
"src/CanvasComponents/BrushComponentCode.cpp"
"src/CanvasComponents/CanvasComponent.cpp"
"src/GUIStuff/GUIManager.cpp"
"src/GUIStuff/GUIFloatAnimation.cpp"
@ -228,6 +230,7 @@ if((NOT (GRAPHICS_BACKEND STREQUAL "Vulkan")) AND (NOT EMSCRIPTEN) AND LINUX AND
endif()
find_package(zstd REQUIRED)
find_package(clipper2 REQUIRED)
message("Skia root: " ${SKIA_INCLUDE})
message("Build type: " ${CMAKE_BUILD_TYPE})
@ -252,8 +255,8 @@ elseif(APPLE)
BUNDLE True
MACOSX_BUNDLE_GUI_IDENTIFIER com.infinipaint.infinipaint
MACOSX_BUNDLE_BUNDLE_NAME infinipaint
MACOSX_BUNDLE_BUNDLE_VERSION "0.5.0"
MACOSX_BUNDLE_SHORT_VERSION_STRING "0.5.0"
MACOSX_BUNDLE_BUNDLE_VERSION "0.6.0"
MACOSX_BUNDLE_SHORT_VERSION_STRING "0.6.0"
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/macosinstall/Info.plist
)
add_custom_command(TARGET main POST_BUILD
@ -357,7 +360,7 @@ if((NOT EMSCRIPTEN) AND (NOT APPLE) AND (NOT ANDROID))
endif()
endif()
target_link_libraries(main zstd::libzstd_static)
target_link_libraries(main zstd::libzstd_static Clipper2::clipper2)
if((NOT EMSCRIPTEN) AND WIN32)
target_link_libraries(main dwrite)
@ -448,7 +451,7 @@ if(APPLE OR WIN32)
set(CPACK_PACKAGE_NAME "infinipaint")
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "5")
set(CPACK_PACKAGE_VERSION_MINOR "6")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_VENDOR "ErrorAtLine0")
set(CPACK_PACKAGE_CONTACT "erroratline0@gmail.com")

View file

@ -34,8 +34,8 @@ android {
applicationId 'com.erroratline0.InfiniPaint'
minSdkVersion 27
targetSdk 36
versionCode 1
versionName "0.5.0"
versionCode 2
versionName "0.6.0"
externalNativeBuild {
cmake {
cppFlags "-fexceptions", "-frtti"
@ -96,4 +96,5 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.core:core:1.18.0"
}

View file

@ -22,6 +22,9 @@
void updateTextboxAndCursorPos(java.lang.String, int, int);
void startNetworkService();
void stopNetworkService();
void shareText(java.lang.String);
void shareInternalFiles(java.lang.String[], java.lang.String);
java.lang.String getFileNameFromUriString(java.lang.String);
}
-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLActivity {

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
android:versionCode="2"
android:versionName="0.6.0"
android:installLocation="auto">
<!-- OpenGL ES 2.0 -->
@ -89,15 +89,26 @@
android:value="When connected to a server/hosting a server, keep the connection alive even when the application is in the background."/>
</service>
<provider
android:name="com.erroratline0.infinipaint.InfiniPaintFileProvider"
android:authorities="com.erroratline0.infinipaint.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<activity android:name="com.erroratline0.infinipaint.InfiniPaint"
android:label="@string/app_name"
android:windowSoftInputMode="adjustNothing"
android:alwaysRetainTaskState="true"
android:launchMode="singleTop"
android:launchMode="singleTask"
android:configChanges="layoutDirection|locale|grammaticalGender|fontScale|fontWeightAdjustment|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:preferMinimalPostProcessing="true"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

View file

@ -18,11 +18,16 @@
package com.erroratline0.infinipaint;
import static androidx.core.content.FileProvider.getUriForFile;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.provider.OpenableColumns;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@ -35,6 +40,9 @@ import org.libsdl.app.SDLActivity;
import org.libsdl.app.SDLDummyEdit;
import org.libsdl.app.SDLSurface;
import java.io.File;
import java.util.ArrayList;
public class InfiniPaint extends SDLActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -148,4 +156,83 @@ public class InfiniPaint extends SDLActivity {
static public void stopNetworkService() {
mSingleton.stopService(new Intent(mSingleton, InfiniPaintNetworkService.class));
}
static public void shareInternalFiles(String[] filePaths, String mimeType) {
if(filePaths.length == 1) {
File newFile = new File(getContext().getFilesDir(), filePaths[0]);
Uri contentUri;
try {
contentUri = getUriForFile(getContext(), "com.erroratline0.infinipaint.fileprovider", newFile);
} catch (Exception e) {
Log.v("INFO", "[shareInternalFile] Exception " + e);
return;
}
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
sendIntent.setType(mimeType);
Intent shareIntent = Intent.createChooser(sendIntent, null);
getContext().startActivity(shareIntent);
}
else if(filePaths.length > 1) {
ArrayList<Uri> arrayList = new ArrayList<Uri>();
for(String str : filePaths) {
File newFile = new File(getContext().getFilesDir(), str);
try {
arrayList.add(getUriForFile(getContext(), "com.erroratline0.infinipaint.fileprovider", newFile));
} catch (Exception e) {
Log.v("INFO", "[shareInternalFile] Exception " + e);
return;
}
}
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
sendIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, arrayList);
sendIntent.setType(mimeType);
Intent shareIntent = Intent.createChooser(sendIntent, null);
getContext().startActivity(shareIntent);
}
}
static public void shareText(String textToSend) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textToSend);
sendIntent.setType("text/plain");
Intent shareIntent = Intent.createChooser(sendIntent, null);
getContext().startActivity(shareIntent);
}
// https://stackoverflow.com/a/25005243
static public String getFileNameFromUriString(String strUri) {
if(strUri == null)
return null;
Uri uri = Uri.parse(strUri);
if(uri == null)
return null;
String result = null;
if (uri.getScheme() != null && uri.getScheme().equals("content")) {
Cursor cursor = getContext().getContentResolver().query(uri, null, null, null, null);
try {
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));
}
} finally {
if(cursor != null)
cursor.close();
}
}
if (result == null) {
result = uri.getPath();
if(result == null)
return null;
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
}

View file

@ -0,0 +1,9 @@
package com.erroratline0.infinipaint;
import androidx.core.content.FileProvider;
public class InfiniPaintFileProvider extends FileProvider {
public InfiniPaintFileProvider() {
super(R.xml.file_paths);
}
}

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="infinipaint_saves" path="saves/" />
</paths>

View file

@ -6,7 +6,7 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.7.3'
classpath 'com.android.tools.build:gradle:8.13.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View file

@ -10,6 +10,7 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
android.useAndroidX=true
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit

View file

@ -1,6 +1,6 @@
#Thu Nov 11 18:20:34 PST 2021
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M3 19H21V21H3V19ZM13 13.1716L19.0711 7.1005L20.4853 8.51472L12 17L3.51472 8.51472L4.92893 7.1005L11 13.1716V2H13V13.1716Z"></path></svg>

After

Width:  |  Height:  |  Size: 225 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M13.1202 17.0228L8.92129 14.7324C8.19135 15.5125 7.15261 16 6 16C3.79086 16 2 14.2091 2 12C2 9.79086 3.79086 8 6 8C7.15255 8 8.19125 8.48746 8.92118 9.26746L13.1202 6.97713C13.0417 6.66441 13 6.33707 13 6C13 3.79086 14.7909 2 17 2C19.2091 2 21 3.79086 21 6C21 8.20914 19.2091 10 17 10C15.8474 10 14.8087 9.51251 14.0787 8.73246L9.87977 11.0228C9.9583 11.3355 10 11.6629 10 12C10 12.3371 9.95831 12.6644 9.87981 12.9771L14.0788 15.2675C14.8087 14.4875 15.8474 14 17 14C19.2091 14 21 15.7909 21 18C21 20.2091 19.2091 22 17 22C14.7909 22 13 20.2091 13 18C13 17.6629 13.0417 17.3355 13.1202 17.0228ZM6 14C7.10457 14 8 13.1046 8 12C8 10.8954 7.10457 10 6 10C4.89543 10 4 10.8954 4 12C4 13.1046 4.89543 14 6 14ZM17 8C18.1046 8 19 7.10457 19 6C19 4.89543 18.1046 4 17 4C15.8954 4 15 4.89543 15 6C15 7.10457 15.8954 8 17 8ZM17 20C18.1046 20 19 19.1046 19 18C19 16.8954 18.1046 16 17 16C15.8954 16 15 16.8954 15 18C15 19.1046 15.8954 20 17 20Z"></path></svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

View file

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View file

@ -118,6 +118,7 @@ class CompressorRecipe(ConanFile):
self.requires("libdatachannel/0.24.0")
self.requires("libcurl/8.20.0")
self.requires("clipper2/2.0.1")
self.requires("zstd/1.5.7")
self.requires("icu-infinipaint/77.1")

286
include/CDT/CMakeLists.txt Normal file
View file

@ -0,0 +1,286 @@
cmake_minimum_required(VERSION 3.4...4.0)
project(
"CDT"
VERSION 1.4.2
DESCRIPTION
"C++ library for constrained Delaunay triangulation"
HOMEPAGE_URL "https://github.com/artem-ogre/CDT"
LANGUAGES CXX)
# -------
# target
# -------
# export all symbols as we do it by instantiating templates anyway
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
# options
option(CDT_USE_AS_COMPILED_LIBRARY
"If enabled templates for float and double will be instantiated and compiled into a library")
option(CDT_USE_64_BIT_INDEX_TYPE
"If enabled 64bits are used to store vertex/triangle index types. Otherwise 32bits are used (up to 4.2bn items)"
OFF)
option(CDT_ENABLE_CALLBACK_HANDLER
"If enabled it is possible to provide a callback handler to the triangulation"
OFF)
option(CDT_ENABLE_TESTING
"If enabled tests target will ge generated)"
OFF)
option(CDT_USE_STRONG_TYPING
"If enabled uses strong typing for types: useful for development and debugging"
OFF)
option(CDT_DEVELOPER_BUILD
"Enables all warnings."
OFF)
option(CDT_DISABLE_EXCEPTIONS
"Disables exceptions: instead of throwing the library will call `std::terminate`"
OFF)
if(CDT_DEVELOPER_BUILD)
if (MSVC)
# warning level 4 and all warnings as errors
add_compile_options(/W4 /WX)
else()
# lots of warnings and all warnings as errors
add_compile_options(-Wall -Wextra -pedantic -Wno-comment)
endif()
endif()
# check if Boost is needed
if(cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
# Work-around as AppleClang 11 defaults to c++98 by default
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
message(STATUS "AppleClang work-around: set CMAKE_CXX_STANDARD to 11")
set(CMAKE_CXX_STANDARD 11)
endif()
else()
message(STATUS "Compiler does not support C++11: falling back to Boost")
set(CDT_USE_BOOST ON)
endif()
if(CDT_USE_STRONG_TYPING)
set(CDT_USE_BOOST ON)
endif()
message(STATUS "CDT_USE_AS_COMPILED_LIBRARY is ${CDT_USE_AS_COMPILED_LIBRARY}")
message(STATUS "CDT_USE_64_BIT_INDEX_TYPE is ${CDT_USE_64_BIT_INDEX_TYPE}")
message(STATUS "CDT_ENABLE_CALLBACK_HANDLER is ${CDT_ENABLE_CALLBACK_HANDLER}")
message(STATUS "CDT_ENABLE_TESTING is ${CDT_ENABLE_TESTING}")
message(STATUS "CDT_USE_STRONG_TYPING is ${CDT_USE_STRONG_TYPING}")
message(STATUS "CDT_DEVELOPER_BUILD is ${CDT_DEVELOPER_BUILD}")
message(STATUS "CDT_DISABLE_EXCEPTIONS is ${CDT_DISABLE_EXCEPTIONS}")
# Use boost for c++98 versions of c++11 containers or for Boost::rtree
if(CDT_USE_BOOST)
find_package(Boost REQUIRED)
endif()
# configure target
set(cdt_include_dirs
include
extras
)
if(CDT_USE_AS_COMPILED_LIBRARY)
set(cdt_scope PUBLIC)
set(cdt_sources
src/CDT.cpp
)
set(cdt_headers
include/CDT.h
include/CDTUtils.h
include/Triangulation.h
include/KDTree.h
include/LocatorKDTree.h
include/remove_at.hpp
include/CDT.hpp
include/CDTUtils.hpp
include/Triangulation.hpp
include/predicates.h
extras/VerifyTopology.h
extras/InitializeWithGrid.h
)
add_library(${PROJECT_NAME} ${cdt_sources} ${cdt_headers})
# Set symbols visibility to hidden by default
set_target_properties(
${PROJECT_NAME}
PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION}
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN 1
)
# Generate export header and add it to include directories
include(GenerateExportHeader)
generate_export_header(${PROJECT_NAME})
target_include_directories(
${PROJECT_NAME} ${cdt_scope}
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
)
target_sources(
${PROJECT_NAME} ${cdt_scope}
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/cdt_export.h>
)
else()
set(cdt_scope INTERFACE)
add_library(${PROJECT_NAME} INTERFACE)
endif()
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
foreach(dir_ ${cdt_include_dirs})
target_include_directories(
${PROJECT_NAME}
${cdt_scope}
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/${dir_}>
)
endforeach()
target_include_directories(
${PROJECT_NAME} INTERFACE $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_compile_definitions(
${PROJECT_NAME}
${cdt_scope}
$<$<BOOL:${CDT_USE_BOOST}>:CDT_USE_BOOST>
$<$<BOOL:${CDT_USE_AS_COMPILED_LIBRARY}>:CDT_USE_AS_COMPILED_LIBRARY>
$<$<BOOL:${CDT_USE_64_BIT_INDEX_TYPE}>:CDT_USE_64_BIT_INDEX_TYPE>
$<$<BOOL:${CDT_ENABLE_CALLBACK_HANDLER}>:CDT_ENABLE_CALLBACK_HANDLER>
$<$<BOOL:${CDT_USE_STRONG_TYPING}>:CDT_USE_STRONG_TYPING>
$<$<BOOL:${CDT_DISABLE_EXCEPTIONS}>:CDT_DISABLE_EXCEPTIONS>
)
target_link_libraries(${PROJECT_NAME} ${cdt_scope} $<$<BOOL:${CDT_USE_BOOST}>:Boost::boost>)
# -------------
# installation
# -------------
include(GNUInstallDirs)
# install and export the library
foreach(dir_ ${cdt_include_dirs})
install(DIRECTORY ${dir_}/ DESTINATION include)
endforeach()
install(
TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Config
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(
FILES
$<$<BOOL:${CDT_USE_AS_COMPILED_LIBRARY}>:${CMAKE_CURRENT_BINARY_DIR}/cdt_export.h>
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(EXPORT ${PROJECT_NAME}Config NAMESPACE CDT:: DESTINATION cmake)
# ------------
# documentation
# ------------
# work-around to detect custom-doxygen
#set(DOXYGEN_EXECUTABLE /usr/local/bin/doxygen)
find_package(Doxygen 1.9)
if(DOXYGEN_FOUND)
message(STATUS "Doxygen found: adding documentation target.")
set(DOXYGEN_EXCLUDE_PATTERNS
*/cmake-build*
*/predicates.h
conanfile.py
${PROJECT_SOURCE_DIR}/tests/*
)
# doxygen settings can be set here, prefixed with "DOXYGEN_"
set(DOXYGEN_SOURCE_BROWSER YES)
set(DOXYGEN_JAVADOC_AUTOBRIEF YES)
set(DOXYGEN_ENABLE_PREPROCESSING NO)
set(DOXYGEN_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/docs")
set(CDT_DOCS_DIRECTORY ${PROJECT_SOURCE_DIR}/../docs)
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE ${CDT_DOCS_DIRECTORY}/README.md)
set(DOXYGEN_IMAGE_PATH ${CDT_DOCS_DIRECTORY}/images)
set(DOXYGEN_GENERATE_TREEVIEW YES)
set(CDT_DOXYGEN_AWESOME_DIRECTORY ${CDT_DOCS_DIRECTORY}/doxygen-custom/doxygen-awesome)
set(DOXYGEN_HTML_EXTRA_STYLESHEET
${CDT_DOXYGEN_AWESOME_DIRECTORY}/doxygen-awesome.css
${CDT_DOXYGEN_AWESOME_DIRECTORY}/doxygen-awesome-sidebar-only.css
${CDT_DOXYGEN_AWESOME_DIRECTORY}/doxygen-awesome-sidebar-only-darkmode-toggle.css
${CDT_DOCS_DIRECTORY}/doxygen-custom/custom.css
)
set(DOXYGEN_HTML_HEADER ${PROJECT_SOURCE_DIR}/../docs/doxygen-custom/header.html)
set(DOXYGEN_HTML_EXTRA_FILES
${CDT_DOCS_DIRECTORY}/doxygen-custom/logo.svg
${CDT_DOCS_DIRECTORY}/doxygen-custom/favicon/favicon.ico
${CDT_DOCS_DIRECTORY}/doxygen-custom/favicon/apple-touch-icon.png
${CDT_DOCS_DIRECTORY}/doxygen-custom/favicon/android-chrome-192x192.png
${CDT_DOCS_DIRECTORY}/doxygen-custom/favicon/android-chrome-512x512.png
${CDT_DOCS_DIRECTORY}/doxygen-custom/favicon/site.webmanifest
${CDT_DOXYGEN_AWESOME_DIRECTORY}/doxygen-awesome-darkmode-toggle.js
${CDT_DOXYGEN_AWESOME_DIRECTORY}/doxygen-awesome-fragment-copy-button.js
${CDT_DOXYGEN_AWESOME_DIRECTORY}/doxygen-awesome-paragraph-link.js
${CDT_DOXYGEN_AWESOME_DIRECTORY}/toggle-alternative-theme.js
)
set(DOXYGEN_LAYOUT_FILE ${CDT_DOCS_DIRECTORY}/doxygen-custom/DoxygenLayout.xml)
# this target will only be built if specifically asked to.
# run "make api-docs" to create the doxygen documentation
doxygen_add_docs(
${PROJECT_NAME}-docs
${PROJECT_SOURCE_DIR}
${CDT_DOCS_DIRECTORY}
COMMENT "Generate doxygen documentation for CDT."
)
# copy README.md images to doxygen so that they are displayed
add_custom_command(
TARGET ${PROJECT_NAME}-docs POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${PROJECT_SOURCE_DIR}/../docs/images
${DOXYGEN_OUTPUT_DIRECTORY}/html/images
)
endif(DOXYGEN_FOUND)
# ------------
# tests
# ------------
if(CDT_ENABLE_TESTING)
include(CTest)
enable_testing()
# add Catch2
find_package(Catch2 3 QUIET)
if(Catch2_FOUND)
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
else()
set(Catch2_directory ${PROJECT_SOURCE_DIR}/tests/Catch2)
add_subdirectory(${Catch2_directory})
list(APPEND CMAKE_MODULE_PATH ${Catch2_directory}/extras)
endif()
set(TEST_TARGET_NAME ${PROJECT_NAME}-tests)
add_executable(${TEST_TARGET_NAME})
set_property(TARGET ${TEST_TARGET_NAME} PROPERTY CXX_STANDARD 17)
target_sources(${TEST_TARGET_NAME} PRIVATE tests/cdt.test.cpp)
target_link_libraries(
${TEST_TARGET_NAME}
PRIVATE
Catch2::Catch2WithMain
CDT::CDT
)
include(Catch)
catch_discover_tests(${TEST_TARGET_NAME} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/tests")
endif()

373
include/CDT/LICENSE Normal file
View file

@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

View file

@ -0,0 +1,10 @@
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/conanbuildinfo.cmake")
message(STATUS "Detected Conan build: perform conan setup")
include("${CMAKE_CURRENT_SOURCE_DIR}/conanbuildinfo.cmake")
# See: https://docs.conan.io/en/latest/howtos/manage_shared_libraries/rpaths.html#default-conan-approach
if(APPLE)
conan_basic_setup(KEEP_RPATHS)
else()
conan_basic_setup()
endif()
endif()

66
include/CDT/conanfile.py Normal file
View file

@ -0,0 +1,66 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain
from conan.tools.files import collect_libs
class CDTConan(ConanFile):
name = "cdt"
version = "1.3.0"
license = "MPL-2.0 License"
url = "https://github.com/artem-ogre/CDT"
description = "Numerically robust C++ implementation of constrained Delaunay triangulation (CDT)"
settings = "os", "compiler", "build_type", "arch"
generators = "CMakeDeps"
options = {
"shared": [True, False],
"use_boost": [True, False],
"as_compiled_library": [True, False],
"enable_testing": [True, False],
"enable_callback_handler": [True, False],
}
default_options = {
"shared": False,
"use_boost": False,
"as_compiled_library": False,
"enable_testing": False,
"enable_callback_handler": False,
}
exports_sources = "*", "!.idea", "!conanfile.py"
def requirements(self):
if self.options.use_boost:
self.requires("boost/1.83.0")
self.requires("catch2/3.4.0")
def configure(self):
if self.options.use_boost:
self.options["boost"].header_only = True
def generate(self):
tc = CMakeToolchain(self)
tc.variables["CDT_USE_BOOST"] = self.options.use_boost
tc.cache_variables["CDT_USE_AS_COMPILED_LIBRARY"] = (
self.options.as_compiled_library
)
tc.cache_variables["CMAKE_PROJECT_CDT_INCLUDE"] = "conan_basic_setup.cmake"
tc.cache_variables["CDT_ENABLE_TESTING"] = self.options.enable_testing
tc.cache_variables["CDT_ENABLE_CALLBACK_HANDLER"] = self.options.enable_callback_handler
tc.generate()
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
if self.options.enable_testing:
cmake.test(cli_args=["--verbose"])
def package(self):
cmake = CMake(self)
cmake.install()
def package_info(self):
self.cpp_info.libs = collect_libs(self)

View file

@ -0,0 +1,242 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/**
* @file
* Helper function to initialize triangulation with regular grid instead of
* super-triangle
*/
#ifndef CDT_HmXGv083vZCrT3OXASD9
#define CDT_HmXGv083vZCrT3OXASD9
#include <CDT.h>
#include <CDTUtils.h>
#ifdef CDT_CXX11_IS_SUPPORTED
#include <algorithm>
#endif
#include <cstddef>
#include <iterator>
#include <vector>
namespace CDT
{
namespace detail
{
/**
* Generate grid vertices given of X- and Y-ticks
*
* @tparam OutputVertIt output vertices iterator
* @tparam OutputTriIt output triangles iterator
* @tparam TXCoordIter iterator dereferencing to X coordinate
* @tparam TYCoordIter iterator dereferencing to Y coordinate
* @param outFirst the beginning of the destination range
* @param xfirst beginning of X-ticks range
* @param xlast end of X-ticks range
* @param yfirst beginning of Y-ticks range
* @param ylast end of Y-ticks range
*/
template <
typename OutputVertIt,
typename OutputTriIt,
typename TXCoordIter,
typename TYCoordIter>
void generateGridVertices(
OutputVertIt outVertsFirst,
OutputTriIt outTrisFirst,
const TXCoordIter xfirst,
const TXCoordIter xlast,
const TYCoordIter yfirst,
const TYCoordIter ylast)
{
typedef typename std::iterator_traits<TXCoordIter>::value_type T;
const std::size_t xres = std::distance(xfirst, xlast) - 1;
const std::size_t yres = std::distance(yfirst, ylast) - 1;
TXCoordIter yiter = yfirst;
for(std::size_t iy = 0; yiter != ylast; ++yiter, ++iy)
{
TXCoordIter xiter = xfirst;
for(std::size_t ix = 0; xiter != xlast; ++xiter, ++ix)
{
*outVertsFirst++ = V2d<T>(*xiter, *yiter);
const std::size_t i = iy * xres + ix;
TriIndVec vTris;
vTris.reserve(6);
// left-up
if(ix > 0 && iy < yres)
{
vTris.push_back(static_cast<TriInd>(2 * (i - 1)));
vTris.push_back(static_cast<TriInd>(2 * (i - 1) + 1));
}
// right-up
if(ix < xres && iy < yres)
{
vTris.push_back(static_cast<TriInd>(2 * i));
}
// left-down
if(ix > 0 && iy > 0)
{
vTris.push_back(static_cast<TriInd>(2 * (i - xres - 1) + 1));
}
// right-down
if(ix < xres && iy > 0)
{
vTris.push_back(static_cast<TriInd>(2 * (i - xres)));
vTris.push_back(static_cast<TriInd>(2 * (i - xres) + 1));
}
#ifdef CDT_CXX11_IS_SUPPORTED
*outTrisFirst++ = std::move(vTris.front());
#else
*outTrisFirst++ = vTris;
#endif
}
}
}
/**
* Generate grid triangles
*
* @tparam OutputIt output iterator
* @param outFirst the beginning of the destination range
* @param xres grid X-resolution
* @param yres grid Y-resolution
*/
template <typename OutputIt>
void generateGridTriangles(
OutputIt outFirst,
const IndexSizeType xres,
const IndexSizeType yres)
{
for(IndexSizeType iy = 0; iy < yres; ++iy)
{
for(IndexSizeType ix = 0; ix < xres; ++ix)
{
// 2___3 v3
// |\ | /\
// | \ | n3/ \n2
// |__\| /____\
// 0 1 v1 n1 v2
const IndexSizeType i = iy * xres + ix;
const IndexSizeType iv = iy * (xres + 1) + ix;
const VertInd vv[4] = {
VertInd(iv),
VertInd(iv + 1),
VertInd(iv + xres + 1),
VertInd(iv + xres + 2)};
{
const Triangle t = {
{vv[0], vv[1], vv[2]},
{TriInd(iy ? 2 * i - xres * 2 + 1 : noNeighbor),
TriInd(2 * i + 1),
TriInd(ix ? 2 * i - 1 : noNeighbor)}};
*outFirst++ = t;
}
{
const Triangle t = {
{vv[1], vv[3], vv[2]},
{TriInd(ix < xres - 1 ? 2 * i + 2 : noNeighbor),
TriInd(iy < yres - 1 ? 2 * i + xres * 2 : noNeighbor),
TriInd(2 * i)}};
*outFirst++ = t;
}
}
}
}
} // namespace detail
/**
* Make a triangulation that uses regular grid triangles instead of
* super-triangle
*
* @tparam T type of vertex coordinates (e.g., float, double)
* @tparam TNearPointLocator class providing locating near point for efficiently
* inserting new points.
* @param xmin minimum X-coordinate of grid
* @param xmax maximum X-coordinate of grid
* @param ymin minimum Y-coordinate of grid
* @param ymax maximum Y-coordinate of grid
* @param xres grid X-resolution
* @param yres grid Y-resolution
* @param out triangulation to initialize with grid super-geometry
*/
template <typename T, typename TNearPointLocator>
void initializeWithRegularGrid(
const T xmin,
const T xmax,
const T ymin,
const T ymax,
const std::size_t xres,
const std::size_t yres,
Triangulation<T, TNearPointLocator>& out)
{
std::vector<T> xcoords;
std::vector<T> ycoords;
xcoords.reserve(xres + 1);
ycoords.reserve(yres + 1);
const T xstep = (xmax - xmin) / xres;
T x = xmin;
for(std::size_t ix = 0; ix <= xres; ++ix, x += xstep)
xcoords.push_back(x);
const T ystep = (ymax - ymin) / yres;
T y = ymin;
for(std::size_t iy = 0; iy <= yres; ++iy, y += ystep)
ycoords.push_back(y);
return initializeWithIrregularGrid(
xcoords.begin(), xcoords.end(), ycoords.begin(), ycoords.end(), out);
}
/**
* Make a triangulation that uses irregular grid triangles instead of
* super-triangle. Irregular grid is given by collections of X- and Y-ticks
*
* @tparam T type of vertex coordinates (e.g., float, double)
* @tparam TNearPointLocator class providing locating near point for efficiently
* inserting new points.
* @tparam TXCoordIter iterator dereferencing to X coordinate
* @tparam TYCoordIter iterator dereferencing to Y coordinate
* @param xfirst beginning of X-ticks range
* @param xlast end of X-ticks range
* @param yfirst beginning of Y-ticks range
* @param ylast end of Y-ticks range
* @param out triangulation to initialize with grid super-geometry
*/
template <
typename T,
typename TNearPointLocator,
typename TXCoordIter,
typename TYCoordIter>
void initializeWithIrregularGrid(
const TXCoordIter xfirst,
const TXCoordIter xlast,
const TYCoordIter yfirst,
const TYCoordIter ylast,
Triangulation<T, TNearPointLocator>& out)
{
const std::size_t xres = std::distance(xfirst, xlast) - 1;
const std::size_t yres = std::distance(yfirst, ylast) - 1;
out.triangles.reserve(xres * yres * 2);
out.vertices.reserve((xres + 1) * (yres + 1));
out.VertTrisInternal().reserve((xres + 1) * (yres + 1));
detail::generateGridVertices(
std::back_inserter(out.vertices),
std::back_inserter(out.VertTrisInternal()),
xfirst,
xlast,
yfirst,
ylast);
detail::generateGridTriangles(
std::back_inserter(out.triangles),
static_cast<IndexSizeType>(xres),
static_cast<IndexSizeType>(yres));
out.initializedWithCustomSuperGeometry();
}
} // namespace CDT
#endif

View file

@ -0,0 +1,90 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/**
* @file
* Helper function to verify if triangulation has no inconsistencies
*/
#ifndef CDT_Zahj4kpHLwFgkKtcOI1i
#define CDT_Zahj4kpHLwFgkKtcOI1i
#include <CDT.h>
#include <algorithm>
namespace CDT
{
/**
* Verify that triangulation topology is consistent.
*
* Checks:
* - for each vertex adjacent triangles contain the vertex
* - each triangle's neighbor in turn has triangle as its neighbor
* - each of triangle's vertices has triangle as adjacent
*
* @tparam T type of vertex coordinates (e.g., float, double)
* @tparam TNearPointLocator class providing locating near point for efficiently
*/
template <typename T, typename TNearPointLocator>
inline bool verifyTopology(const CDT::Triangulation<T, TNearPointLocator>& cdt)
{
// Check if vertices' adjacent triangles contain vertex
const VerticesTriangles vertTris = calculateTrianglesByVertex(
cdt.triangles, static_cast<VertInd>(cdt.vertices.size()));
for(VertInd iV(0); iV < VertInd(cdt.vertices.size()); ++iV)
{
const TriIndVec& vTris = vertTris[iV];
typedef TriIndVec::const_iterator TriIndCit;
for(TriIndCit it = vTris.begin(); it != vTris.end(); ++it)
{
const array<VertInd, 3>& vv = cdt.triangles[*it].vertices;
if(std::find(vv.begin(), vv.end(), iV) == vv.end())
return false;
}
}
// Check if triangle neighbor links are fine
for(TriInd iT(0); iT < TriInd(cdt.triangles.size()); ++iT)
{
const Triangle& t = cdt.triangles[iT];
typedef NeighborsArr3::const_iterator NCit;
for(NCit it = t.neighbors.begin(); it != t.neighbors.end(); ++it)
{
if(*it == noNeighbor)
continue;
const array<TriInd, 3>& nn = cdt.triangles[*it].neighbors;
if(std::find(nn.begin(), nn.end(), iT) == nn.end())
return false;
}
}
// Check if triangle's vertices have triangle as adjacent
for(TriInd iT(0); iT < TriInd(cdt.triangles.size()); ++iT)
{
const Triangle& t = cdt.triangles[iT];
typedef VerticesArr3::const_iterator VCit;
for(VCit it = t.vertices.begin(); it != t.vertices.end(); ++it)
{
const TriIndVec& tt = vertTris[*it];
if(std::find(tt.begin(), tt.end(), iT) == tt.end())
return false;
}
}
return true;
}
/// Check that each vertex has a neighbor triangle
template <typename T, typename TNearPointLocator>
inline bool eachVertexHasNeighborTriangle(
const CDT::Triangulation<T, TNearPointLocator>& cdt)
{
for(const auto& vt : cdt.VertTrisInternal())
if(vt == noNeighbor)
return false;
return true;
}
} // namespace CDT
#endif

448
include/CDT/include/CDT.h Normal file
View file

@ -0,0 +1,448 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/**
* @file
* Public API
*/
#ifndef CDT_lNrmUayWQaIR5fxnsg9B
#define CDT_lNrmUayWQaIR5fxnsg9B
#include "CDTUtils.h"
#include "Triangulation.h"
#include "remove_at.hpp"
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <iterator>
#include <memory>
#include <stack>
#include <vector>
/// Namespace containing triangulation functionality
namespace CDT
{
/** @defgroup API Public API
* Contains API for constrained and conforming Delaunay triangulations
*/
/// @{
/**
* Type used for storing layer depths for triangles
* @note LayerDepth should support 60K+ layers, which could be to much or
* too little for some use cases. Feel free to re-define this typedef.
*/
typedef unsigned short LayerDepth;
typedef LayerDepth BoundaryOverlapCount;
/// Triangles by vertex index
typedef std::vector<TriIndVec> VerticesTriangles;
/** @defgroup helpers Helpers
* Helpers for working with CDT::Triangulation.
*/
/// @{
/**
* Calculate triangles adjacent to vertices (triangles by vertex index)
* @param triangles triangulation
* @param verticesSize total number of vertices to pre-allocate the output
* @return triangles by vertex index
*/
CDT_EXPORT VerticesTriangles
calculateTrianglesByVertex(const TriangleVec& triangles, VertInd verticesSize);
/**
* Information about removed duplicated vertices.
*
* Contains mapping information and removed duplicates indices.
* @note vertices {0,1,2,3,4} where 0 and 3 are the same will produce mapping
* {0,1,2,0,3} (to new vertices {0,1,2,3}) and duplicates {3}
*/
struct CDT_EXPORT DuplicatesInfo
{
std::vector<std::size_t> mapping; ///< vertex index mapping
std::vector<std::size_t> duplicates; ///< duplicates' indices
};
/**
* Find duplicates in given custom point-type range
* @note duplicates are points with exactly same X and Y coordinates
* @tparam TVertexIter iterator that dereferences to custom point type
* @tparam TGetVertexCoordX function object getting x coordinate from vertex.
* Getter signature: const TVertexIter::value_type& -> T
* @tparam TGetVertexCoordY function object getting y coordinate from vertex.
* Getter signature: const TVertexIter::value_type& -> T
* @param first beginning of the range of vertices
* @param last end of the range of vertices
* @param getX getter of X-coordinate
* @param getY getter of Y-coordinate
* @returns information about vertex duplicates
*/
template <
typename T,
typename TVertexIter,
typename TGetVertexCoordX,
typename TGetVertexCoordY>
DuplicatesInfo FindDuplicates(
TVertexIter first,
TVertexIter last,
TGetVertexCoordX getX,
TGetVertexCoordY getY);
/**
* Remove duplicates in-place from vector of custom points
* @tparam TVertex vertex type
* @tparam TAllocator allocator used by input vector of vertices
* @param vertices vertices to remove duplicates from
* @param duplicates information about duplicates
*/
template <typename TVertex, typename TAllocator>
void RemoveDuplicates(
std::vector<TVertex, TAllocator>& vertices,
const std::vector<std::size_t>& duplicates);
/**
* Remove duplicated points in-place
*
* @tparam T type of vertex coordinates (e.g., float, double)
* @param[in, out] vertices collection of vertices to remove duplicates from
* @returns information about duplicated vertices that were removed.
*/
template <typename T>
CDT_EXPORT DuplicatesInfo RemoveDuplicates(std::vector<V2d<T> >& vertices);
/**
* Remap vertex indices in edges (in-place) using given vertex-index mapping.
* @tparam TEdgeIter iterator that dereferences to custom edge type
* @tparam TGetEdgeVertexStart function object getting start vertex index
* from an edge.
* Getter signature: const TEdgeIter::value_type& -> CDT::VertInd
* @tparam TGetEdgeVertexEnd function object getting end vertex index from
* an edge. Getter signature: const TEdgeIter::value_type& -> CDT::VertInd
* @tparam TMakeEdgeFromStartAndEnd function object that makes new edge from
* start and end vertices
* @param first beginning of the range of edges
* @param last end of the range of edges
* @param mapping vertex-index mapping
* @param getStart getter of edge start vertex index
* @param getEnd getter of edge end vertex index
* @param makeEdge factory for making edge from vetices
*/
template <
typename TEdgeIter,
typename TGetEdgeVertexStart,
typename TGetEdgeVertexEnd,
typename TMakeEdgeFromStartAndEnd>
void RemapEdges(
TEdgeIter first,
TEdgeIter last,
const std::vector<std::size_t>& mapping,
TGetEdgeVertexStart getStart,
TGetEdgeVertexEnd getEnd,
TMakeEdgeFromStartAndEnd makeEdge);
/**
* Remap vertex indices in edges (in-place) using given vertex-index mapping.
*
* @note Mapping can be a result of RemoveDuplicates function
* @param[in,out] edges collection of edges to remap
* @param mapping vertex-index mapping
*/
CDT_EXPORT void
RemapEdges(std::vector<Edge>& edges, const std::vector<std::size_t>& mapping);
/**
* Find point duplicates, remove them from vector (in-place) and remap edges
* (in-place)
* @note Same as a chained call of CDT::FindDuplicates, CDT::RemoveDuplicates,
* and CDT::RemapEdges
* @tparam T type of vertex coordinates (e.g., float, double)
* @tparam TVertex type of vertex
* @tparam TGetVertexCoordX function object getting x coordinate from vertex.
* Getter signature: const TVertexIter::value_type& -> T
* @tparam TGetVertexCoordY function object getting y coordinate from vertex.
* Getter signature: const TVertexIter::value_type& -> T
* @tparam TEdgeIter iterator that dereferences to custom edge type
* @tparam TGetEdgeVertexStart function object getting start vertex index
* from an edge.
* Getter signature: const TEdgeIter::value_type& -> CDT::VertInd
* @tparam TGetEdgeVertexEnd function object getting end vertex index from
* an edge. Getter signature: const TEdgeIter::value_type& -> CDT::VertInd
* @tparam TMakeEdgeFromStartAndEnd function object that makes new edge from
* start and end vertices
* @param[in, out] vertices vertices to remove duplicates from
* @param[in, out] edges collection of edges connecting vertices
* @param getX getter of X-coordinate
* @param getY getter of Y-coordinate
* @param edgesFirst beginning of the range of edges
* @param edgesLast end of the range of edges
* @param getStart getter of edge start vertex index
* @param getEnd getter of edge end vertex index
* @param makeEdge factory for making edge from vetices
* @returns information about vertex duplicates
*/
template <
typename T,
typename TVertex,
typename TGetVertexCoordX,
typename TGetVertexCoordY,
typename TVertexAllocator,
typename TEdgeIter,
typename TGetEdgeVertexStart,
typename TGetEdgeVertexEnd,
typename TMakeEdgeFromStartAndEnd>
DuplicatesInfo RemoveDuplicatesAndRemapEdges(
std::vector<TVertex, TVertexAllocator>& vertices,
TGetVertexCoordX getX,
TGetVertexCoordY getY,
TEdgeIter edgesFirst,
TEdgeIter edgesLast,
TGetEdgeVertexStart getStart,
TGetEdgeVertexEnd getEnd,
TMakeEdgeFromStartAndEnd makeEdge);
/**
* Same as a chained call of CDT::RemoveDuplicates + CDT::RemapEdges
*
* @tparam T type of vertex coordinates (e.g., float, double)
* @param[in, out] vertices collection of vertices to remove duplicates from
* @param[in,out] edges collection of edges to remap
*/
template <typename T>
CDT_EXPORT DuplicatesInfo RemoveDuplicatesAndRemapEdges(
std::vector<V2d<T> >& vertices,
std::vector<Edge>& edges);
/**
* Extract all edges of triangles
*
* @param triangles triangles used to extract edges
* @return an unordered set of all edges of triangulation
*/
CDT_EXPORT EdgeUSet extractEdgesFromTriangles(const TriangleVec& triangles);
/*!
* Converts piece->original_edges mapping to original_edge->pieces
* @param pieceToOriginals maps pieces to original edges
* @return mapping of original edges to pieces
*/
CDT_EXPORT unordered_map<Edge, EdgeVec>
EdgeToPiecesMapping(const unordered_map<Edge, EdgeVec>& pieceToOriginals);
/*!
* Convert edge-to-pieces mapping into edge-to-split-vertices mapping
* @tparam T type of vertex coordinates (e.g., float, double)
* @param edgeToPieces edge-to-pieces mapping
* @param vertices vertex buffer
* @return mapping of edge-to-split-points.
* Split points are sorted from edge's start (v1) to end (v2)
*/
template <typename T>
unordered_map<Edge, std::vector<VertInd> > EdgeToSplitVertices(
const unordered_map<Edge, EdgeVec>& edgeToPieces,
const std::vector<V2d<T> >& vertices);
/// @}
/// @}
} // namespace CDT
//*****************************************************************************
// Implementations of template functionlity
//*****************************************************************************
// hash for CDT::V2d<T>
#ifdef CDT_CXX11_IS_SUPPORTED
namespace std
#else
namespace boost
#endif
{
template <typename T>
struct hash<CDT::V2d<T> >
{
size_t operator()(const CDT::V2d<T>& xy) const
{
#ifdef CDT_CXX11_IS_SUPPORTED
typedef std::hash<T> Hasher;
#else
typedef boost::hash<T> Hasher;
#endif
return Hasher()(xy.x) ^ Hasher()(xy.y);
}
};
} // namespace std
namespace CDT
{
//-----
// API
//-----
template <
typename T,
typename TVertexIter,
typename TGetVertexCoordX,
typename TGetVertexCoordY>
DuplicatesInfo FindDuplicates(
TVertexIter first,
TVertexIter last,
TGetVertexCoordX getX,
TGetVertexCoordY getY)
{
typedef unordered_map<V2d<T>, std::size_t> PosToIndex;
PosToIndex uniqueVerts;
const std::size_t verticesSize = std::distance(first, last);
DuplicatesInfo di = {
std::vector<std::size_t>(verticesSize), std::vector<std::size_t>()};
for(std::size_t iIn = 0, iOut = iIn; iIn < verticesSize; ++iIn, ++first)
{
typename PosToIndex::const_iterator it;
bool isUnique;
tie(it, isUnique) = uniqueVerts.insert(
std::make_pair(V2d<T>(getX(*first), getY(*first)), iOut));
if(isUnique)
{
di.mapping[iIn] = iOut++;
continue;
}
di.mapping[iIn] = it->second; // found a duplicate
di.duplicates.push_back(iIn);
}
return di;
}
template <typename TVertex, typename TAllocator>
void RemoveDuplicates(
std::vector<TVertex, TAllocator>& vertices,
const std::vector<std::size_t>& duplicates)
{
vertices.erase(
remove_at(
vertices.begin(),
vertices.end(),
duplicates.begin(),
duplicates.end()),
vertices.end());
}
template <
typename TEdgeIter,
typename TGetEdgeVertexStart,
typename TGetEdgeVertexEnd,
typename TMakeEdgeFromStartAndEnd>
void RemapEdges(
TEdgeIter first,
const TEdgeIter last,
const std::vector<std::size_t>& mapping,
TGetEdgeVertexStart getStart,
TGetEdgeVertexEnd getEnd,
TMakeEdgeFromStartAndEnd makeEdge)
{
for(; first != last; ++first)
{
*first = makeEdge(
static_cast<VertInd>(mapping[getStart(*first)]),
static_cast<VertInd>(mapping[getEnd(*first)]));
}
}
template <
typename T,
typename TVertex,
typename TGetVertexCoordX,
typename TGetVertexCoordY,
typename TVertexAllocator,
typename TEdgeIter,
typename TGetEdgeVertexStart,
typename TGetEdgeVertexEnd,
typename TMakeEdgeFromStartAndEnd>
DuplicatesInfo RemoveDuplicatesAndRemapEdges(
std::vector<TVertex, TVertexAllocator>& vertices,
TGetVertexCoordX getX,
TGetVertexCoordY getY,
const TEdgeIter edgesFirst,
const TEdgeIter edgesLast,
TGetEdgeVertexStart getStart,
TGetEdgeVertexEnd getEnd,
TMakeEdgeFromStartAndEnd makeEdge)
{
const DuplicatesInfo di =
FindDuplicates<T>(vertices.begin(), vertices.end(), getX, getY);
RemoveDuplicates(vertices, di.duplicates);
RemapEdges(edgesFirst, edgesLast, di.mapping, getStart, getEnd, makeEdge);
return di;
}
template <typename T>
unordered_map<Edge, std::vector<VertInd> > EdgeToSplitVertices(
const unordered_map<Edge, EdgeVec>& edgeToPieces,
const std::vector<V2d<T> >& vertices)
{
typedef std::pair<VertInd, T> VertCoordPair;
struct ComparePred
{
bool operator()(const VertCoordPair& a, const VertCoordPair& b) const
{
return a.second < b.second;
}
} comparePred;
unordered_map<Edge, std::vector<VertInd> > edgeToSplitVerts;
typedef unordered_map<Edge, EdgeVec>::const_iterator It;
for(It e2pIt = edgeToPieces.begin(); e2pIt != edgeToPieces.end(); ++e2pIt)
{
const Edge& e = e2pIt->first;
const T dX = vertices[e.v2()].x - vertices[e.v1()].x;
const T dY = vertices[e.v2()].y - vertices[e.v1()].y;
const bool isX = std::abs(dX) >= std::abs(dY); // X-coord longer
const bool isAscending =
isX ? dX >= 0 : dY >= 0; // Longer coordinate ascends
const EdgeVec& pieces = e2pIt->second;
std::vector<VertCoordPair> splitVerts;
// size is: 2[ends] + (pieces - 1)[split vertices] = pieces + 1
splitVerts.reserve(pieces.size() + 1);
typedef EdgeVec::const_iterator EIt;
for(EIt pieceIt = pieces.begin(); pieceIt != pieces.end(); ++pieceIt)
{
const array<VertInd, 2> vv = {pieceIt->v1(), pieceIt->v2()};
typedef array<VertInd, 2>::const_iterator VIt;
for(VIt v = vv.begin(); v != vv.end(); ++v)
{
const T c = isX ? vertices[*v].x : vertices[*v].y;
splitVerts.push_back(std::make_pair(*v, isAscending ? c : -c));
}
}
// sort by longest coordinate
std::sort(splitVerts.begin(), splitVerts.end(), comparePred);
// remove duplicates
splitVerts.erase(
std::unique(splitVerts.begin(), splitVerts.end()),
splitVerts.end());
assert(splitVerts.size() > 2); // 2 end points with split vertices
std::pair<Edge, std::vector<VertInd> > val =
std::make_pair(e, std::vector<VertInd>());
val.second.reserve(splitVerts.size());
typedef typename std::vector<VertCoordPair>::const_iterator SEIt;
for(SEIt it = splitVerts.begin() + 1; it != splitVerts.end() - 1; ++it)
{
val.second.push_back(it->first);
}
edgeToSplitVerts.insert(val);
}
return edgeToSplitVerts;
}
} // namespace CDT
#ifndef CDT_USE_AS_COMPILED_LIBRARY
#include "CDT.hpp"
#endif
#endif // header-guard

107
include/CDT/include/CDT.hpp Normal file
View file

@ -0,0 +1,107 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/**
* @file
* Public API - implementation
*/
#include "CDT.h"
#include <algorithm>
#include <deque>
#include <limits>
#include <stdexcept>
namespace CDT
{
CDT_INLINE_IF_HEADER_ONLY VerticesTriangles calculateTrianglesByVertex(
const TriangleVec& triangles,
const VertInd verticesSize)
{
VerticesTriangles vertTris(verticesSize);
for(TriInd iT(0); iT < triangles.size(); ++iT)
{
const VerticesArr3& vv = triangles[iT].vertices;
for(VerticesArr3::const_iterator v = vv.begin(); v != vv.end(); ++v)
{
vertTris[*v].push_back(iT);
}
}
return vertTris;
}
template <typename T>
DuplicatesInfo RemoveDuplicates(std::vector<V2d<T> >& vertices)
{
const DuplicatesInfo di = FindDuplicates<T>(
vertices.begin(), vertices.end(), getX_V2d<T>, getY_V2d<T>);
RemoveDuplicates(vertices, di.duplicates);
return di;
}
CDT_INLINE_IF_HEADER_ONLY void
RemapEdges(std::vector<Edge>& edges, const std::vector<std::size_t>& mapping)
{
RemapEdges(
edges.begin(),
edges.end(),
mapping,
edge_get_v1,
edge_get_v2,
edge_make);
}
template <typename T>
DuplicatesInfo RemoveDuplicatesAndRemapEdges(
std::vector<V2d<T> >& vertices,
std::vector<Edge>& edges)
{
return RemoveDuplicatesAndRemapEdges<T>(
vertices,
getX_V2d<T>,
getY_V2d<T>,
edges.begin(),
edges.end(),
edge_get_v1,
edge_get_v2,
edge_make);
}
CDT_INLINE_IF_HEADER_ONLY EdgeUSet
extractEdgesFromTriangles(const TriangleVec& triangles)
{
EdgeUSet edges;
typedef TriangleVec::const_iterator CIt;
for(CIt t = triangles.begin(); t != triangles.end(); ++t)
{
edges.insert(Edge(VertInd(t->vertices[0]), VertInd(t->vertices[1])));
edges.insert(Edge(VertInd(t->vertices[1]), VertInd(t->vertices[2])));
edges.insert(Edge(VertInd(t->vertices[2]), VertInd(t->vertices[0])));
}
return edges;
}
CDT_INLINE_IF_HEADER_ONLY unordered_map<Edge, EdgeVec>
EdgeToPiecesMapping(const unordered_map<Edge, EdgeVec>& pieceToOriginals)
{
unordered_map<Edge, EdgeVec> originalToPieces;
typedef unordered_map<Edge, EdgeVec>::const_iterator Cit;
for(Cit ptoIt = pieceToOriginals.begin(); ptoIt != pieceToOriginals.end();
++ptoIt)
{
const Edge piece = ptoIt->first;
const EdgeVec& originals = ptoIt->second;
for(EdgeVec::const_iterator origIt = originals.begin();
origIt != originals.end();
++origIt)
{
originalToPieces[*origIt].push_back(piece);
}
}
return originalToPieces;
}
} // namespace CDT

View file

@ -0,0 +1,592 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/**
* @file
* Utilities and helpers
*/
#ifndef CDT_obwOaxOTdAWcLNTlNnaq
#define CDT_obwOaxOTdAWcLNTlNnaq
#ifdef CDT_DONT_USE_BOOST_RTREE
// CDT_DONT_USE_BOOST_RTREE was replaced with CDT_USE_BOOST
typedef char CDT_DONT_USE_BOOST_RTREE__was__replaced__with__CDT_USE_BOOST[-1];
#endif
// #define CDT_USE_STRONG_TYPING // strong type checks on indices
// check if c++11 is supported
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
#define CDT_CXX11_IS_SUPPORTED
#elif !defined(__cplusplus) && !defined(_MSC_VER)
typedef char couldnt_parse_cxx_standard[-1]; ///< Error: couldn't parse standard
#endif
// Functions defined outside the class need to be 'inline'
// if CDT is configured to be used as header-only library:
// single-definition rule is violated otherwise
#ifdef CDT_USE_AS_COMPILED_LIBRARY
#define CDT_INLINE_IF_HEADER_ONLY
#include "cdt_export.h" // automatically generated by CMake
#else
/**
* Macro for inlining non-template functions when in header-only mode to
* avoid multiple declaration errors.
*/
#define CDT_INLINE_IF_HEADER_ONLY inline
/// Export not needed in header-only mode
#define CDT_EXPORT
#endif
#include <algorithm>
#include <cassert>
#include <cmath>
#include <limits>
#include <vector>
#ifdef CDT_USE_STRONG_TYPING
#include <boost/serialization/strong_typedef.hpp>
#endif
// use fall-backs for c++11 features
#ifdef CDT_CXX11_IS_SUPPORTED
#include <array>
#include <functional>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#ifdef CDT_DISABLE_EXCEPTIONS
#include <exception>
#endif
namespace CDT
{
using std::array;
using std::get;
using std::make_tuple;
using std::tie;
using std::to_string;
using std::tuple;
using std::unordered_map;
using std::unordered_set;
} // namespace CDT
#else
#include <boost/array.hpp>
#include <boost/functional/hash.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
namespace CDT
{
using boost::array;
using boost::get;
using boost::make_tuple;
using boost::tie;
using boost::tuple;
using boost::unordered_map;
using boost::unordered_set;
template <typename T>
std::string to_string(const T& value)
{
return boost::lexical_cast<std::string>(value);
}
} // namespace CDT
#endif
namespace CDT
{
template <typename T>
void handleException(const T& error)
{
#ifdef CDT_DISABLE_EXCEPTIONS
std::terminate();
#else
throw error;
#endif
}
/// Needed for c++03 compatibility (no uniform initialization available)
template <typename T>
array<T, 3> arr3(const T& v0, const T& v1, const T& v2)
{
const array<T, 3> out = {v0, v1, v2};
return out;
}
/// Needed for c++03 compatibility (no uniform initialization available)
template <typename T>
array<T, 3> arr3(const T& v)
{
const array<T, 3> out = {v, v, v};
return out;
}
/// 2D vector
template <typename T>
struct CDT_EXPORT V2d
{
T x; ///< X-coordinate
T y; ///< Y-coordinate
/// Vertex with zero coordinates
V2d()
: x(T(0))
, y(T(0))
{}
/// Vertex with given coordinates
V2d(const T x, const T y)
: x(x)
, y(y)
{}
};
/// X- coordinate getter for V2d
template <typename T>
const T& getX_V2d(const V2d<T>& v)
{
return v.x;
}
/// Y-coordinate getter for V2d
template <typename T>
const T& getY_V2d(const V2d<T>& v)
{
return v.y;
}
/// If two 2D vectors are exactly equal
template <typename T>
bool operator==(const CDT::V2d<T>& lhs, const CDT::V2d<T>& rhs)
{
return lhs.x == rhs.x && lhs.y == rhs.y;
}
#ifdef CDT_USE_64_BIT_INDEX_TYPE
typedef unsigned long long IndexSizeType;
#else
typedef unsigned int IndexSizeType;
#endif
#ifdef CDT_USE_STRONG_TYPING
/// Index in triangle
BOOST_STRONG_TYPEDEF(unsigned char, Index);
/// Vertex index
BOOST_STRONG_TYPEDEF(IndexSizeType, VertInd);
/// Triangle index
BOOST_STRONG_TYPEDEF(IndexSizeType, TriInd);
#else
/// Index in triangle
typedef unsigned char Index;
/// Vertex index
typedef IndexSizeType VertInd;
/// Triangle index
typedef IndexSizeType TriInd;
#endif
/// Constant representing no valid value for index
const static Index invalidIndex(std::numeric_limits<Index>::max());
/// Constant representing no valid value for index size
const static IndexSizeType
invalidIndexSizeType(std::numeric_limits<IndexSizeType>::max());
/// Number of super triangle vertices
/// @note placed in a constant so that it's easier to find usages in code
const static IndexSizeType nSuperTriangleVertices(3);
/// Constant representing no valid neighbor for a triangle
const static TriInd noNeighbor(invalidIndexSizeType);
/// Constant representing no valid vertex for a triangle
const static VertInd noVertex(invalidIndexSizeType);
typedef std::vector<TriInd> TriIndVec; ///< Vector of triangle indices
typedef array<VertInd, 3> VerticesArr3; ///< array of three vertex indices
typedef array<TriInd, 3> NeighborsArr3; ///< array of three neighbors
/// 2D bounding box
template <typename T>
struct CDT_EXPORT Box2d
{
V2d<T> min; ///< min box corner
V2d<T> max; ///< max box corner
/// Box that doesn't contain any point
Box2d()
: min(std::numeric_limits<T>::max(), std::numeric_limits<T>::max())
, max(-std::numeric_limits<T>::max(), -std::numeric_limits<T>::max())
{}
/// Envelop box around a point
Box2d<T>& envelopPoint(const V2d<T>& p)
{
return envelopPoint(p.x, p.y);
}
/// Envelop box around a point with given coordinates
Box2d<T>& envelopPoint(const T x, const T y)
{
min.x = std::min(x, min.x);
max.x = std::max(x, max.x);
min.y = std::min(y, min.y);
max.y = std::max(y, max.y);
return *this;
}
/// Envelop box around a collection of custom points
template <
typename TVertexIter,
typename TGetVertexCoordX,
typename TGetVertexCoordY>
Box2d<T>& envelopPoints(
TVertexIter first,
TVertexIter last,
TGetVertexCoordX getX,
TGetVertexCoordY getY)
{
for(; first != last; ++first)
{
envelopPoint(getX(*first), getY(*first));
}
return *this;
}
/// Envelop box around a collection of points
Box2d<T>& envelopPoints(const std::vector<V2d<T> >& vertices)
{
return envelopPoints(
vertices.begin(), vertices.end(), getX_V2d<T>, getY_V2d<T>);
}
};
/// Edge connecting two vertices: vertex with smaller index is always first
/// @note: hash Edge is specialized at the bottom
struct CDT_EXPORT Edge
{
/// Constructor
Edge(const VertInd iV1, const VertInd iV2)
: m_vertices(
iV1 < iV2 ? std::make_pair(iV1, iV2) : std::make_pair(iV2, iV1))
{}
/// Equals operator
bool operator==(const Edge& other) const
{
return m_vertices == other.m_vertices;
}
/// Not-equals operator
bool operator!=(const Edge& other) const
{
return !(this->operator==(other));
}
/// V1 getter
VertInd v1() const
{
return m_vertices.first;
}
/// V2 getter
VertInd v2() const
{
return m_vertices.second;
}
/// Edges' vertices
const std::pair<VertInd, VertInd>& verts() const
{
return m_vertices;
}
private:
std::pair<VertInd, VertInd> m_vertices;
};
/// Get edge first vertex
inline VertInd edge_get_v1(const Edge& e)
{
return e.v1();
}
/// Get edge second vertex
inline VertInd edge_get_v2(const Edge& e)
{
return e.v2();
}
/// Get edge second vertex
inline Edge edge_make(VertInd iV1, VertInd iV2)
{
return Edge(iV1, iV2);
}
typedef std::vector<Edge> EdgeVec; ///< Vector of edges
typedef unordered_set<Edge> EdgeUSet; ///< Hash table of edges
typedef unordered_set<TriInd> TriIndUSet; ///< Hash table of triangles
typedef unordered_map<TriInd, TriInd> TriIndUMap; ///< Triangle hash map
/// Triangulation triangle (counter-clockwise winding)
/*
* v3
* /\
* n3/ \n2
* /____\
* v1 n1 v2
*/
struct CDT_EXPORT Triangle
{
VerticesArr3 vertices; ///< triangle's three vertices
NeighborsArr3 neighbors; ///< triangle's three neighbors
/// Triangle with no vertices and no neighbors
Triangle()
: vertices(arr3(noVertex))
, neighbors(arr3(noNeighbor))
{}
/// Triangle with given vertices and neighbors
Triangle(const VerticesArr3& vertices, const NeighborsArr3& neighbors)
: vertices(vertices)
, neighbors(neighbors)
{}
/// Next triangle adjacent to a vertex (clockwise)
/// @returns pair of next triangle and the other vertex of a common edge
std::pair<TriInd, VertInd> next(const VertInd i) const
{
assert(vertices[0] == i || vertices[1] == i || vertices[2] == i);
if(vertices[0] == i)
{
return std::make_pair(neighbors[0], vertices[1]);
}
if(vertices[1] == i)
{
return std::make_pair(neighbors[1], vertices[2]);
}
return std::make_pair(neighbors[2], vertices[0]);
}
/// Previous triangle adjacent to a vertex (counter-clockwise)
/// @returns pair of previous triangle and the other vertex of a common edge
std::pair<TriInd, VertInd> prev(const VertInd i) const
{
assert(vertices[0] == i || vertices[1] == i || vertices[2] == i);
if(vertices[0] == i)
return std::make_pair(neighbors[2], vertices[2]);
if(vertices[1] == i)
return std::make_pair(neighbors[0], vertices[0]);
return std::make_pair(neighbors[1], vertices[1]);
}
/// Check if triangle contains a vertex
bool containsVertex(const VertInd i) const
{
return std::find(vertices.begin(), vertices.end(), i) != vertices.end();
}
};
typedef std::vector<Triangle> TriangleVec; ///< Vector of triangles
/// Advance vertex or neighbor index counter-clockwise
CDT_EXPORT Index ccw(Index i);
/// Advance vertex or neighbor index clockwise
CDT_EXPORT Index cw(Index i);
/// Location of point on a triangle
struct CDT_EXPORT PtTriLocation
{
/// Enum
enum Enum
{
Inside,
Outside,
OnEdge1,
OnEdge2,
OnEdge3,
OnVertex,
};
};
/// Check if location is classified as on any of three edges
CDT_EXPORT bool isOnEdge(PtTriLocation::Enum location);
/// Neighbor index from a on-edge location
/// @note Call only if located on the edge!
CDT_EXPORT Index edgeNeighbor(PtTriLocation::Enum location);
/// Relative location of point to a line
struct CDT_EXPORT PtLineLocation
{
/// Enum
enum Enum
{
Left,
Right,
OnLine,
};
};
/// Orient p against line v1-v2 2D: robust geometric predicate
template <typename T>
CDT_EXPORT T orient2D(const V2d<T>& p, const V2d<T>& v1, const V2d<T>& v2);
/// Check if point lies to the left of, to the right of, or on a line
template <typename T>
CDT_EXPORT PtLineLocation::Enum locatePointLine(
const V2d<T>& p,
const V2d<T>& v1,
const V2d<T>& v2,
T orientationTolerance = T(0));
/// Classify value of orient2d predicate
template <typename T>
CDT_EXPORT PtLineLocation::Enum
classifyOrientation(T orientation, T orientationTolerance = T(0));
/// Check if point a lies inside of, outside of, or on an edge of a triangle
template <typename T>
CDT_EXPORT PtTriLocation::Enum locatePointTriangle(
const V2d<T>& p,
const V2d<T>& v1,
const V2d<T>& v2,
const V2d<T>& v3);
/// Opposed neighbor index from vertex index
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opoNbr(Index vertIndex);
/// Opposed vertex index from neighbor index
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index opoVrt(Index neighborIndex);
/// Index of triangle's neighbor opposed to a vertex
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index
opposedTriangleInd(const VerticesArr3& vv, VertInd iVert);
/// Index of triangle's neighbor opposed to an edge
CDT_INLINE_IF_HEADER_ONLY Index
edgeNeighborInd(const VerticesArr3& vv, VertInd iVedge1, VertInd iVedge2);
/// Index of triangle's vertex opposed to a triangle
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index
opposedVertexInd(const NeighborsArr3& nn, TriInd iTopo);
/// If triangle has a given vertex return vertex-index
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY Index
vertexInd(const VerticesArr3& vv, VertInd iV);
/// Given triangle and a vertex find opposed triangle
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY TriInd
opposedTriangle(const Triangle& tri, VertInd iVert);
/// Given triangle and an edge find neighbor sharing the edge
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY TriInd
edgeNeighbor(const Triangle& tri, VertInd iVedge1, VertInd iVedge2);
/// Given two triangles, return vertex of first triangle opposed to the second
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY VertInd
opposedVertex(const Triangle& tri, TriInd iTopo);
/// Test if point lies in a circumscribed circle of a triangle
template <typename T>
CDT_EXPORT bool isInCircumcircle(
const V2d<T>& p,
const V2d<T>& v1,
const V2d<T>& v2,
const V2d<T>& v3);
/// Test if two vertices share at least one common triangle
CDT_EXPORT CDT_INLINE_IF_HEADER_ONLY bool
verticesShareEdge(const TriIndVec& aTris, const TriIndVec& bTris);
/// Distance between two 2D points
template <typename T>
CDT_EXPORT T distance(const V2d<T>& a, const V2d<T>& b);
/// Squared distance between two 2D points
template <typename T>
CDT_EXPORT T distanceSquared(const V2d<T>& a, const V2d<T>& b);
/// Check if any of triangle's vertices belongs to a super-triangle
CDT_INLINE_IF_HEADER_ONLY bool touchesSuperTriangle(const Triangle& t);
} // namespace CDT
#ifndef CDT_USE_AS_COMPILED_LIBRARY
#include "CDTUtils.hpp"
#endif
//*****************************************************************************
// Specialize hash functions
//*****************************************************************************
#ifdef CDT_CXX11_IS_SUPPORTED
namespace std
#else
namespace boost
#endif
{
#ifdef CDT_USE_STRONG_TYPING
/// Vertex index hasher
template <>
struct hash<CDT::VertInd>
{
/// Hash operator
std::size_t operator()(const CDT::VertInd& vi) const
{
return std::hash<std::size_t>()(vi.t);
}
};
/// Triangle index hasher
template <>
struct hash<CDT::TriInd>
{
/// Hash operator
std::size_t operator()(const CDT::TriInd& vi) const
{
return std::hash<std::size_t>()(vi.t);
}
};
#endif // CDT_USE_STRONG_TYPING
/// Edge hasher
template <>
struct hash<CDT::Edge>
{
/// Hash operator
std::size_t operator()(const CDT::Edge& e) const
{
return hashEdge(e);
}
private:
static void hashCombine(std::size_t& seed, const CDT::VertInd& key)
{
#ifdef CDT_CXX11_IS_SUPPORTED
typedef std::hash<CDT::VertInd> Hasher;
#else
typedef boost::hash<CDT::VertInd> Hasher;
#endif
seed ^= Hasher()(key) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
static std::size_t hashEdge(const CDT::Edge& e)
{
std::size_t seed(0);
hashCombine(seed, e.v1());
hashCombine(seed, e.v2());
return seed;
}
};
} // namespace std/boost
#endif // header guard

View file

@ -0,0 +1,264 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/**
* @file
* Utilities and helpers - implementation
*/
#include "CDTUtils.h"
#include "predicates.h" // robust predicates: orient, in-circle
#include <stdexcept>
namespace CDT
{
CDT_INLINE_IF_HEADER_ONLY Index ccw(Index i)
{
return Index((i + 1) % 3);
}
CDT_INLINE_IF_HEADER_ONLY Index cw(Index i)
{
return Index((i + 2) % 3);
}
CDT_INLINE_IF_HEADER_ONLY bool isOnEdge(const PtTriLocation::Enum location)
{
return location == PtTriLocation::OnEdge1 ||
location == PtTriLocation::OnEdge2 ||
location == PtTriLocation::OnEdge3;
}
CDT_INLINE_IF_HEADER_ONLY Index edgeNeighbor(const PtTriLocation::Enum location)
{
assert(isOnEdge(location));
return static_cast<Index>(location - PtTriLocation::OnEdge1);
}
template <typename T>
T orient2D(const V2d<T>& p, const V2d<T>& v1, const V2d<T>& v2)
{
return predicates::adaptive::orient2d(v1.x, v1.y, v2.x, v2.y, p.x, p.y);
}
template <typename T>
PtLineLocation::Enum locatePointLine(
const V2d<T>& p,
const V2d<T>& v1,
const V2d<T>& v2,
const T orientationTolerance)
{
return classifyOrientation(orient2D(p, v1, v2), orientationTolerance);
}
template <typename T>
PtLineLocation::Enum
classifyOrientation(const T orientation, const T orientationTolerance)
{
if(orientation < -orientationTolerance)
return PtLineLocation::Right;
if(orientation > orientationTolerance)
return PtLineLocation::Left;
return PtLineLocation::OnLine;
}
template <typename T>
PtTriLocation::Enum locatePointTriangle(
const V2d<T>& p,
const V2d<T>& v1,
const V2d<T>& v2,
const V2d<T>& v3)
{
using namespace predicates::adaptive;
PtTriLocation::Enum result = PtTriLocation::Inside;
PtLineLocation::Enum edgeCheck = locatePointLine(p, v1, v2);
if(edgeCheck == PtLineLocation::Right)
return PtTriLocation::Outside;
if(edgeCheck == PtLineLocation::OnLine)
result = PtTriLocation::OnEdge1;
edgeCheck = locatePointLine(p, v2, v3);
if(edgeCheck == PtLineLocation::Right)
return PtTriLocation::Outside;
if(edgeCheck == PtLineLocation::OnLine)
{
result = (result == PtTriLocation::Inside) ? PtTriLocation::OnEdge2
: PtTriLocation::OnVertex;
}
edgeCheck = locatePointLine(p, v3, v1);
if(edgeCheck == PtLineLocation::Right)
return PtTriLocation::Outside;
if(edgeCheck == PtLineLocation::OnLine)
{
result = (result == PtTriLocation::Inside) ? PtTriLocation::OnEdge3
: PtTriLocation::OnVertex;
}
return result;
}
CDT_INLINE_IF_HEADER_ONLY Index opoNbr(const Index vertIndex)
{
if(vertIndex == Index(0))
return Index(1);
if(vertIndex == Index(1))
return Index(2);
if(vertIndex == Index(2))
return Index(0);
assert(false && "Invalid vertex index");
handleException(std::runtime_error("Invalid vertex index"));
return invalidIndex;
}
CDT_INLINE_IF_HEADER_ONLY Index opoVrt(const Index neighborIndex)
{
if(neighborIndex == Index(0))
return Index(2);
if(neighborIndex == Index(1))
return Index(0);
if(neighborIndex == Index(2))
return Index(1);
assert(false && "Invalid neighbor index");
handleException(std::runtime_error("Invalid neighbor index"));
return invalidIndex;
}
CDT_INLINE_IF_HEADER_ONLY Index
opposedTriangleInd(const VerticesArr3& vv, const VertInd iVert)
{
assert(vv[0] == iVert || vv[1] == iVert || vv[2] == iVert);
if(vv[0] == iVert)
return Index(1);
if(vv[1] == iVert)
return Index(2);
return Index(0);
}
CDT_INLINE_IF_HEADER_ONLY Index edgeNeighborInd(
const VerticesArr3& vv,
const VertInd iVedge1,
const VertInd iVedge2)
{
assert(vv[0] == iVedge1 || vv[1] == iVedge1 || vv[2] == iVedge1);
assert(vv[0] == iVedge2 || vv[1] == iVedge2 || vv[2] == iVedge2);
assert(
(vv[0] != iVedge1 && vv[0] != iVedge2) ||
(vv[1] != iVedge1 && vv[1] != iVedge2) ||
(vv[2] != iVedge1 && vv[2] != iVedge2));
/*
* vv[2]
* /\
* n[2]/ \n[1]
* /____\
* vv[0] n[0] vv[1]
*/
if(vv[0] == iVedge1)
{
if(vv[1] == iVedge2)
return Index(0);
return Index(2);
}
if(vv[0] == iVedge2)
{
if(vv[1] == iVedge1)
return Index(0);
return Index(2);
}
return Index(1);
}
CDT_INLINE_IF_HEADER_ONLY Index
opposedVertexInd(const NeighborsArr3& nn, const TriInd iTopo)
{
assert(nn[0] == iTopo || nn[1] == iTopo || nn[2] == iTopo);
if(nn[0] == iTopo)
return Index(2);
if(nn[1] == iTopo)
return Index(0);
return Index(1);
}
CDT_INLINE_IF_HEADER_ONLY Index
vertexInd(const VerticesArr3& vv, const VertInd iV)
{
assert(vv[0] == iV || vv[1] == iV || vv[2] == iV);
if(vv[0] == iV)
return Index(0);
if(vv[1] == iV)
return Index(1);
return Index(2);
}
CDT_INLINE_IF_HEADER_ONLY TriInd
opposedTriangle(const Triangle& tri, const VertInd iVert)
{
return tri.neighbors[opposedTriangleInd(tri.vertices, iVert)];
}
CDT_INLINE_IF_HEADER_ONLY VertInd
opposedVertex(const Triangle& tri, const TriInd iTopo)
{
return tri.vertices[opposedVertexInd(tri.neighbors, iTopo)];
}
/// Given triangle and an edge find neighbor sharing the edge
CDT_INLINE_IF_HEADER_ONLY TriInd
edgeNeighbor(const Triangle& tri, VertInd iVedge1, VertInd iVedge2)
{
return tri.neighbors[edgeNeighborInd(tri.vertices, iVedge1, iVedge2)];
}
template <typename T>
bool isInCircumcircle(
const V2d<T>& p,
const V2d<T>& v1,
const V2d<T>& v2,
const V2d<T>& v3)
{
using namespace predicates::adaptive;
return incircle(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y, p.x, p.y) > T(0);
}
CDT_INLINE_IF_HEADER_ONLY
bool verticesShareEdge(const TriIndVec& aTris, const TriIndVec& bTris)
{
for(TriIndVec::const_iterator it = aTris.begin(); it != aTris.end(); ++it)
if(std::find(bTris.begin(), bTris.end(), *it) != bTris.end())
return true;
return false;
}
template <typename T>
T distanceSquared(const T ax, const T ay, const T bx, const T by)
{
const T dx = bx - ax;
const T dy = by - ay;
return dx * dx + dy * dy;
}
template <typename T>
T distance(const T ax, const T ay, const T bx, const T by)
{
return std::sqrt(distanceSquared(ax, ay, bx, by));
}
template <typename T>
T distance(const V2d<T>& a, const V2d<T>& b)
{
return distance(a.x, a.y, b.x, b.y);
}
template <typename T>
T distanceSquared(const V2d<T>& a, const V2d<T>& b)
{
return distanceSquared(a.x, a.y, b.x, b.y);
}
bool touchesSuperTriangle(const Triangle& t)
{
return t.vertices[0] < 3 || t.vertices[1] < 3 || t.vertices[2] < 3;
}
} // namespace CDT

View file

@ -0,0 +1,471 @@
/// This Source Code Form is subject to the terms of the Mozilla Public
/// License, v. 2.0. If a copy of the MPL was not distributed with this
/// file, You can obtain one at https://mozilla.org/MPL/2.0/.
/// Contribution of original implementation:
/// Andre Fecteau <andre.fecteau1@gmail.com>
#ifndef KDTREE_KDTREE_H
#define KDTREE_KDTREE_H
#include "CDTUtils.h"
#include <limits>
namespace CDT
{
namespace KDTree
{
struct NodeSplitDirection
{
enum Enum
{
X,
Y,
};
};
/// Simple tree structure with alternating half splitting nodes
/// @details Simple tree structure
/// - Tree to incrementally add points to the structure.
/// - Get the nearest point to a given input.
/// - Does not check for duplicates, expect unique points.
/// @tparam TCoordType type used for storing point coordinate.
/// @tparam NumVerticesInLeaf The number of points per leaf.
/// @tparam InitialStackDepth initial size of stack depth for nearest query.
/// Should be at least 1.
/// @tparam StackDepthIncrement increment of stack depth for nearest query when
/// stack depth is reached.
template <
typename TCoordType,
size_t NumVerticesInLeaf,
size_t InitialStackDepth,
size_t StackDepthIncrement>
class KDTree
{
public:
typedef TCoordType coord_type;
typedef CDT::V2d<coord_type> point_type;
typedef CDT::VertInd point_index;
typedef std::pair<point_type, point_index> value_type;
typedef std::vector<point_index> point_data_vec;
typedef point_data_vec::const_iterator pd_cit;
typedef CDT::VertInd node_index;
typedef CDT::array<node_index, 2> children_type;
/// Stores kd-tree node data
struct Node
{
children_type children; ///< two children if not leaf; {0,0} if leaf
point_data_vec data; ///< points' data if leaf
/// Create empty leaf
Node()
{
setChildren(node_index(0), node_index(0));
data.reserve(NumVerticesInLeaf);
}
/// Children setter for convenience
void setChildren(const node_index c1, const node_index c2)
{
children[0] = c1;
children[1] = c2;
}
/// Check if node is a leaf (has no valid children)
bool isLeaf() const
{
return children[0] == children[1];
}
};
/// Default constructor
KDTree()
: m_rootDir(NodeSplitDirection::X)
, m_min(point_type(
-std::numeric_limits<coord_type>::max(),
-std::numeric_limits<coord_type>::max()))
, m_max(point_type(
std::numeric_limits<coord_type>::max(),
std::numeric_limits<coord_type>::max()))
, m_size(0)
, m_isRootBoxInitialized(false)
, m_tasksStack(InitialStackDepth, NearestTask())
{
m_root = addNewNode();
}
/// Constructor with bounding box known in advance
KDTree(const point_type& min, const point_type& max)
: m_rootDir(NodeSplitDirection::X)
, m_min(min)
, m_max(max)
, m_size(0)
, m_isRootBoxInitialized(true)
, m_tasksStack(InitialStackDepth, NearestTask())
{
m_root = addNewNode();
}
CDT::VertInd size() const
{
return m_size;
}
/// Insert a point into kd-tree
/// @note external point-buffer is used to reduce kd-tree's memory footprint
/// @param iPoint index of point in external point-buffer
/// @param points external point-buffer
void
insert(const point_index& iPoint, const std::vector<point_type>& points)
{
++m_size;
// if point is outside root, extend tree by adding new roots
const point_type& pos = points[iPoint];
while(!isInsideBox(pos, m_min, m_max))
{
extendTree(pos);
}
// now insert the point into the tree
node_index node = m_root;
point_type min = m_min;
point_type max = m_max;
NodeSplitDirection::Enum dir = m_rootDir;
// below: initialized only to suppress warnings
NodeSplitDirection::Enum newDir(NodeSplitDirection::X);
coord_type mid(0);
point_type newMin, newMax;
while(true)
{
if(m_nodes[node].isLeaf())
{
// add point if capacity is not reached
point_data_vec& pd = m_nodes[node].data;
if(pd.size() < NumVerticesInLeaf)
{
pd.push_back(iPoint);
return;
}
// initialize bbox first time the root capacity is reached
if(!m_isRootBoxInitialized)
{
initializeRootBox(points);
min = m_min;
max = m_max;
}
// split a full leaf node
calcSplitInfo(min, max, dir, mid, newDir, newMin, newMax);
const node_index c1 = addNewNode(), c2 = addNewNode();
Node& n = m_nodes[node];
n.setChildren(c1, c2);
point_data_vec& c1data = m_nodes[c1].data;
point_data_vec& c2data = m_nodes[c2].data;
// move node's points to children
for(pd_cit it = n.data.begin(); it != n.data.end(); ++it)
{
whichChild(points[*it], mid, dir) == 0
? c1data.push_back(*it)
: c2data.push_back(*it);
}
n.data = point_data_vec();
}
else
{
calcSplitInfo(min, max, dir, mid, newDir, newMin, newMax);
}
// add the point to a child
const std::size_t iChild = whichChild(points[iPoint], mid, dir);
iChild == 0 ? max = newMax : min = newMin;
node = m_nodes[node].children[iChild];
dir = newDir;
}
}
/// Query kd-tree for a nearest neighbor point
/// @note external point-buffer is used to reduce kd-tree's memory footprint
/// @param point query point position
/// @param points external point-buffer
value_type nearest(
const point_type& point,
const std::vector<point_type>& points) const
{
value_type out;
int iTask = -1;
coord_type minDistSq = std::numeric_limits<coord_type>::max();
m_tasksStack[++iTask] = NearestTask(
m_root,
m_min,
m_max,
m_rootDir,
distanceSquaredToBox(point, m_min, m_max));
while(iTask != -1)
{
const NearestTask t = m_tasksStack[iTask--];
if(t.distSq > minDistSq)
continue;
const Node& n = m_nodes[t.node];
if(n.isLeaf())
{
for(pd_cit it = n.data.begin(); it != n.data.end(); ++it)
{
const point_type& p = points[*it];
const coord_type distSq = CDT::distanceSquared(point, p);
if(distSq < minDistSq)
{
minDistSq = distSq;
out.first = p;
out.second = *it;
}
}
}
else
{
coord_type mid(0);
NodeSplitDirection::Enum newDir(NodeSplitDirection::X);
point_type newMin = t.min, newMax = t.max;
coord_type dSqFarther = std::numeric_limits<coord_type>::max();
switch(t.dir)
{
case NodeSplitDirection::X:
{
mid = (t.min.x + t.max.x) / coord_type(2);
newDir = NodeSplitDirection::Y;
newMin.x = mid;
newMax.x = mid;
const coord_type dx = point.x - mid;
const coord_type dy = std::max(
std::max(t.min.y - point.y, coord_type(0)),
point.y - t.max.y);
dSqFarther = dx * dx + dy * dy;
break;
}
case NodeSplitDirection::Y:
{
mid = (t.min.y + t.max.y) / coord_type(2);
newDir = NodeSplitDirection::X;
newMin.y = mid;
newMax.y = mid;
const coord_type dx = std::max(
std::max(t.min.x - point.x, coord_type(0)),
point.x - t.max.x);
const coord_type dy = point.y - mid;
dSqFarther = dx * dx + dy * dy;
break;
}
}
if(iTask + 2 >= static_cast<int>(m_tasksStack.size()))
{
m_tasksStack.resize(
m_tasksStack.size() + StackDepthIncrement);
}
// put the closest node on top of the stack
if(isAfterSplit(point, mid, t.dir))
{
if(dSqFarther <= minDistSq)
{
m_tasksStack[++iTask] = NearestTask(
n.children[0], t.min, newMax, newDir, dSqFarther);
}
m_tasksStack[++iTask] = NearestTask(
n.children[1], newMin, t.max, newDir, t.distSq);
}
else
{
if(dSqFarther <= minDistSq)
{
m_tasksStack[++iTask] = NearestTask(
n.children[1], newMin, t.max, newDir, dSqFarther);
}
m_tasksStack[++iTask] = NearestTask(
n.children[0], t.min, newMax, newDir, t.distSq);
}
}
}
return out;
}
private:
/// Add a new node and return it's index in nodes buffer
node_index addNewNode()
{
const node_index newNodeIndex = static_cast<node_index>(m_nodes.size());
m_nodes.push_back(Node());
return newNodeIndex;
}
static bool isAfterSplit(
const point_type& point,
const coord_type& split,
const NodeSplitDirection::Enum dir)
{
return dir == NodeSplitDirection::X ? point.x > split : point.y > split;
}
/// Test which child point belongs to after the split
/// @returns 0 if first child, 1 if second child
static std::size_t whichChild(
const point_type& point,
const coord_type& split,
const NodeSplitDirection::Enum dir)
{
return isAfterSplit(point, split, dir);
}
/// Calculate split location, direction, and children boxes
static void calcSplitInfo(
const point_type& min,
const point_type& max,
const NodeSplitDirection::Enum dir,
coord_type& midOut,
NodeSplitDirection::Enum& newDirOut,
point_type& newMinOut,
point_type& newMaxOut)
{
newMaxOut = max;
newMinOut = min;
switch(dir)
{
case NodeSplitDirection::X:
midOut = (min.x + max.x) / coord_type(2);
newDirOut = NodeSplitDirection::Y;
newMinOut.x = midOut;
newMaxOut.x = midOut;
return;
case NodeSplitDirection::Y:
midOut = (min.y + max.y) / coord_type(2);
newDirOut = NodeSplitDirection::X;
newMinOut.y = midOut;
newMaxOut.y = midOut;
return;
}
}
/// Test if point is inside a box
static bool isInsideBox(
const point_type& p,
const point_type& min,
const point_type& max)
{
return p.x >= min.x && p.x <= max.x && p.y >= min.y && p.y <= max.y;
}
/// Extend a tree by creating new root with old root and a new node as
/// children
void extendTree(const point_type& point)
{
const node_index newRoot = addNewNode();
const node_index newLeaf = addNewNode();
switch(m_rootDir)
{
case NodeSplitDirection::X:
m_rootDir = NodeSplitDirection::Y;
if(point.y < m_min.y)
{
m_min.y -= m_max.y - m_min.y;
m_nodes[newRoot].setChildren(newLeaf, m_root);
}
else
{
m_max.y += m_max.y - m_min.y;
m_nodes[newRoot].setChildren(m_root, newLeaf);
}
break;
case NodeSplitDirection::Y:
m_rootDir = NodeSplitDirection::X;
if(point.x < m_min.x)
{
m_min.x -= m_max.x - m_min.x;
m_nodes[newRoot].setChildren(newLeaf, m_root);
}
else
{
m_max.x += m_max.x - m_min.x;
m_nodes[newRoot].setChildren(m_root, newLeaf);
}
break;
}
m_root = newRoot;
}
/// Calculate root's box enclosing all root points
void initializeRootBox(const std::vector<point_type>& points)
{
const point_data_vec& data = m_nodes[m_root].data;
m_min = points[data.front()];
m_max = m_min;
for(pd_cit it = data.begin(); it != data.end(); ++it)
{
const point_type& p = points[*it];
m_min = point_type(std::min(m_min.x, p.x), std::min(m_min.y, p.y));
m_max = point_type(std::max(m_max.x, p.x), std::max(m_max.y, p.y));
}
// Make sure bounding box does not have a zero size by adding padding:
// zero-size bounding box cannot be extended properly
const TCoordType padding(1);
if(m_min.x == m_max.x)
{
m_min.x -= padding;
m_max.x += padding;
}
if(m_min.y == m_max.y)
{
m_min.y -= padding;
m_max.y += padding;
}
m_isRootBoxInitialized = true;
}
static coord_type distanceSquaredToBox(
const point_type& p,
const point_type& min,
const point_type& max)
{
const coord_type dx =
std::max(std::max(min.x - p.x, coord_type(0)), p.x - max.x);
const coord_type dy =
std::max(std::max(min.y - p.y, coord_type(0)), p.y - max.y);
return dx * dx + dy * dy;
}
private:
node_index m_root;
std::vector<Node> m_nodes;
NodeSplitDirection::Enum m_rootDir;
point_type m_min;
point_type m_max;
CDT::VertInd m_size;
bool m_isRootBoxInitialized;
// used for nearest query
struct NearestTask
{
node_index node;
point_type min, max;
NodeSplitDirection::Enum dir;
coord_type distSq;
NearestTask()
: dir(NodeSplitDirection::X)
{}
NearestTask(
const node_index node,
const point_type& min,
const point_type& max,
const NodeSplitDirection::Enum dir,
const coord_type distSq = std::numeric_limits<coord_type>::max())
: node(node)
, min(min)
, max(max)
, dir(dir)
, distSq(distSq)
{}
};
// allocated in class (not in the 'nearest' method) for better performance
mutable std::vector<NearestTask> m_tasksStack;
};
} // namespace KDTree
} // namespace CDT
#endif // header guard

View file

@ -0,0 +1,81 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/**
* @file
* Adapter between for KDTree and CDT
*/
#ifndef CDT_POINTKDTREE_H
#define CDT_POINTKDTREE_H
#include "CDTUtils.h"
#include "KDTree.h"
namespace CDT
{
/// KD-tree holding points
template <
typename TCoordType,
size_t NumVerticesInLeaf = 32,
size_t InitialStackDepth = 32,
size_t StackDepthIncrement = 32>
class LocatorKDTree
{
public:
/// Initialize KD-tree with points
void initialize(const std::vector<V2d<TCoordType> >& points)
{
typedef V2d<TCoordType> V2d_t;
V2d_t min = points.front();
V2d_t max = min;
typedef typename std::vector<V2d_t>::const_iterator Cit;
for(Cit it = points.begin(); it != points.end(); ++it)
{
min = V2d_t(std::min(min.x, it->x), std::min(min.y, it->y));
max = V2d_t(std::max(max.x, it->x), std::max(max.y, it->y));
}
m_kdTree = KDTree_t(min, max);
for(VertInd i(0); i < points.size(); ++i)
{
m_kdTree.insert(i, points);
}
}
/// Add point to KD-tree
void addPoint(const VertInd i, const std::vector<V2d<TCoordType> >& points)
{
m_kdTree.insert(i, points);
}
/// Find nearest point using R-tree
VertInd nearPoint(
const V2d<TCoordType>& pos,
const std::vector<V2d<TCoordType> >& points) const
{
return m_kdTree.nearest(pos, points).second;
}
CDT::VertInd size() const
{
return m_kdTree.size();
}
bool empty() const
{
return !size();
}
private:
typedef KDTree::KDTree<
TCoordType,
NumVerticesInLeaf,
InitialStackDepth,
StackDepthIncrement>
KDTree_t;
KDTree_t m_kdTree;
};
} // namespace CDT
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,313 @@
// This code is copied from LLVM's libc++
// https://github.com/llvm-mirror/libcxx/blob/4dde9ccef57d50e50620408a0b7a902f0aba803e/include/algorithm
// It is needed to provide portable nth_element on different platforms
// -*- C++ -*-
//===-------------------------- algorithm ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef CDT_PORTABLE_NTH_ELEMENT
#define CDT_PORTABLE_NTH_ELEMENT
#include <algorithm>
#include <iterator>
#ifdef CDT_CXX11_IS_SUPPORTED
#include <type_traits>
#else
#include <boost/type_traits/add_lvalue_reference.hpp>
#endif
namespace CDT
{
namespace detail
{
// sort
// stable, 2-3 compares, 0-2 swaps
template <class Compare, class ForwardIterator>
unsigned
sort3(ForwardIterator x, ForwardIterator y, ForwardIterator z, Compare c)
{
unsigned r = 0;
if(!c(*y, *x)) // if x <= y
{
if(!c(*z, *y)) // if y <= z
return r; // x <= y && y <= z
// x <= y && y > z
std::swap(*y, *z); // x <= z && y < z
r = 1;
if(c(*y, *x)) // if x > y
{
std::swap(*x, *y); // x < y && y <= z
r = 2;
}
return r; // x <= y && y < z
}
if(c(*z, *y)) // x > y, if y > z
{
std::swap(*x, *z); // x < y && y < z
r = 1;
return r;
}
std::swap(*x, *y); // x > y && y <= z
r = 1; // x < y && x <= z
if(c(*z, *y)) // if y > z
{
std::swap(*y, *z); // x <= y && y < z
r = 2;
}
return r;
} // x <= y && y <= z
// Assumes size > 0
template <class Compare, class BirdirectionalIterator>
void selection_sort(
BirdirectionalIterator first,
BirdirectionalIterator last,
Compare comp)
{
BirdirectionalIterator lm1 = last;
for(--lm1; first != lm1; ++first)
{
#ifdef CDT_CXX11_IS_SUPPORTED
BirdirectionalIterator i = std::min_element<
BirdirectionalIterator,
typename std::add_lvalue_reference<Compare>::type>(
first, last, comp);
#else
BirdirectionalIterator i = std::min_element<
BirdirectionalIterator,
typename boost::add_lvalue_reference<Compare>::type>(
first, last, comp);
#endif
if(i != first)
std::swap(*first, *i);
}
}
// nth_element
template <class Compare, class RandomAccessIterator>
void nth_element(
RandomAccessIterator first,
RandomAccessIterator nth,
RandomAccessIterator last,
Compare comp)
{
// Compare is known to be a reference type
typedef typename std::iterator_traits<RandomAccessIterator>::difference_type
difference_type;
const difference_type limit = 7;
while(true)
{
restart:
if(nth == last)
return;
difference_type len = last - first;
switch(len)
{
case 0:
case 1:
return;
case 2:
if(comp(*--last, *first))
std::swap(*first, *last);
return;
case 3: {
RandomAccessIterator m = first;
detail::sort3<Compare>(first, ++m, --last, comp);
return;
}
}
if(len <= limit)
{
detail::selection_sort<Compare>(first, last, comp);
return;
}
// len > limit >= 3
RandomAccessIterator m = first + len / 2;
RandomAccessIterator lm1 = last;
unsigned n_swaps = detail::sort3<Compare>(first, m, --lm1, comp);
// *m is median
// partition [first, m) < *m and *m <= [m, last)
// (this inhibits tossing elements equivalent to m around
// unnecessarily)
RandomAccessIterator i = first;
RandomAccessIterator j = lm1;
// j points beyond range to be tested, *lm1 is known to be <= *m
// The search going up is known to be guarded but the search coming
// down isn't. Prime the downward search with a guard.
if(!comp(*i, *m)) // if *first == *m
{
// *first == *m, *first doesn't go in first part
// manually guard downward moving j against i
while(true)
{
if(i == --j)
{
// *first == *m, *m <= all other elements
// Parition instead into [first, i) == *first and
// *first < [i, last)
++i; // first + 1
j = last;
if(!comp(*first, *--j)) // we need a guard if
// *first == *(last-1)
{
while(true)
{
if(i == j)
return; // [first, last) all equivalent
// elements
if(comp(*first, *i))
{
std::swap(*i, *j);
++n_swaps;
++i;
break;
}
++i;
}
}
// [first, i) == *first and *first < [j,
// last) and j == last - 1
if(i == j)
return;
while(true)
{
while(!comp(*first, *i))
++i;
while(comp(*first, *--j))
;
if(i >= j)
break;
std::swap(*i, *j);
++n_swaps;
++i;
}
// [first, i) == *first and *first < [i,
// last) The first part is sorted,
if(nth < i)
return;
// nth_element the secod part
// nth_element<Compare>(i, nth, last, comp);
first = i;
goto restart;
}
if(comp(*j, *m))
{
std::swap(*i, *j);
++n_swaps;
break; // found guard for downward moving j, now use
// unguarded partition
}
}
}
++i;
// j points beyond range to be tested, *lm1 is known to be <= *m
// if not yet partitioned...
if(i < j)
{
// known that *(i - 1) < *m
while(true)
{
// m still guards upward moving i
while(comp(*i, *m))
++i;
// It is now known that a guard exists for downward moving
// j
while(!comp(*--j, *m))
;
if(i >= j)
break;
std::swap(*i, *j);
++n_swaps;
// It is known that m != j
// If m just moved, follow it
if(m == i)
m = j;
++i;
}
}
// [first, i) < *m and *m <= [i, last)
if(i != m && comp(*m, *i))
{
std::swap(*i, *m);
++n_swaps;
}
// [first, i) < *i and *i <= [i+1, last)
if(nth == i)
return;
if(n_swaps == 0)
{
// We were given a perfectly partitioned sequence. Coincidence?
if(nth < i)
{
// Check for [first, i) already sorted
j = m = first;
while(++j != i)
{
if(comp(*j, *m))
// not yet sorted, so sort
goto not_sorted;
m = j;
}
// [first, i) sorted
return;
}
else
{
// Check for [i, last) already sorted
j = m = i;
while(++j != last)
{
if(comp(*j, *m))
// not yet sorted, so sort
goto not_sorted;
m = j;
}
// [i, last) sorted
return;
}
}
not_sorted:
// nth_element on range containing nth
if(nth < i)
{
// nth_element<Compare>(first, nth, i, comp);
last = i;
}
else
{
// nth_element<Compare>(i+1, nth, last, comp);
first = ++i;
}
}
}
template <class _RandomAccessIterator, class _Compare>
inline void portable_nth_element(
_RandomAccessIterator first,
_RandomAccessIterator nth,
_RandomAccessIterator last,
_Compare comp)
{
#ifdef CDT_CXX11_IS_SUPPORTED
detail::nth_element<typename std::add_lvalue_reference<_Compare>::type>(
first, nth, last, comp);
#else
detail::nth_element<typename boost::add_lvalue_reference<_Compare>::type>(
first, nth, last, comp);
#endif
}
} // namespace detail
} // namespace CDT
#endif // CDT_PORTABLE_NTH_ELEMENT

View file

@ -0,0 +1,915 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (c) 2019, William C. Lenthe *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions are met: *
* *
* 1. Redistributions of source code must retain the above copyright notice, this *
* list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, *
* this list of conditions and the following disclaimer in the documentation *
* and/or other materials provided with the distribution. *
* *
* 3. Neither the name of the copyright holder nor the names of its *
* contributors may be used to endorse or promote products derived from *
* this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" *
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE *
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE *
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef PREDICATES_H_INCLUDED
#define PREDICATES_H_INCLUDED
//@reference: https://www.cs.cmu.edu/~quake/robust.html
namespace predicates {
//@brief: geometric predicates using arbitrary precision arithmetic
//@note : these are provided primarily for illustrative purposes and adaptive routines should be preferred
namespace exact {
//@brief : determine if the 2d point c is above, on, or below the line defined by a and b
//@param ax: X-coordinate of a
//@param ay: Y-coordinate of a
//@param bx: X-coordinate of b
//@param by: Y-coordinate of b
//@param cx: X-coordinate of c
//@param cy: Y-coordinate of c
//@return : determinant of {{ax - cx, ay - cy}, {bx - cx, by - cy}}
//@note : positive, 0, negative result for c above, on, or below the line defined by a -> b
template <typename T> T orient2d(T const ax, T const ay, T const bx, T const by, T const cx, T const cy);
//@brief : determine if the 2d point c is above, on, or below the line defined by a and b
//@param pa: pointer to a as {x, y}
//@param pb: pointer to b as {x, y}
//@param pc: pointer to c as {x, y}
//@return : determinant of {{ax - cx, ay - cy}, {bx - cx, by - cy}}
//@note : positive, 0, negative result for c above, on, or below the line defined by a -> b
template <typename T> T orient2d(T const*const pa, T const*const pb, T const*const pc);
//@brief : determine if the 2d point d is inside, on, or outside the circle defined by a, b, and c
//@param ax: X-coordinate of a
//@param ay: Y-coordinate of a
//@param bx: X-coordinate of b
//@param by: Y-coordinate of b
//@param cx: X-coordinate of c
//@param cy: Y-coordinate of c
//@param dx: X-coordinate of d
//@param dy: Y-coordinate of d
//@return : determinant of {{ax - dx, ay - dy, (ax - dx)^2 + (ay - dy)^2}, {bx - dx, by - dy, (bx - dx)^2 + (by - dy)^2}, {cx - dx, cy - dy, (cx - dx)^2 + (cy - dy)^2}}
//@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c
template <typename T> T incircle(T const ax, T const ay, T const bx, T const by, T const cx, T const cy, T const dx, T const dy);
//@brief : determine if the 2d point d is inside, on, or outside the circle defined by a, b, and c
//@param pa: pointer to a as {x, y}
//@param pb: pointer to b as {x, y}
//@param pc: pointer to c as {x, y}
//@param pc: pointer to d as {x, y}
//@return : determinant of {{ax - dx, ay - dy, (ax - dx)^2 + (ay - dy)^2}, {bx - dx, by - dy, (bx - dx)^2 + (by - dy)^2}, {cx - dx, cy - dy, (cx - dx)^2 + (cy - dy)^2}}
//@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c
template <typename T> T incircle(T const*const pa, T const*const pb, T const*const pc, T const*const pd);
//@brief : determine if the 3d point d is above, on, or below the plane defined by a, b, and c
//@param pa: pointer to a as {x, y, z}
//@param pb: pointer to b as {x, y, z}
//@param pc: pointer to c as {x, y, z}
//@param pd: pointer to d as {x, y, z}
//@return : determinant of {{ax - dx, ay - dy, az - dz}, {bx - dx, by - dy, bz - dz}, {cx - dx, cy - dy, cz - dz}}
//@note : positive, 0, negative result for c above, on, or below the plane defined by a, b, and c
template <typename T> T orient3d(T const*const pa, T const*const pb, T const*const pc, T const*const pd);
//@brief : determine if the 3d point e is inside, on, or outside the sphere defined by a, b, c, and d
//@param pa: pointer to a as {x, y, z}
//@param pb: pointer to b as {x, y, z}
//@param pc: pointer to c as {x, y, z}
//@param pd: pointer to d as {x, y, z}
//@param pe: pointer to e as {x, y, z}
//@return : determinant of {{ax - ex, ay - ey, az - ez, (ax - ex)^2 + (ay - ey)^2 + (az - ez)^2}, {bx - ex, by - ey, bz - ez, (bx - ex)^2 + (by - ey)^2 + (bz - ez)^2}, {cx - ex, cy - ey, cz - ez, (cx - ex)^2 + (cy - ey)^2 + (cz - ez)^2}, {dx - ex, dy - ey, dz - ez, (dx - ex)^2 + (dy - ey)^2 + (dz - ez)^2}}
//@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c
template <typename T> T insphere(T const*const pa, T const*const pb, T const*const pc, T const*const pd, T const*const pe);
}
//@brief: geometric predicates using normal floating point arithmetic but falling back to arbitrary precision when needed
//@note : these should have the same accuracy but are significantly faster when determinants are large
namespace adaptive {
//@brief : determine if the 2d point c is above, on, or below the line defined by a and b
//@param ax: X-coordinate of a
//@param ay: Y-coordinate of a
//@param bx: X-coordinate of b
//@param by: Y-coordinate of b
//@param cx: X-coordinate of c
//@param cy: Y-coordinate of c
//@return : determinant of {{ax - cx, ay - cy}, {bx - cx, by - cy}}
//@note : positive, 0, negative result for c above, on, or below the line defined by a -> b
template <typename T> T orient2d(T const ax, T const ay, T const bx, T const by, T const cx, T const cy);
//@brief : determine if the 2d point c is above, on, or below the line defined by a and b
//@param pa: pointer to a as {x, y}
//@param pb: pointer to b as {x, y}
//@param pc: pointer to c as {x, y}
//@return : determinant of {{ax - cx, ay - cy}, {bx - cx, by - cy}}
//@note : positive, 0, negative result for c above, on, or below the line defined by a -> b
template <typename T> T orient2d(T const*const pa, T const*const pb, T const*const pc);
//@brief : determine if the 2d point d is inside, on, or outside the circle defined by a, b, and c
//@param ax: X-coordinate of a
//@param ay: Y-coordinate of a
//@param bx: X-coordinate of b
//@param by: Y-coordinate of b
//@param cx: X-coordinate of c
//@param cy: Y-coordinate of c
//@param dx: X-coordinate of d
//@param dy: Y-coordinate of d
//@return : determinant of {{ax - dx, ay - dy, (ax - dx)^2 + (ay - dy)^2}, {bx - dx, by - dy, (bx - dx)^2 + (by - dy)^2}, {cx - dx, cy - dy, (cx - dx)^2 + (cy - dy)^2}}
//@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c
template <typename T> T incircle(T const ax, T const ay, T const bx, T const by, T const cx, T const cy, T const dx, T const dy);
//@brief : determine if the 2d point d is inside, on, or outside the circle defined by a, b, and c
//@param pa: pointer to a as {x, y}
//@param pb: pointer to b as {x, y}
//@param pc: pointer to c as {x, y}
//@param pc: pointer to d as {x, y}
//@return : determinant of {{ax - dx, ay - dy, (ax - dx)^2 + (ay - dy)^2}, {bx - dx, by - dy, (bx - dx)^2 + (by - dy)^2}, {cx - dx, cy - dy, (cx - dx)^2 + (cy - dy)^2}}
//@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c
template <typename T> T incircle(T const*const pa, T const*const pb, T const*const pc, T const*const pd);
//@brief : determine if the 3d point d is above, on, or below the plane defined by a, b, and c
//@param pa: pointer to a as {x, y, z}
//@param pb: pointer to b as {x, y, z}
//@param pc: pointer to c as {x, y, z}
//@param pd: pointer to d as {x, y, z}
//@return : determinant of {{ax - dx, ay - dy, az - dz}, {bx - dx, by - dy, bz - dz}, {cx - dx, cy - dy, cz - dz}}
//@note : positive, 0, negative result for c above, on, or below the plane defined by a, b, and c
template <typename T> T orient3d(T const*const pa, T const*const pb, T const*const pc, T const*const pd);
//@brief : determine if the 3d point e is inside, on, or outside the sphere defined by a, b, c, and d
//@param pa: pointer to a as {x, y, z}
//@param pb: pointer to b as {x, y, z}
//@param pc: pointer to c as {x, y, z}
//@param pd: pointer to d as {x, y, z}
//@param pe: pointer to e as {x, y, z}
//@return : determinant of {{ax - ex, ay - ey, az - ez, (ax - ex)^2 + (ay - ey)^2 + (az - ez)^2}, {bx - ex, by - ey, bz - ez, (bx - ex)^2 + (by - ey)^2 + (bz - ez)^2}, {cx - ex, cy - ey, cz - ez, (cx - ex)^2 + (cy - ey)^2 + (cz - ez)^2}, {dx - ex, dy - ey, dz - ez, (dx - ex)^2 + (dy - ey)^2 + (dz - ez)^2}}
//@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c
template <typename T> T insphere(T const*const pa, T const*const pb, T const*const pc, T const*const pd, T const*const pe);
}
}
#include <cmath>//abs, fma
#include <limits>
#include <utility>//pair
#include <numeric>//accumulate
#include <algorithm>//transform, copy_n, merge
#include <functional>//negate
// a macro based static assert for pre c++11
#define PREDICATES_PORTABLE_STATIC_ASSERT(condition, message) typedef char message[(condition) ? 1 : -1]
// check if c++11 is supported
#if !defined(__cplusplus) && !defined(_MSC_VER)
PREDICATES_PORTABLE_STATIC_ASSERT(false, couldnt_parse_cxx_standard)
#endif
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
#define PREDICATES_CXX11_IS_SUPPORTED
#endif
// choose to use c++11 features or their backports
#ifdef PREDICATES_CXX11_IS_SUPPORTED
#include <array>
#include <type_traits>// is_same, enable_if
#undef PREDICATES_PORTABLE_STATIC_ASSERT
#define PREDICATES_TOKEN_TO_STRING1(x) #x
#define PREDICATES_TOKEN_TO_STRING(x) PREDICATES_TOKEN_TO_STRING1(x)
#define PREDICATES_PORTABLE_STATIC_ASSERT(condition, message) static_assert(condition, PREDICATES_TOKEN_TO_STRING(message))
namespace predicates {
namespace stdx {
using std::array;
using std::copy_n;
}
#else
namespace predicates {
namespace stdx {
// array
template<typename T, size_t N>
class array {
T buff[N];
public:
T& operator[](const size_t& i) { return buff[i]; }
const T& operator[](const size_t& i) const { return buff[i]; }
T * data() { return buff; }
T const * data() const { return buff; }
T * begin() { return buff; }
T const * cbegin() const { return buff; }
};
// copy_n
template< class InputIt, class Size, class OutputIt>
OutputIt copy_n(InputIt first, Size count, OutputIt result)
{
if (count > 0) {
*result++ = *first;
for (Size i = 1; i < count; ++i) {
*result++ = *++first;
}
}
return result;
}
}
#endif // PREDICATES_CXX11_IS_SUPPORTED
namespace detail {
template<typename T> class ExpansionBase;
//@brief: class to exactly represent the result of a sequence of arithmetic operations as an sequence of values that sum to the result
template<typename T, size_t N>
class Expansion : private ExpansionBase<T>, public stdx::array<T, N> {
private:
public:
size_t m_size;
template <typename S> friend class ExpansionBase;//access for base class
template <typename S, size_t M> friend class Expansion;//access for expansions of different size
Expansion() : m_size(0) {}
template <size_t M> Expansion& operator=(const Expansion<T, M>& e) {
PREDICATES_PORTABLE_STATIC_ASSERT(M <= N, cannot_assign_a_larger_expansion_to_a_smaller_expansion);
stdx::copy_n(e.cbegin(), e.size(), stdx::array<T, N>::begin());
m_size = e.size();
return *this;
}
//vector like convenience functions
size_t size() const {return m_size;}
bool empty() const {return 0 == m_size;}
void push_back(const T v) {stdx::array<T, N>::operator[](m_size++) = v;}
public:
//estimates of expansion value
T mostSignificant() const {return empty() ? T(0) : stdx::array<T, N>::operator[](m_size - 1);}
T estimate() const {return std::accumulate(stdx::array<T, N>::cbegin(), stdx::array<T, N>::cbegin() + size(), T(0));}
template <size_t M> Expansion<T, N+M> operator+(const Expansion<T, M>& f) const {
Expansion<T, N+M> h;
h.m_size = ExpansionBase<T>::ExpansionSum(this->data(), this->size(), f.data(), f.size(), h.data());
return h;
}
void negate() {std::transform(stdx::array<T, N>::cbegin(), stdx::array<T, N>::cbegin() + size(), stdx::array<T, N>::begin(), std::negate<T>());}
Expansion operator-() const {Expansion e = *this; e.negate(); return e;}
template <size_t M> Expansion<T, N+M> operator-(const Expansion<T, M>& f) const {return operator+(-f);}
Expansion<T, 2*N> operator*(const T b) const {
Expansion<T, 2*N> h;
h.m_size = ExpansionBase<T>::ScaleExpansion(this->data(), this->size(), b, h.data());
return h;
}
};
// See: https://stackoverflow.com/a/40765925/1597714
// Standard defines: https://en.cppreference.com/w/cpp/numeric/math/fma
#if defined(__FMA__) || defined(__FMA4__) || defined(__AVX2__) || (defined(FP_FAST_FMA) && defined(FP_FAST_FMAF))
#define PREDICATES_FAST_FMA 1
#endif
//@brief : helper function to sort by absolute value
//@param a: lhs item to compare
//@param b: rhs item to compare
//@return : true if |a| < |b|
//@note : defined since lambda functions aren't allow in c++03
template <typename T> bool absLess(const T& a, const T& b) {return std::abs(a) < std::abs(b);}
template<typename T>
class ExpansionBase {
private:
static const T Splitter;
PREDICATES_PORTABLE_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, Requires_IEC_559_IEEE_754_floating_point_type);
PREDICATES_PORTABLE_STATIC_ASSERT(2 == std::numeric_limits<T>::radix, Requires_base_2_floating_point_type);
//combine result + roundoff error into expansion
static inline Expansion<T, 2> MakeExpansion(const T value, const T tail) {
Expansion<T, 2> e;
if(T(0) != tail) e.push_back(tail);
if(T(0) != value) e.push_back(value);
return e;
}
protected:
//add 2 expansions
static size_t ExpansionSum(T const * const e, const size_t n, T const * const f, const size_t m, T * const h) {
std::merge(e, e + n, f, f + m, h, absLess<T>);
if(m == 0) return n;
if(n == 0) return m;
size_t hIndex = 0;
T Q = h[0];
T Qnew = h[1] + Q;
T hh = FastPlusTail(h[1], Q, Qnew);
Q = Qnew;
if(T(0) != hh) h[hIndex++] = hh;
for(size_t g = 2; g != n + m; ++g) {
Qnew = Q + h[g];
hh = PlusTail(Q, h[g], Qnew);
Q = Qnew;
if(T(0) != hh) h[hIndex++] = hh;
}
if(T(0) != Q) h[hIndex++] = Q;
return hIndex;
}
//scale an expansion by a constant
static size_t ScaleExpansion(T const * const e, const size_t n, const T b, T * const h) {
if(n == 0 || T(0) == b) return 0;
size_t hIndex = 0;
T Q = e[0] * b;
const std::pair<T, T> bSplit = Split(b);
T hh = MultTailPreSplit(e[0], b, bSplit, Q);
if(T(0) != hh) h[hIndex++] = hh;
for(size_t eIndex = 1; eIndex < n; ++eIndex) {
T Ti = e[eIndex] * b;
T ti = MultTailPreSplit(e[eIndex], b, bSplit, Ti);
T Qi = Q + ti;
hh = PlusTail(Q, ti, Qi);
if(T(0) != hh) h[hIndex++] = hh;
Q = Ti + Qi;
hh = FastPlusTail(Ti, Qi, Q);
if(T(0) != hh) h[hIndex++] = hh;
}
if(T(0) != Q) h[hIndex++] = Q;
return hIndex;
}
public:
//roundoff error of x = a + b
static inline T PlusTail(const T a, const T b, const T x) {
const T bVirtual = x - a;
const T aVirtual = x - bVirtual;
const T bRoundoff = b - bVirtual;
const T aRoundoff = a - aVirtual;
return aRoundoff + bRoundoff;
}
//roundoff error of x = a + b if |a| > |b|
static inline T FastPlusTail(const T a, const T b, const T x) {
const T bVirtual = x - a;
return b - bVirtual;
}
//roundoff error of x = a - b
static inline T MinusTail(const T a, const T b, const T x) {
const T bVirtual = a - x;
const T aVirtual = x + bVirtual;
const T bRoundoff = bVirtual - b;
const T aRoundoff = a - aVirtual;
return aRoundoff + bRoundoff;
}
//split a into 2 nonoverlapping values
static inline std::pair<T, T> Split(const T a) {
const T c = a * Splitter;
const T aBig = c - a;
const T aHi = c - aBig;
return std::pair<T, T>(aHi, a - aHi);
}
//roundoff error of x = a * b via dekkers product
static inline T DekkersProduct(const T /*a*/, const std::pair<T, T> aSplit, const T /*b*/, const std::pair<T, T> bSplit, const T p) {
T y = p - T(aSplit.first * bSplit.first);
y -= T(aSplit.second * bSplit.first);
y -= T(aSplit.first * bSplit.second);
return T(aSplit.second * bSplit.second) - y;
}
//roundoff error of x = a * b
#if defined(PREDICATES_CXX11_IS_SUPPORTED) && defined(PREDICATES_FAST_FMA)
static T MultTail(const T a, const T b, const T p) {return std::fma(a, b, -p);}
static T MultTailPreSplit(const T a, const T b, const std::pair<T, T> /*bSplit*/, const T p) {return std::fma(a, b, -p);}
#else
static T MultTail(const T a, const T b, const T p) {return DekkersProduct(a, Split(a), b, Split(b), p);}
static T MultTailPreSplit(const T a, const T b, const std::pair<T, T> bSplit, const T p) {return DekkersProduct(a, Split(a), b, bSplit, p);}
#endif
//expand a + b
static inline Expansion<T, 2> Plus(const T a, const T b) {
const T x = a + b;
return MakeExpansion(x, PlusTail(a, b, x));
}
//expand a - b
static inline Expansion<T, 2> Minus(const T a, const T b) {return Plus(a, -b);}
//expand a * b
static inline Expansion<T, 2> Mult(const T a, const T b) {
const T x = a * b;
return MakeExpansion(x, MultTail(a, b, x));
}
//expand the determinant of {{ax, ay}, {bx, by}} (unrolled Mult(ax, by) - Mult(ay, bx))
static inline Expansion<T, 4> TwoTwoDiff(const T ax, const T by, const T ay, const T bx) {
const T axby1 = ax * by;
const T axby0 = MultTail(ax, by, axby1);
const T bxay1 = bx * ay;
const T bxay0 = MultTail(bx, ay, bxay1);
const T _i0 = axby0 - bxay0;
const T x0 = MinusTail(axby0, bxay0, _i0);
const T _j = axby1 + _i0;
const T _0 = PlusTail(axby1, _i0, _j);
const T _i1 = _0 - bxay1;
const T x1 = MinusTail(_0, bxay1, _i1);
const T x3 = _j + _i1;
const T x2 = PlusTail(_j, _i1, x3);
Expansion<T, 4> e;
if(T(0) != x0) e.push_back(x0);
if(T(0) != x1) e.push_back(x1);
if(T(0) != x2) e.push_back(x2);
if(T(0) != x3) e.push_back(x3);
return e;
}
//TwoTwoDiff checking for zeros to avoid extra splitting
static inline Expansion<T, 4> TwoTwoDiffZeroCheck(const T ax, const T by, const T ay, const T bx) {
Expansion<T, 4> e;
if(T(0) == ax && T(0) == ay) return e;
else if(T(0) == ax) e = Mult(ay, bx);
else if(T(0) == ay) e = Mult(ax, by);
else e = TwoTwoDiff(ax, by, ay, bx);
return e;
}
//(a * b) * c checking for zeros
static inline Expansion<T, 4> ThreeProd(const T a, const T b, const T c) {return (T(0) == a || T(0) == b || T(0) == c) ? Expansion<T, 4>() : Mult(a, b) * c;}
};
template <typename T> const T ExpansionBase<T>::Splitter =
#ifdef PREDICATES_CXX11_IS_SUPPORTED
static_cast<T>(std::exp2(std::numeric_limits<T>::digits/2 + 1));
#else
static_cast<T>(std::ldexp(T(1), std::numeric_limits<T>::digits/2 + 1));
#endif
}
namespace exact {
template <typename T> T orient2d(T const ax, T const ay, T const bx, T const by, T const cx, T const cy)
{
const detail::Expansion<T, 4> aterms = detail::ExpansionBase<T>::TwoTwoDiff(ax, by, ax, cy);
const detail::Expansion<T, 4> bterms = detail::ExpansionBase<T>::TwoTwoDiff(bx, cy, bx, ay);
const detail::Expansion<T, 4> cterms = detail::ExpansionBase<T>::TwoTwoDiff(cx, ay, cx, by);
const detail::Expansion<T, 12> w = aterms + bterms + cterms;
return w.mostSignificant();
}
template <typename T> T orient2d(T const*const pa, T const*const pb, T const*const pc) {
return orient2d(pa[0], pa[1], pb[0], pb[1], pc[0], pc[1]);
}
template <typename T> T incircle(T const ax, T const ay, T const bx, T const by, T const cx, T const cy, T const dx, T const dy) {
const detail::Expansion<T, 4> ab = detail::ExpansionBase<T>::TwoTwoDiff(ax, by, bx, ay);
const detail::Expansion<T, 4> bc = detail::ExpansionBase<T>::TwoTwoDiff(bx, cy, cx, by);
const detail::Expansion<T, 4> cd = detail::ExpansionBase<T>::TwoTwoDiff(cx, dy, dx, cy);
const detail::Expansion<T, 4> da = detail::ExpansionBase<T>::TwoTwoDiff(dx, ay, ax, dy);
const detail::Expansion<T, 4> ac = detail::ExpansionBase<T>::TwoTwoDiff(ax, cy, cx, ay);
const detail::Expansion<T, 4> bd = detail::ExpansionBase<T>::TwoTwoDiff(bx, dy, dx, by);
const detail::Expansion<T, 12> abc = ab + bc - ac;
const detail::Expansion<T, 12> bcd = bc + cd - bd;
const detail::Expansion<T, 12> cda = cd + da + ac;
const detail::Expansion<T, 12> dab = da + ab + bd;
const detail::Expansion<T, 96> adet = bcd * ax * ax + bcd * ay * ay;
const detail::Expansion<T, 96> bdet = cda * bx * -bx + cda * by * -by;
const detail::Expansion<T, 96> cdet = dab * cx * cx + dab * cy * cy;
const detail::Expansion<T, 96> ddet = abc * dx * -dx + abc * dy * -dy;
const detail::Expansion<T, 384> deter = (adet + bdet) + (cdet + ddet);
return deter.mostSignificant();
}
template <typename T> T incircle(T const*const pa, T const*const pb, T const*const pc, T const*const pd) {
return incircle(pa[0], pa[1], pb[0], pb[1], pc[0], pc[1], pd[0], pd[1]);
}
//@brief : determine if the 3d point d is above, on, or below the plane defined by a, b, and c
//@param pa: pointer to a as {x, y, z}
//@param pb: pointer to b as {x, y, z}
//@param pc: pointer to c as {x, y, z}
//@param pd: pointer to d as {x, y, z}
//@return : determinant of {{ax - dx, ay - dy, az - dz}, {bx - dx, by - dy, bz - dz}, {cx - dx, cy - dy, cz - dz}}
//@note : positive, 0, negative result for c above, on, or below the plane defined by a, b, and c
template <typename T> T orient3d(T const*const pa, T const*const pb, T const*const pc, T const*const pd) {
const detail::Expansion<T, 4> ab = detail::ExpansionBase<T>::TwoTwoDiff(pa[0], pb[1], pb[0], pa[1]);
const detail::Expansion<T, 4> bc = detail::ExpansionBase<T>::TwoTwoDiff(pb[0], pc[1], pc[0], pb[1]);
const detail::Expansion<T, 4> cd = detail::ExpansionBase<T>::TwoTwoDiff(pc[0], pd[1], pd[0], pc[1]);
const detail::Expansion<T, 4> da = detail::ExpansionBase<T>::TwoTwoDiff(pd[0], pa[1], pa[0], pd[1]);
const detail::Expansion<T, 4> ac = detail::ExpansionBase<T>::TwoTwoDiff(pa[0], pc[1], pc[0], pa[1]);
const detail::Expansion<T, 4> bd = detail::ExpansionBase<T>::TwoTwoDiff(pb[0], pd[1], pd[0], pb[1]);
const detail::Expansion<T, 12> abc = ab + bc - ac;
const detail::Expansion<T, 12> bcd = bc + cd - bd;
const detail::Expansion<T, 12> cda = cd + da + ac;
const detail::Expansion<T, 12> dab = da + ab + bd;
const detail::Expansion<T, 24> adet = bcd * pa[2];
const detail::Expansion<T, 24> bdet = cda * -pb[2];
const detail::Expansion<T, 24> cdet = dab * pc[2];
const detail::Expansion<T, 24> ddet = abc * -pd[2];
const detail::Expansion<T, 96> deter = (adet + bdet) + (cdet + ddet);
return deter.mostSignificant();
}
//@brief : determine if the 3d point e is inside, on, or outside the sphere defined by a, b, c, and d
//@param pa: pointer to a as {x, y, z}
//@param pb: pointer to b as {x, y, z}
//@param pc: pointer to c as {x, y, z}
//@param pd: pointer to d as {x, y, z}
//@param pe: pointer to e as {x, y, z}
//@return : determinant of {{ax - ex, ay - ey, az - ez, (ax - ex)^2 + (ay - ey)^2 + (az - ez)^2}, {bx - ex, by - ey, bz - ez, (bx - ex)^2 + (by - ey)^2 + (bz - ez)^2}, {cx - ex, cy - ey, cz - ez, (cx - ex)^2 + (cy - ey)^2 + (cz - ez)^2}, {dx - ex, dy - ey, dz - ez, (dx - ex)^2 + (dy - ey)^2 + (dz - ez)^2}}
//@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c
template <typename T> T insphere(T const*const pa, T const*const pb, T const*const pc, T const*const pd, T const*const pe) {
const detail::Expansion<T, 4> ab = detail::ExpansionBase<T>::TwoTwoDiff(pa[0], pb[1], pb[0], pa[1]);
const detail::Expansion<T, 4> bc = detail::ExpansionBase<T>::TwoTwoDiff(pb[0], pc[1], pc[0], pb[1]);
const detail::Expansion<T, 4> cd = detail::ExpansionBase<T>::TwoTwoDiff(pc[0], pd[1], pd[0], pc[1]);
const detail::Expansion<T, 4> de = detail::ExpansionBase<T>::TwoTwoDiff(pd[0], pe[1], pe[0], pd[1]);
const detail::Expansion<T, 4> ea = detail::ExpansionBase<T>::TwoTwoDiff(pe[0], pa[1], pa[0], pe[1]);
const detail::Expansion<T, 4> ac = detail::ExpansionBase<T>::TwoTwoDiff(pa[0], pc[1], pc[0], pa[1]);
const detail::Expansion<T, 4> bd = detail::ExpansionBase<T>::TwoTwoDiff(pb[0], pd[1], pd[0], pb[1]);
const detail::Expansion<T, 4> ce = detail::ExpansionBase<T>::TwoTwoDiff(pc[0], pe[1], pe[0], pc[1]);
const detail::Expansion<T, 4> da = detail::ExpansionBase<T>::TwoTwoDiff(pd[0], pa[1], pa[0], pd[1]);
const detail::Expansion<T, 4> eb = detail::ExpansionBase<T>::TwoTwoDiff(pe[0], pb[1], pb[0], pe[1]);
const detail::Expansion<T, 24> abc = bc * pa[2] + ac * -pb[2] + ab * pc[2];
const detail::Expansion<T, 24> bcd = cd * pb[2] + bd * -pc[2] + bc * pd[2];
const detail::Expansion<T, 24> cde = de * pc[2] + ce * -pd[2] + cd * pe[2];
const detail::Expansion<T, 24> dea = ea * pd[2] + da * -pe[2] + de * pa[2];
const detail::Expansion<T, 24> eab = ab * pe[2] + eb * -pa[2] + ea * pb[2];
const detail::Expansion<T, 24> abd = bd * pa[2] + da * pb[2] + ab * pd[2];
const detail::Expansion<T, 24> bce = ce * pb[2] + eb * pc[2] + bc * pe[2];
const detail::Expansion<T, 24> cda = da * pc[2] + ac * pd[2] + cd * pa[2];
const detail::Expansion<T, 24> deb = eb * pd[2] + bd * pe[2] + de * pb[2];
const detail::Expansion<T, 24> eac = ac * pe[2] + ce * pa[2] + ea * pc[2];
const detail::Expansion<T, 96> bcde = (cde + bce) - (deb + bcd);
const detail::Expansion<T, 96> cdea = (dea + cda) - (eac + cde);
const detail::Expansion<T, 96> deab = (eab + deb) - (abd + dea);
const detail::Expansion<T, 96> eabc = (abc + eac) - (bce + eab);
const detail::Expansion<T, 96> abcd = (bcd + abd) - (cda + abc);
const detail::Expansion<T, 1152> adet = bcde * pa[0] * pa[0] + bcde * pa[1] * pa[1] + bcde * pa[2] * pa[2];
const detail::Expansion<T, 1152> bdet = cdea * pb[0] * pb[0] + cdea * pb[1] * pb[1] + cdea * pb[2] * pb[2];
const detail::Expansion<T, 1152> cdet = deab * pc[0] * pc[0] + deab * pc[1] * pc[1] + deab * pc[2] * pc[2];
const detail::Expansion<T, 1152> ddet = eabc * pd[0] * pd[0] + eabc * pd[1] * pd[1] + eabc * pd[2] * pd[2];
const detail::Expansion<T, 1152> edet = abcd * pe[0] * pe[0] + abcd * pe[1] * pe[1] + abcd * pe[2] * pe[2];
const detail::Expansion<T, 5760> deter = (adet + bdet) + ((cdet + ddet) + edet);
return deter.mostSignificant();
}
}
template <typename T>
const T& Epsilon()
{
static const T epsilon =
#ifdef PREDICATES_CXX11_IS_SUPPORTED
static_cast<T>(std::exp2(-std::numeric_limits<T>::digits));
#else
static_cast<T>(std::ldexp(T(1), -std::numeric_limits<T>::digits));
#endif
return epsilon;
}
template <typename T>
class Constants {
public:
static const T epsilon, resulterrbound;
static const T ccwerrboundA, ccwerrboundB, ccwerrboundC;
static const T o3derrboundA, o3derrboundB, o3derrboundC;
static const T iccerrboundA, iccerrboundB, iccerrboundC;
static const T isperrboundA, isperrboundB, isperrboundC;
};
template <typename T> const T Constants<T>::epsilon = Epsilon<T>();
template <typename T> const T Constants<T>::resulterrbound = (T( 3) + T( 8) * Epsilon<T>()) * Epsilon<T>();
template <typename T> const T Constants<T>::ccwerrboundA = (T( 3) + T( 16) * Epsilon<T>()) * Epsilon<T>();
template <typename T> const T Constants<T>::ccwerrboundB = (T( 2) + T( 12) * Epsilon<T>()) * Epsilon<T>();
template <typename T> const T Constants<T>::ccwerrboundC = (T( 9) + T( 64) * Epsilon<T>()) * Epsilon<T>() * Epsilon<T>();
template <typename T> const T Constants<T>::o3derrboundA = (T( 7) + T( 56) * Epsilon<T>()) * Epsilon<T>();
template <typename T> const T Constants<T>::o3derrboundB = (T( 3) + T( 28) * Epsilon<T>()) * Epsilon<T>();
template <typename T> const T Constants<T>::o3derrboundC = (T(26) + T( 288) * Epsilon<T>()) * Epsilon<T>() * Epsilon<T>();
template <typename T> const T Constants<T>::iccerrboundA = (T(10) + T( 96) * Epsilon<T>()) * Epsilon<T>();
template <typename T> const T Constants<T>::iccerrboundB = (T( 4) + T( 48) * Epsilon<T>()) * Epsilon<T>();
template <typename T> const T Constants<T>::iccerrboundC = (T(44) + T( 576) * Epsilon<T>()) * Epsilon<T>() * Epsilon<T>();
template <typename T> const T Constants<T>::isperrboundA = (T(16) + T( 224) * Epsilon<T>()) * Epsilon<T>();
template <typename T> const T Constants<T>::isperrboundB = (T( 5) + T( 72) * Epsilon<T>()) * Epsilon<T>();
template <typename T> const T Constants<T>::isperrboundC = (T(71) + T(1408) * Epsilon<T>()) * Epsilon<T>() * Epsilon<T>();
namespace adaptive {
template <typename T> T orient2d(T const ax, T const ay, T const bx, T const by, T const cx, T const cy) {
const T acx = ax - cx;
const T bcx = bx - cx;
const T acy = ay - cy;
const T bcy = by - cy;
const T detleft = acx * bcy;
const T detright = acy * bcx;
T det = detleft - detright;
if((detleft < 0) != (detright < 0)) return det;
if(T(0) == detleft || T(0) == detright) return det;
const T detsum = std::abs(detleft + detright);
T errbound = Constants<T>::ccwerrboundA * detsum;
if(std::abs(det) >= std::abs(errbound)) return det;
const detail::Expansion<T, 4> B = detail::ExpansionBase<T>::TwoTwoDiff(acx, bcy, acy, bcx);
det = B.estimate();
errbound = Constants<T>::ccwerrboundB * detsum;
if(std::abs(det) >= std::abs(errbound)) return det;
const T acxtail = detail::ExpansionBase<T>::MinusTail(ax, cx, acx);
const T bcxtail = detail::ExpansionBase<T>::MinusTail(bx, cx, bcx);
const T acytail = detail::ExpansionBase<T>::MinusTail(ay, cy, acy);
const T bcytail = detail::ExpansionBase<T>::MinusTail(by, cy, bcy);
if(T(0) == acxtail && T(0) == bcxtail && T(0) == acytail && T(0) == bcytail) return det;
errbound = Constants<T>::ccwerrboundC * detsum + Constants<T>::resulterrbound * std::abs(det);
det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail);
if(std::abs(det) >= std::abs(errbound)) return det;
const detail::Expansion<T, 16> D = ((B + detail::ExpansionBase<T>::TwoTwoDiff(acxtail, bcy, acytail, bcx)) + detail::ExpansionBase<T>::TwoTwoDiff(acx, bcytail, acy, bcxtail)) + detail::ExpansionBase<T>::TwoTwoDiff(acxtail, bcytail, acytail, bcxtail);
return D.mostSignificant();
}
template <typename T> T orient2d(T const*const pa, T const*const pb, T const*const pc) {
return orient2d(pa[0], pa[1], pb[0], pb[1], pc[0], pc[1]);
}
template <typename T> T incircle(T const ax, T const ay, T const bx, T const by, T const cx, T const cy, T const dx, T const dy) {
const T adx = ax - dx;
const T bdx = bx - dx;
const T cdx = cx - dx;
const T ady = ay - dy;
const T bdy = by - dy;
const T cdy = cy - dy;
const T bdxcdy = bdx * cdy;
const T cdxbdy = cdx * bdy;
const T cdxady = cdx * ady;
const T adxcdy = adx * cdy;
const T adxbdy = adx * bdy;
const T bdxady = bdx * ady;
const T alift = adx * adx + ady * ady;
const T blift = bdx * bdx + bdy * bdy;
const T clift = cdx * cdx + cdy * cdy;
T det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady);
const T permanent = (std::abs(bdxcdy) + std::abs(cdxbdy)) * alift
+ (std::abs(cdxady) + std::abs(adxcdy)) * blift
+ (std::abs(adxbdy) + std::abs(bdxady)) * clift;
T errbound = Constants<T>::iccerrboundA * permanent;
if(std::abs(det) >= std::abs(errbound)) return det;
const detail::Expansion<T, 4> bc = detail::ExpansionBase<T>::TwoTwoDiff(bdx, cdy, cdx, bdy);
const detail::Expansion<T, 4> ca = detail::ExpansionBase<T>::TwoTwoDiff(cdx, ady, adx, cdy);
const detail::Expansion<T, 4> ab = detail::ExpansionBase<T>::TwoTwoDiff(adx, bdy, bdx, ady);
const detail::Expansion<T, 32> adet = bc * adx * adx + bc * ady * ady;
const detail::Expansion<T, 32> bdet = ca * bdx * bdx + ca * bdy * bdy;
const detail::Expansion<T, 32> cdet = ab * cdx * cdx + ab * cdy * cdy;
const detail::Expansion<T, 96> fin1 = adet + bdet + cdet;
det = fin1.estimate();
errbound = Constants<T>::iccerrboundB * permanent;
if(std::abs(det) >= std::abs(errbound)) return det;
const T adxtail = detail::ExpansionBase<T>::MinusTail(ax, dx, adx);
const T adytail = detail::ExpansionBase<T>::MinusTail(ay, dy, ady);
const T bdxtail = detail::ExpansionBase<T>::MinusTail(bx, dx, bdx);
const T bdytail = detail::ExpansionBase<T>::MinusTail(by, dy, bdy);
const T cdxtail = detail::ExpansionBase<T>::MinusTail(cx, dx, cdx);
const T cdytail = detail::ExpansionBase<T>::MinusTail(cy, dy, cdy);
if(T(0) == adxtail && T(0) == bdxtail && T(0) == cdxtail && T(0) == adytail && T(0) == bdytail && T(0) == cdytail) return det;
errbound = Constants<T>::iccerrboundC * permanent + Constants<T>::resulterrbound * std::abs(det);
det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail))
+ (bdx * cdy - bdy * cdx) * (adx * adxtail + ady * adytail) * T(2))
+ ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail))
+ (cdx * ady - cdy * adx) * (bdx * bdxtail + bdy * bdytail) * T(2))
+ ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail))
+ (adx * bdy - ady * bdx) * (cdx * cdxtail + cdy * cdytail) * T(2));
if(std::abs(det) >= std::abs(errbound)) return det;
return exact::incircle(ax, ay, bx, by, cx, cy, dx, dy);
}
template <typename T> T incircle(T const*const pa, T const*const pb, T const*const pc, T const*const pd) {
return incircle(pa[0], pa[1], pb[0], pb[1], pc[0], pc[1], pd[0], pd[1]);
}
//@brief : determine if the 3d point d is above, on, or below the plane defined by a, b, and c
//@param pa: pointer to a as {x, y, z}
//@param pb: pointer to b as {x, y, z}
//@param pc: pointer to c as {x, y, z}
//@param pd: pointer to d as {x, y, z}
//@return : determinant of {{ax - dx, ay - dy, az - dz}, {bx - dx, by - dy, bz - dz}, {cx - dx, cy - dy, cz - dz}}
//@note : positive, 0, negative result for c above, on, or below the plane defined by a, b, and c
template <typename T> T orient3d(T const*const pa, T const*const pb, T const*const pc, T const*const pd) {
const T adx = pa[0] - pd[0];
const T bdx = pb[0] - pd[0];
const T cdx = pc[0] - pd[0];
const T ady = pa[1] - pd[1];
const T bdy = pb[1] - pd[1];
const T cdy = pc[1] - pd[1];
const T adz = pa[2] - pd[2];
const T bdz = pb[2] - pd[2];
const T cdz = pc[2] - pd[2];
const T bdxcdy = bdx * cdy;
const T cdxbdy = cdx * bdy;
const T cdxady = cdx * ady;
const T adxcdy = adx * cdy;
const T adxbdy = adx * bdy;
const T bdxady = bdx * ady;
T det = adz * (bdxcdy - cdxbdy) + bdz * (cdxady - adxcdy) + cdz * (adxbdy - bdxady);
const T permanent = (std::abs(bdxcdy) + std::abs(cdxbdy)) * std::abs(adz) + (std::abs(cdxady) + std::abs(adxcdy)) * std::abs(bdz) + (std::abs(adxbdy) + std::abs(bdxady)) * std::abs(cdz);
T errbound = Constants<T>::o3derrboundA * permanent;
if(std::abs(det) >= std::abs(errbound)) return det;
const detail::Expansion<T, 4> bc = detail::ExpansionBase<T>::TwoTwoDiff(bdx, cdy, cdx, bdy);
const detail::Expansion<T, 4> ca = detail::ExpansionBase<T>::TwoTwoDiff(cdx, ady, adx, cdy);
const detail::Expansion<T, 4> ab = detail::ExpansionBase<T>::TwoTwoDiff(adx, bdy, bdx, ady);
const detail::Expansion<T, 24> fin1 = (bc * adz + ca * bdz) + ab * cdz;
det = fin1.estimate();
errbound = Constants<T>::o3derrboundB * permanent;
if(std::abs(det) >= std::abs(errbound)) return det;
const T adxtail = detail::ExpansionBase<T>::MinusTail(pa[0], pd[0], adx);
const T bdxtail = detail::ExpansionBase<T>::MinusTail(pb[0], pd[0], bdx);
const T cdxtail = detail::ExpansionBase<T>::MinusTail(pc[0], pd[0], cdx);
const T adytail = detail::ExpansionBase<T>::MinusTail(pa[1], pd[1], ady);
const T bdytail = detail::ExpansionBase<T>::MinusTail(pb[1], pd[1], bdy);
const T cdytail = detail::ExpansionBase<T>::MinusTail(pc[1], pd[1], cdy);
const T adztail = detail::ExpansionBase<T>::MinusTail(pa[2], pd[2], adz);
const T bdztail = detail::ExpansionBase<T>::MinusTail(pb[2], pd[2], bdz);
const T cdztail = detail::ExpansionBase<T>::MinusTail(pc[2], pd[2], cdz);
if(T(0) == adxtail && T(0) == adytail && T(0) == adztail &&
T(0) == bdxtail && T(0) == bdytail && T(0) == bdztail &&
T(0) == cdxtail && T(0) == cdytail && T(0) == cdztail) return det;
errbound = Constants<T>::o3derrboundC * permanent + Constants<T>::resulterrbound * std::abs(det);
det += (adz * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail)) + adztail * (bdx * cdy - bdy * cdx))
+ (bdz * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail)) + bdztail * (cdx * ady - cdy * adx))
+ (cdz * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail)) + cdztail * (adx * bdy - ady * bdx));
if(std::abs(det) >= std::abs(errbound)) return det;
const detail::Expansion<T, 8> bct = detail::ExpansionBase<T>::TwoTwoDiffZeroCheck(bdxtail, cdy, bdytail, cdx) + detail::ExpansionBase<T>::TwoTwoDiffZeroCheck(cdytail, bdx, cdxtail, bdy);
const detail::Expansion<T, 8> cat = detail::ExpansionBase<T>::TwoTwoDiffZeroCheck(cdxtail, ady, cdytail, adx) + detail::ExpansionBase<T>::TwoTwoDiffZeroCheck(adytail, cdx, adxtail, cdy);
const detail::Expansion<T, 8> abt = detail::ExpansionBase<T>::TwoTwoDiffZeroCheck(adxtail, bdy, adytail, bdx) + detail::ExpansionBase<T>::TwoTwoDiffZeroCheck(bdytail, adx, bdxtail, ady);
const detail::Expansion<T, 192> fin2 = fin1 + bct * adz + cat * bdz + abt * cdz + bc * adztail + ca * bdztail + ab * cdztail
+ detail::ExpansionBase<T>::ThreeProd( adxtail, bdytail, cdz) + detail::ExpansionBase<T>::ThreeProd( adxtail, bdytail, cdztail)
+ detail::ExpansionBase<T>::ThreeProd(-adxtail, cdytail, bdz) + detail::ExpansionBase<T>::ThreeProd(-adxtail, cdytail, bdztail)
+ detail::ExpansionBase<T>::ThreeProd( bdxtail, cdytail, adz) + detail::ExpansionBase<T>::ThreeProd( bdxtail, cdytail, adztail)
+ detail::ExpansionBase<T>::ThreeProd(-bdxtail, adytail, cdz) + detail::ExpansionBase<T>::ThreeProd(-bdxtail, adytail, cdztail)
+ detail::ExpansionBase<T>::ThreeProd( cdxtail, adytail, bdz) + detail::ExpansionBase<T>::ThreeProd( cdxtail, adytail, bdztail)
+ detail::ExpansionBase<T>::ThreeProd(-cdxtail, bdytail, adz) + detail::ExpansionBase<T>::ThreeProd(-cdxtail, bdytail, adztail)
+ bct * adztail + cat * bdztail + abt * cdztail;
return fin2.mostSignificant();
}
//@brief : determine if the 3d point e is inside, on, or outside the sphere defined by a, b, c, and d
//@param pa: pointer to a as {x, y, z}
//@param pb: pointer to b as {x, y, z}
//@param pc: pointer to c as {x, y, z}
//@param pd: pointer to d as {x, y, z}
//@param pe: pointer to e as {x, y, z}
//@return : determinant of {{ax - ex, ay - ey, az - ez, (ax - ex)^2 + (ay - ey)^2 + (az - ez)^2}, {bx - ex, by - ey, bz - ez, (bx - ex)^2 + (by - ey)^2 + (bz - ez)^2}, {cx - ex, cy - ey, cz - ez, (cx - ex)^2 + (cy - ey)^2 + (cz - ez)^2}, {dx - ex, dy - ey, dz - ez, (dx - ex)^2 + (dy - ey)^2 + (dz - ez)^2}}
//@note : positive, 0, negative result for d inside, on, or outside the circle defined by a, b, and c
template <typename T> T insphere(T const*const pa, T const*const pb, T const*const pc, T const*const pd, T const*const pe) {
T permanent;
const T aex = pa[0] - pe[0];
const T bex = pb[0] - pe[0];
const T cex = pc[0] - pe[0];
const T dex = pd[0] - pe[0];
const T aey = pa[1] - pe[1];
const T bey = pb[1] - pe[1];
const T cey = pc[1] - pe[1];
const T dey = pd[1] - pe[1];
const T aez = pa[2] - pe[2];
const T bez = pb[2] - pe[2];
const T cez = pc[2] - pe[2];
const T dez = pd[2] - pe[2];
{
const T aexbey = aex * bey;
const T bexaey = bex * aey;
const T bexcey = bex * cey;
const T cexbey = cex * bey;
const T cexdey = cex * dey;
const T dexcey = dex * cey;
const T dexaey = dex * aey;
const T aexdey = aex * dey;
const T aexcey = aex * cey;
const T cexaey = cex * aey;
const T bexdey = bex * dey;
const T dexbey = dex * bey;
const T ab = aexbey - bexaey;
const T bc = bexcey - cexbey;
const T cd = cexdey - dexcey;
const T da = dexaey - aexdey;
const T ac = aexcey - cexaey;
const T bd = bexdey - dexbey;
const T abc = aez * bc - bez * ac + cez * ab;
const T bcd = bez * cd - cez * bd + dez * bc;
const T cda = cez * da + dez * ac + aez * cd;
const T dab = dez * ab + aez * bd + bez * da;
const T alift = aex * aex + aey * aey + aez * aez;
const T blift = bex * bex + bey * bey + bez * bez;
const T clift = cex * cex + cey * cey + cez * cez;
const T dlift = dex * dex + dey * dey + dez * dez;
const T det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd);
const T aezplus = std::abs(aez);
const T bezplus = std::abs(bez);
const T cezplus = std::abs(cez);
const T dezplus = std::abs(dez);
const T aexbeyplus = std::abs(aexbey);
const T bexaeyplus = std::abs(bexaey);
const T bexceyplus = std::abs(bexcey);
const T cexbeyplus = std::abs(cexbey);
const T cexdeyplus = std::abs(cexdey);
const T dexceyplus = std::abs(dexcey);
const T dexaeyplus = std::abs(dexaey);
const T aexdeyplus = std::abs(aexdey);
const T aexceyplus = std::abs(aexcey);
const T cexaeyplus = std::abs(cexaey);
const T bexdeyplus = std::abs(bexdey);
const T dexbeyplus = std::abs(dexbey);
permanent = ((cexdeyplus + dexceyplus) * bezplus + (dexbeyplus + bexdeyplus) * cezplus + (bexceyplus + cexbeyplus) * dezplus) * alift
+ ((dexaeyplus + aexdeyplus) * cezplus + (aexceyplus + cexaeyplus) * dezplus + (cexdeyplus + dexceyplus) * aezplus) * blift
+ ((aexbeyplus + bexaeyplus) * dezplus + (bexdeyplus + dexbeyplus) * aezplus + (dexaeyplus + aexdeyplus) * bezplus) * clift
+ ((bexceyplus + cexbeyplus) * aezplus + (cexaeyplus + aexceyplus) * bezplus + (aexbeyplus + bexaeyplus) * cezplus) * dlift;
const T errbound = Constants<T>::isperrboundA * permanent;
if(std::abs(det) >= std::abs(errbound)) return det;
}
const detail::Expansion<T, 4> ab = detail::ExpansionBase<T>::TwoTwoDiff(aex, bey, bex, aey);
const detail::Expansion<T, 4> bc = detail::ExpansionBase<T>::TwoTwoDiff(bex, cey, cex, bey);
const detail::Expansion<T, 4> cd = detail::ExpansionBase<T>::TwoTwoDiff(cex, dey, dex, cey);
const detail::Expansion<T, 4> da = detail::ExpansionBase<T>::TwoTwoDiff(dex, aey, aex, dey);
const detail::Expansion<T, 4> ac = detail::ExpansionBase<T>::TwoTwoDiff(aex, cey, cex, aey);
const detail::Expansion<T, 4> bd = detail::ExpansionBase<T>::TwoTwoDiff(bex, dey, dex, bey);
const detail::Expansion<T, 24> temp24a = bc * dez + (cd * bez + bd * -cez);
const detail::Expansion<T, 24> temp24b = cd * aez + (da * cez + ac * dez);
const detail::Expansion<T, 24> temp24c = da * bez + (ab * dez + bd * aez);
const detail::Expansion<T, 24> temp24d = ab * cez + (bc * aez + ac * -bez);
const detail::Expansion<T, 288> adet = temp24a * aex * -aex + temp24a * aey * -aey + temp24a * aez * -aez;
const detail::Expansion<T, 288> bdet = temp24b * bex * bex + temp24b * bey * bey + temp24b * bez * bez;
const detail::Expansion<T, 288> cdet = temp24c * cex * -cex + temp24c * cey * -cey + temp24c * cez * -cez;
const detail::Expansion<T, 288> ddet = temp24d * dex * dex + temp24d * dey * dey + temp24d * dez * dez;
const detail::Expansion<T, 1152> fin1 = (adet + bdet) + (cdet + ddet);
T det = fin1.estimate();
T errbound = Constants<T>::isperrboundB * permanent;
if(std::abs(det) >= std::abs(errbound)) return det;
const T aextail = detail::ExpansionBase<T>::MinusTail(pa[0], pe[0], aex);
const T aeytail = detail::ExpansionBase<T>::MinusTail(pa[1], pe[1], aey);
const T aeztail = detail::ExpansionBase<T>::MinusTail(pa[2], pe[2], aez);
const T bextail = detail::ExpansionBase<T>::MinusTail(pb[0], pe[0], bex);
const T beytail = detail::ExpansionBase<T>::MinusTail(pb[1], pe[1], bey);
const T beztail = detail::ExpansionBase<T>::MinusTail(pb[2], pe[2], bez);
const T cextail = detail::ExpansionBase<T>::MinusTail(pc[0], pe[0], cex);
const T ceytail = detail::ExpansionBase<T>::MinusTail(pc[1], pe[1], cey);
const T ceztail = detail::ExpansionBase<T>::MinusTail(pc[2], pe[2], cez);
const T dextail = detail::ExpansionBase<T>::MinusTail(pd[0], pe[0], dex);
const T deytail = detail::ExpansionBase<T>::MinusTail(pd[1], pe[1], dey);
const T deztail = detail::ExpansionBase<T>::MinusTail(pd[2], pe[2], dez);
if (T(0) == aextail && T(0) == aeytail && T(0) == aeztail &&
T(0) == bextail && T(0) == beytail && T(0) == beztail &&
T(0) == cextail && T(0) == ceytail && T(0) == ceztail &&
T(0) == dextail && T(0) == deytail && T(0) == deztail) return det;
errbound = Constants<T>::isperrboundC * permanent + Constants<T>::resulterrbound * std::abs(det);
const T abeps = (aex * beytail + bey * aextail) - (aey * bextail + bex * aeytail);
const T bceps = (bex * ceytail + cey * bextail) - (bey * cextail + cex * beytail);
const T cdeps = (cex * deytail + dey * cextail) - (cey * dextail + dex * ceytail);
const T daeps = (dex * aeytail + aey * dextail) - (dey * aextail + aex * deytail);
const T aceps = (aex * ceytail + cey * aextail) - (aey * cextail + cex * aeytail);
const T bdeps = (bex * deytail + dey * bextail) - (bey * dextail + dex * beytail);
const T ab3 = ab.mostSignificant();
const T bc3 = bc.mostSignificant();
const T cd3 = cd.mostSignificant();
const T da3 = da.mostSignificant();
const T ac3 = ac.mostSignificant();
const T bd3 = bd.mostSignificant();
det += ( ( (bex * bex + bey * bey + bez * bez) * ((cez * daeps + dez * aceps + aez * cdeps) + (ceztail * da3 + deztail * ac3 + aeztail * cd3))
+ (dex * dex + dey * dey + dez * dez) * ((aez * bceps - bez * aceps + cez * abeps) + (aeztail * bc3 - beztail * ac3 + ceztail * ab3)) )
- ( (aex * aex + aey * aey + aez * aez) * ((bez * cdeps - cez * bdeps + dez * bceps) + (beztail * cd3 - ceztail * bd3 + deztail * bc3))
+ (cex * cex + cey * cey + cez * cez) * ((dez * abeps + aez * bdeps + bez * daeps) + (deztail * ab3 + aeztail * bd3 + beztail * da3)) ) )
+ T(2) * ( ( (bex * bextail + bey * beytail + bez * beztail) * (cez * da3 + dez * ac3 + aez * cd3)
+ (dex * dextail + dey * deytail + dez * deztail) * (aez * bc3 - bez * ac3 + cez * ab3))
- ( (aex * aextail + aey * aeytail + aez * aeztail) * (bez * cd3 - cez * bd3 + dez * bc3)
+ (cex * cextail + cey * ceytail + cez * ceztail) * (dez * ab3 + aez * bd3 + bez * da3)));
if(std::abs(det) >= std::abs(errbound)) return det;
return exact::insphere(pa, pb, pc, pd, pe);
}
}
}
#endif

View file

@ -0,0 +1,55 @@
#ifndef REMOVE_AT_HPP
#define REMOVE_AT_HPP
// check if c++11 is supported
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
#define REMOVE_AT_CXX11_IS_SUPPORTED
#elif !defined(__cplusplus) && !defined(_MSC_VER)
typedef char couldnt_parse_cxx_standard[-1];
#endif
#include <algorithm>
#include <iterator>
/*!
* Remove elements in the range [first; last) with indices from the sorted
* unique range [ii_first, ii_last)
*/
template <class ForwardIt, class SortUniqIndsFwdIt>
inline ForwardIt remove_at(
ForwardIt first,
ForwardIt last,
SortUniqIndsFwdIt ii_first,
SortUniqIndsFwdIt ii_last)
{
if(ii_first == ii_last) // no indices-to-remove are given
return last;
typedef typename std::iterator_traits<ForwardIt>::difference_type diff_t;
typedef typename std::iterator_traits<SortUniqIndsFwdIt>::value_type ind_t;
ForwardIt destination = first + static_cast<diff_t>(*ii_first);
while(ii_first != ii_last)
{
// advance to an index after a chunk of elements-to-keep
for(ind_t cur = *ii_first++; ii_first != ii_last; ++ii_first)
{
const ind_t nxt = *ii_first;
if(nxt - cur > 1)
break;
cur = nxt;
}
// move the chunk of elements-to-keep to new destination
const ForwardIt source_first =
first + static_cast<diff_t>(*(ii_first - 1)) + 1;
const ForwardIt source_last =
ii_first != ii_last ? first + static_cast<diff_t>(*ii_first) : last;
#ifdef REMOVE_AT_CXX11_IS_SUPPORTED
std::move(source_first, source_last, destination);
#else
std::copy(source_first, source_last, destination); // c++98 version
#endif
destination += source_last - source_first;
}
return destination;
}
#endif // REMOVE_AT_HPP

80
include/CDT/src/CDT.cpp Normal file
View file

@ -0,0 +1,80 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
/**
* @file
* Explicit template instantiations for `float` and `double` coordinate types.
*
* Explicit instantiations are used when consuming as a compiled library.
* In almost all of the cases 'float' and 'double' are sufficient.
* Feel free to extend this with custom data types if needed.
*/
#ifdef CDT_USE_AS_COMPILED_LIBRARY
#include "CDT.hpp"
#include "CDTUtils.hpp"
#include "InitializeWithGrid.h"
#include "Triangulation.hpp"
#include "VerifyTopology.h"
namespace CDT
{
template struct CDT_EXPORT V2d<float>;
template struct CDT_EXPORT V2d<double>;
template struct CDT_EXPORT Box2d<float>;
template struct CDT_EXPORT Box2d<double>;
template class CDT_EXPORT Triangulation<float>;
template class CDT_EXPORT Triangulation<double>;
template CDT_EXPORT DuplicatesInfo
RemoveDuplicates<float>(std::vector<V2d<float> >&);
template CDT_EXPORT DuplicatesInfo
RemoveDuplicates<double>(std::vector<V2d<double> >&);
template CDT_EXPORT DuplicatesInfo RemoveDuplicatesAndRemapEdges<float>(
std::vector<V2d<float> >&,
std::vector<Edge>&);
template CDT_EXPORT DuplicatesInfo RemoveDuplicatesAndRemapEdges<double>(
std::vector<V2d<double> >&,
std::vector<Edge>&);
template CDT_EXPORT bool
verifyTopology<float>(const CDT::Triangulation<float>&);
template CDT_EXPORT bool
verifyTopology<double>(const CDT::Triangulation<double>&);
template CDT_EXPORT void initializeWithRegularGrid<float>(
float,
float,
float,
float,
std::size_t,
std::size_t,
Triangulation<float>&);
template CDT_EXPORT void initializeWithRegularGrid<double>(
double,
double,
double,
double,
std::size_t,
std::size_t,
Triangulation<double>&);
template
CDT_EXPORT float distance(const V2d<float>& a, const V2d<float>& b);
template
CDT_EXPORT double distance(const V2d<double>& a, const V2d<double>& b);
template
CDT_EXPORT float distanceSquared(const V2d<float>& a, const V2d<float>& b);
template
CDT_EXPORT double distanceSquared(const V2d<double>& a, const V2d<double>& b);
} // namespace CDT
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,12 @@
5
0 1 3 4294967295 3 1
0 3 2 0 4 4294967295
1 2 4 4294967295 4 3
1 4 3 2 4 0
2 3 4 1 3 2
0
0
0

View file

@ -0,0 +1,25 @@
17
0 1 4 4294967295 4 1
0 4 2 0 6 4294967295
1 2 3 4294967295 7 3
1 3 9 2 8 5
1 7 4 5 14 0
1 9 7 3 14 4
2 4 6 1 13 7
2 6 3 6 10 2
3 4 9 9 14 3
3 5 4 12 13 8
3 6 8 7 15 11
3 8 10 10 16 12
3 10 5 11 16 9
4 5 6 9 15 6
4 7 9 4 5 8
5 8 6 16 10 13
5 10 8 12 11 15
1
3 4
0
0

View file

@ -0,0 +1,27 @@
19
0 1 4 4294967295 6 2
0 3 2 3 7 4294967295
0 4 11 0 13 4
0 9 3 4 11 1
0 11 9 2 17 3
1 2 10 4294967295 7 6
1 10 4 5 14 0
2 3 10 1 8 5
3 5 10 10 14 7
3 6 11 11 17 12
3 8 5 12 16 8
3 9 6 3 17 9
3 11 8 9 18 10
4 5 11 14 15 2
4 10 5 6 8 13
5 7 11 16 18 13
5 8 7 10 18 15
6 9 11 11 4 9
7 8 11 16 12 15
1
3 11
0
0

View file

@ -0,0 +1,95 @@
59
0 1 31 4294967295 8 3
0 3 7 3 13 2
0 7 2 1 9 4294967295
0 31 3 0 14 1
1 2 12 4294967295 10 5
1 12 13 4 38 6
1 13 14 5 40 7
1 14 27 6 43 8
1 27 31 7 57 0
2 7 8 2 25 10
2 8 12 9 26 4
3 4 5 14 15 12
3 5 6 11 18 13
3 6 7 12 23 1
3 31 4 3 17 11
4 24 5 16 19 11
4 25 24 17 55 15
4 31 25 14 57 16
5 23 6 19 22 12
5 24 23 15 55 18
6 21 28 21 50 23
6 22 21 22 52 20
6 23 22 18 53 21
6 28 7 20 24 13
7 28 30 23 58 25
7 30 8 24 28 9
8 9 12 27 30 10
8 29 9 28 35 26
8 30 29 25 58 27
9 10 11 31 36 30
9 11 12 29 38 26
9 17 10 32 37 29
9 18 17 33 48 31
9 19 18 34 45 32
9 20 19 35 46 33
9 29 20 27 51 34
10 16 11 37 39 29
10 17 16 31 48 36
11 13 12 39 5 30
11 16 13 36 40 38
13 16 14 39 42 6
14 15 26 42 47 43
14 16 15 40 44 41
14 26 27 41 56 7
15 16 18 42 48 45
15 18 19 44 33 46
15 19 20 45 34 47
15 20 26 46 49 41
16 17 18 37 32 44
20 21 26 50 52 47
20 28 21 51 20 49
20 29 28 35 58 50
21 22 26 21 54 49
22 23 25 22 55 54
22 25 26 53 56 52
23 24 25 19 16 53
25 27 26 57 43 54
25 31 27 17 8 56
28 29 30 51 28 24
29
3 4
3 31
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 25
25 26
26 27
27 31
28 29
28 30
29 30
0
0

View file

@ -0,0 +1,65 @@
29
0 28 1 4294967295 3 4294967295
1 21 2 2 5 4294967295
1 22 21 3 4294967295 1
1 28 22 0 28 2
2 20 3 5 8 4294967295
2 21 20 1 4294967295 4
3 18 25 7 25 9
3 19 18 8 4294967295 6
3 20 19 4 4294967295 7
3 25 4 6 10 4294967295
4 25 27 9 4294967295 11
4 27 5 10 13 4294967295
5 26 6 13 18 4294967295
5 27 26 11 4294967295 12
6 14 7 15 20 4294967295
6 15 14 16 4294967295 14
6 16 15 17 4294967295 15
6 17 16 18 4294967295 16
6 26 17 12 26 17
7 13 8 20 22 4294967295
7 14 13 14 4294967295 19
8 10 9 22 4294967295 4294967295
8 13 10 19 23 21
10 13 11 22 24 4294967295
11 13 12 23 4294967295 4294967295
17 25 18 26 6 4294967295
17 26 25 18 4294967295 25
22 24 23 28 4294967295 4294967295
22 28 24 3 4294967295 27
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,66 @@
30
0 28 1 4294967295 3 4294967295
1 21 2 2 5 4294967295
1 22 21 3 4294967295 1
1 28 22 0 28 2
2 20 3 5 8 4294967295
2 21 20 1 4294967295 4
3 18 25 7 25 9
3 19 18 8 4294967295 6
3 20 19 4 4294967295 7
3 25 4 6 10 4294967295
4 25 27 9 29 11
4 27 5 10 13 4294967295
5 26 6 13 18 4294967295
5 27 26 11 29 12
6 14 7 15 20 4294967295
6 15 14 16 4294967295 14
6 16 15 17 4294967295 15
6 17 16 18 4294967295 16
6 26 17 12 26 17
7 13 8 20 22 4294967295
7 14 13 14 4294967295 19
8 10 9 22 4294967295 4294967295
8 13 10 19 23 21
10 13 11 22 24 4294967295
11 13 12 23 4294967295 4294967295
17 25 18 26 6 4294967295
17 26 25 18 29 25
22 24 23 28 4294967295 4294967295
22 28 24 3 4294967295 27
25 26 27 26 13 10
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,84 @@
48
0 1 2 3 4 1
0 2 3 0 7 2
0 3 4 1 12 4294967295
0 28 1 4294967295 6 0
1 21 2 5 8 0
1 22 21 6 44 4
1 28 22 3 46 5
2 20 3 8 11 1
2 21 20 4 44 7
3 18 25 10 39 12
3 19 18 11 41 9
3 20 19 7 42 10
3 25 4 9 13 2
4 25 27 12 47 14
4 27 5 13 17 4294967295
5 6 9 16 19 4294967295
5 26 6 17 24 15
5 27 26 14 47 16
6 7 8 20 25 19
6 8 9 18 27 15
6 14 7 21 26 18
6 15 14 22 37 20
6 16 15 23 34 21
6 17 16 24 35 22
6 26 17 16 40 23
7 13 8 26 28 18
7 14 13 20 37 25
8 10 9 28 4294967295 19
8 13 10 25 29 27
10 13 11 28 31 4294967295
11 12 23 31 36 32
11 13 12 29 33 30
11 23 24 30 45 4294967295
12 13 15 31 37 34
12 15 16 33 22 35
12 16 17 34 23 36
12 17 23 35 38 30
13 14 15 26 21 33
17 18 23 39 41 36
17 25 18 40 9 38
17 26 25 24 47 39
18 19 23 10 43 38
19 20 22 11 44 43
19 22 23 42 45 41
20 21 22 8 5 42
22 24 23 46 32 43
22 28 24 6 4294967295 45
25 26 27 40 17 13
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,95 @@
59
0 1 31 4294967295 8 3
0 3 7 3 13 2
0 7 2 1 9 4294967295
0 31 3 0 14 1
1 2 12 4294967295 10 5
1 12 13 4 38 6
1 13 14 5 40 7
1 14 27 6 43 8
1 27 31 7 57 0
2 7 8 2 25 10
2 8 12 9 26 4
3 4 5 14 15 12
3 5 6 11 18 13
3 6 7 12 23 1
3 31 4 3 17 11
4 24 5 16 19 11
4 25 24 17 55 15
4 31 25 14 57 16
5 23 6 19 22 12
5 24 23 15 55 18
6 21 28 21 50 23
6 22 21 22 52 20
6 23 22 18 53 21
6 28 7 20 24 13
7 28 30 23 58 25
7 30 8 24 28 9
8 9 12 27 30 10
8 29 9 28 35 26
8 30 29 25 58 27
9 10 11 31 36 30
9 11 12 29 38 26
9 17 10 32 37 29
9 18 17 33 48 31
9 19 18 34 45 32
9 20 19 35 46 33
9 29 20 27 51 34
10 16 11 37 39 29
10 17 16 31 48 36
11 13 12 39 5 30
11 16 13 36 40 38
13 16 14 39 42 6
14 15 26 42 47 43
14 16 15 40 44 41
14 26 27 41 56 7
15 16 18 42 48 45
15 18 19 44 33 46
15 19 20 45 34 47
15 20 26 46 49 41
16 17 18 37 32 44
20 21 26 50 52 47
20 28 21 51 20 49
20 29 28 35 58 50
21 22 26 21 54 49
22 23 25 22 55 54
22 25 26 53 56 52
23 24 25 19 16 53
25 27 26 57 43 54
25 31 27 17 8 56
28 29 30 51 28 24
29
3 4
3 31
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 25
25 26
26 27
27 31
28 29
28 30
29 30
0
0

View file

@ -0,0 +1,65 @@
29
0 28 1 4294967295 3 4294967295
1 21 2 2 5 4294967295
1 22 21 3 4294967295 1
1 28 22 0 28 2
2 20 3 5 8 4294967295
2 21 20 1 4294967295 4
3 18 25 7 25 9
3 19 18 8 4294967295 6
3 20 19 4 4294967295 7
3 25 4 6 10 4294967295
4 25 27 9 4294967295 11
4 27 5 10 13 4294967295
5 26 6 13 18 4294967295
5 27 26 11 4294967295 12
6 14 7 15 20 4294967295
6 15 14 16 4294967295 14
6 16 15 17 4294967295 15
6 17 16 18 4294967295 16
6 26 17 12 26 17
7 13 8 20 22 4294967295
7 14 13 14 4294967295 19
8 10 9 22 4294967295 4294967295
8 13 10 19 23 21
10 13 11 22 24 4294967295
11 13 12 23 4294967295 4294967295
17 25 18 26 6 4294967295
17 26 25 18 4294967295 25
22 24 23 28 4294967295 4294967295
22 28 24 3 4294967295 27
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,66 @@
30
0 28 1 4294967295 3 4294967295
1 21 2 2 5 4294967295
1 22 21 3 4294967295 1
1 28 22 0 28 2
2 20 3 5 8 4294967295
2 21 20 1 4294967295 4
3 18 25 7 25 9
3 19 18 8 4294967295 6
3 20 19 4 4294967295 7
3 25 4 6 10 4294967295
4 25 27 9 29 11
4 27 5 10 13 4294967295
5 26 6 13 18 4294967295
5 27 26 11 29 12
6 14 7 15 20 4294967295
6 15 14 16 4294967295 14
6 16 15 17 4294967295 15
6 17 16 18 4294967295 16
6 26 17 12 26 17
7 13 8 20 22 4294967295
7 14 13 14 4294967295 19
8 10 9 22 4294967295 4294967295
8 13 10 19 23 21
10 13 11 22 24 4294967295
11 13 12 23 4294967295 4294967295
17 25 18 26 6 4294967295
17 26 25 18 29 25
22 24 23 28 4294967295 4294967295
22 28 24 3 4294967295 27
25 26 27 26 13 10
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,84 @@
48
0 1 2 3 4 1
0 2 3 0 7 2
0 3 4 1 12 4294967295
0 28 1 4294967295 6 0
1 21 2 5 8 0
1 22 21 6 44 4
1 28 22 3 46 5
2 20 3 8 11 1
2 21 20 4 44 7
3 18 25 10 39 12
3 19 18 11 41 9
3 20 19 7 42 10
3 25 4 9 13 2
4 25 27 12 47 14
4 27 5 13 17 4294967295
5 6 9 16 19 4294967295
5 26 6 17 24 15
5 27 26 14 47 16
6 7 8 20 25 19
6 8 9 18 27 15
6 14 7 21 26 18
6 15 14 22 37 20
6 16 15 23 34 21
6 17 16 24 35 22
6 26 17 16 40 23
7 13 8 26 28 18
7 14 13 20 37 25
8 10 9 28 4294967295 19
8 13 10 25 29 27
10 13 11 28 31 4294967295
11 12 23 31 36 32
11 13 12 29 33 30
11 23 24 30 45 4294967295
12 13 15 31 37 34
12 15 16 33 22 35
12 16 17 34 23 36
12 17 23 35 38 30
13 14 15 26 21 33
17 18 23 39 41 36
17 25 18 40 9 38
17 26 25 24 47 39
18 19 23 10 43 38
19 20 22 11 44 43
19 22 23 42 45 41
20 21 22 8 5 42
22 24 23 46 32 43
22 28 24 6 4294967295 45
25 26 27 40 17 13
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,95 @@
59
0 1 13 4294967295 7 2
0 3 2 5 8 4294967295
0 13 14 0 40 3
0 14 27 2 43 4
0 27 31 3 57 5
0 31 3 4 14 1
1 2 12 4294967295 10 7
1 12 13 6 38 0
2 3 7 1 13 9
2 7 8 8 25 10
2 8 12 9 26 6
3 4 5 14 15 12
3 5 6 11 18 13
3 6 7 12 23 8
3 31 4 5 17 11
4 24 5 16 19 11
4 25 24 17 55 15
4 31 25 14 57 16
5 23 6 19 22 12
5 24 23 15 55 18
6 21 28 21 50 23
6 22 21 22 52 20
6 23 22 18 53 21
6 28 7 20 24 13
7 28 30 23 58 25
7 30 8 24 28 9
8 9 12 27 30 10
8 29 9 28 35 26
8 30 29 25 58 27
9 10 11 31 36 30
9 11 12 29 38 26
9 17 10 32 37 29
9 18 17 33 48 31
9 19 18 34 45 32
9 20 19 35 46 33
9 29 20 27 51 34
10 16 11 37 39 29
10 17 16 31 48 36
11 13 12 39 7 30
11 16 13 36 40 38
13 16 14 39 42 2
14 15 26 42 47 43
14 16 15 40 44 41
14 26 27 41 56 3
15 16 18 42 48 45
15 18 19 44 33 46
15 19 20 45 34 47
15 20 26 46 49 41
16 17 18 37 32 44
20 21 26 50 52 47
20 28 21 51 20 49
20 29 28 35 58 50
21 22 26 21 54 49
22 23 25 22 55 54
22 25 26 53 56 52
23 24 25 19 16 53
25 27 26 57 43 54
25 31 27 17 4 56
28 29 30 51 28 24
29
3 4
3 31
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 25
25 26
26 27
27 31
28 29
28 30
29 30
0
0

View file

@ -0,0 +1,65 @@
29
0 28 1 4294967295 3 4294967295
1 21 2 2 5 4294967295
1 22 21 3 4294967295 1
1 28 22 0 28 2
2 20 3 5 8 4294967295
2 21 20 1 4294967295 4
3 18 25 7 25 9
3 19 18 8 4294967295 6
3 20 19 4 4294967295 7
3 25 4 6 10 4294967295
4 25 27 9 4294967295 11
4 27 5 10 13 4294967295
5 26 6 13 18 4294967295
5 27 26 11 4294967295 12
6 14 7 15 20 4294967295
6 15 14 16 4294967295 14
6 16 15 17 4294967295 15
6 17 16 18 4294967295 16
6 26 17 12 26 17
7 13 8 20 22 4294967295
7 14 13 14 4294967295 19
8 10 9 22 4294967295 4294967295
8 13 10 19 23 21
10 13 11 22 24 4294967295
11 13 12 23 4294967295 4294967295
17 25 18 26 6 4294967295
17 26 25 18 4294967295 25
22 24 23 28 4294967295 4294967295
22 28 24 3 4294967295 27
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,66 @@
30
0 28 1 4294967295 3 4294967295
1 21 2 2 5 4294967295
1 22 21 3 4294967295 1
1 28 22 0 28 2
2 20 3 5 8 4294967295
2 21 20 1 4294967295 4
3 18 25 7 25 9
3 19 18 8 4294967295 6
3 20 19 4 4294967295 7
3 25 4 6 10 4294967295
4 25 27 9 29 11
4 27 5 10 13 4294967295
5 26 6 13 18 4294967295
5 27 26 11 29 12
6 14 7 15 20 4294967295
6 15 14 16 4294967295 14
6 16 15 17 4294967295 15
6 17 16 18 4294967295 16
6 26 17 12 26 17
7 13 8 20 22 4294967295
7 14 13 14 4294967295 19
8 10 9 22 4294967295 4294967295
8 13 10 19 23 21
10 13 11 22 24 4294967295
11 13 12 23 4294967295 4294967295
17 25 18 26 6 4294967295
17 26 25 18 29 25
22 24 23 28 4294967295 4294967295
22 28 24 3 4294967295 27
25 26 27 26 13 10
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,84 @@
48
0 1 2 3 4 1
0 2 3 0 7 2
0 3 4 1 12 4294967295
0 28 1 4294967295 6 0
1 21 2 5 8 0
1 22 21 6 44 4
1 28 22 3 46 5
2 20 3 8 11 1
2 21 20 4 44 7
3 18 25 10 39 12
3 19 18 11 41 9
3 20 19 7 42 10
3 25 4 9 13 2
4 25 27 12 47 14
4 27 5 13 17 4294967295
5 6 9 16 19 4294967295
5 26 6 17 24 15
5 27 26 14 47 16
6 7 8 20 25 19
6 8 9 18 27 15
6 14 7 21 26 18
6 15 14 22 37 20
6 16 15 23 34 21
6 17 16 24 35 22
6 26 17 16 40 23
7 13 8 26 28 18
7 14 13 20 37 25
8 10 9 28 4294967295 19
8 13 10 25 29 27
10 13 11 28 31 4294967295
11 12 23 31 36 32
11 13 12 29 33 30
11 23 24 30 45 4294967295
12 13 15 31 37 34
12 15 16 33 22 35
12 16 17 34 23 36
12 17 23 35 38 30
13 14 15 26 21 33
17 18 23 39 41 36
17 25 18 40 9 38
17 26 25 24 47 39
18 19 23 10 43 38
19 20 22 11 44 43
19 22 23 42 45 41
20 21 22 8 5 42
22 24 23 46 32 43
22 28 24 6 4294967295 45
25 26 27 40 17 13
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,95 @@
59
0 1 13 4294967295 7 2
0 3 2 5 8 4294967295
0 13 14 0 40 3
0 14 27 2 43 4
0 27 31 3 57 5
0 31 3 4 14 1
1 2 12 4294967295 10 7
1 12 13 6 38 0
2 3 7 1 13 9
2 7 8 8 25 10
2 8 12 9 26 6
3 4 5 14 15 12
3 5 6 11 18 13
3 6 7 12 23 8
3 31 4 5 17 11
4 24 5 16 19 11
4 25 24 17 55 15
4 31 25 14 57 16
5 23 6 19 22 12
5 24 23 15 55 18
6 21 28 21 50 23
6 22 21 22 52 20
6 23 22 18 53 21
6 28 7 20 24 13
7 28 30 23 58 25
7 30 8 24 28 9
8 9 12 27 30 10
8 29 9 28 35 26
8 30 29 25 58 27
9 10 11 31 36 30
9 11 12 29 38 26
9 17 10 32 37 29
9 18 17 33 48 31
9 19 18 34 45 32
9 20 19 35 46 33
9 29 20 27 51 34
10 16 11 37 39 29
10 17 16 31 48 36
11 13 12 39 7 30
11 16 13 36 40 38
13 16 14 39 42 2
14 15 26 42 47 43
14 16 15 40 44 41
14 26 27 41 56 3
15 16 18 42 48 45
15 18 19 44 33 46
15 19 20 45 34 47
15 20 26 46 49 41
16 17 18 37 32 44
20 21 26 50 52 47
20 28 21 51 20 49
20 29 28 35 58 50
21 22 26 21 54 49
22 23 25 22 55 54
22 25 26 53 56 52
23 24 25 19 16 53
25 27 26 57 43 54
25 31 27 17 4 56
28 29 30 51 28 24
29
3 4
3 31
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 25
25 26
26 27
27 31
28 29
28 30
29 30
0
0

View file

@ -0,0 +1,65 @@
29
0 28 1 4294967295 3 4294967295
1 21 2 2 5 4294967295
1 22 21 3 4294967295 1
1 28 22 0 28 2
2 20 3 5 8 4294967295
2 21 20 1 4294967295 4
3 18 25 7 25 9
3 19 18 8 4294967295 6
3 20 19 4 4294967295 7
3 25 4 6 10 4294967295
4 25 27 9 4294967295 11
4 27 5 10 13 4294967295
5 26 6 13 18 4294967295
5 27 26 11 4294967295 12
6 14 7 15 20 4294967295
6 15 14 16 4294967295 14
6 16 15 17 4294967295 15
6 17 16 18 4294967295 16
6 26 17 12 26 17
7 13 8 20 22 4294967295
7 14 13 14 4294967295 19
8 10 9 22 4294967295 4294967295
8 13 10 19 23 21
10 13 11 22 24 4294967295
11 13 12 23 4294967295 4294967295
17 25 18 26 6 4294967295
17 26 25 18 4294967295 25
22 24 23 28 4294967295 4294967295
22 28 24 3 4294967295 27
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,66 @@
30
0 28 1 4294967295 3 4294967295
1 21 2 2 5 4294967295
1 22 21 3 4294967295 1
1 28 22 0 28 2
2 20 3 5 8 4294967295
2 21 20 1 4294967295 4
3 18 25 7 25 9
3 19 18 8 4294967295 6
3 20 19 4 4294967295 7
3 25 4 6 10 4294967295
4 25 27 9 29 11
4 27 5 10 13 4294967295
5 26 6 13 18 4294967295
5 27 26 11 29 12
6 14 7 15 20 4294967295
6 15 14 16 4294967295 14
6 16 15 17 4294967295 15
6 17 16 18 4294967295 16
6 26 17 12 26 17
7 13 8 20 22 4294967295
7 14 13 14 4294967295 19
8 10 9 22 4294967295 4294967295
8 13 10 19 23 21
10 13 11 22 24 4294967295
11 13 12 23 4294967295 4294967295
17 25 18 26 6 4294967295
17 26 25 18 29 25
22 24 23 28 4294967295 4294967295
22 28 24 3 4294967295 27
25 26 27 26 13 10
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,84 @@
48
0 1 2 3 4 1
0 2 3 0 7 2
0 3 4 1 12 4294967295
0 28 1 4294967295 6 0
1 21 2 5 8 0
1 22 21 6 44 4
1 28 22 3 46 5
2 20 3 8 11 1
2 21 20 4 44 7
3 18 25 10 39 12
3 19 18 11 41 9
3 20 19 7 42 10
3 25 4 9 13 2
4 25 27 12 47 14
4 27 5 13 17 4294967295
5 6 9 16 19 4294967295
5 26 6 17 24 15
5 27 26 14 47 16
6 7 8 20 25 19
6 8 9 18 27 15
6 14 7 21 26 18
6 15 14 22 37 20
6 16 15 23 34 21
6 17 16 24 35 22
6 26 17 16 40 23
7 13 8 26 28 18
7 14 13 20 37 25
8 10 9 28 4294967295 19
8 13 10 25 29 27
10 13 11 28 31 4294967295
11 12 23 31 36 32
11 13 12 29 33 30
11 23 24 30 45 4294967295
12 13 15 31 37 34
12 15 16 33 22 35
12 16 17 34 23 36
12 17 23 35 38 30
13 14 15 26 21 33
17 18 23 39 41 36
17 25 18 40 9 38
17 26 25 24 47 39
18 19 23 10 43 38
19 20 22 11 44 43
19 22 23 42 45 41
20 21 22 8 5 42
22 24 23 46 32 43
22 28 24 6 4294967295 45
25 26 27 40 17 13
29
0 1
0 28
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 27
26 27
0
0

View file

@ -0,0 +1,81 @@
31
0 28 1 4294967295 3 4294967295
1 21 2 2 5 4294967295
1 22 21 3 4294967295 1
1 28 22 0 28 2
2 20 3 5 8 4294967295
2 21 20 1 4294967295 4
3 18 25 7 25 9
3 19 18 8 4294967295 6
3 20 19 4 4294967295 7
3 25 29 6 29 4294967295
4 27 5 11 13 4294967295
4 29 27 4294967295 30 10
5 26 6 13 18 4294967295
5 27 26 10 4294967295 12
6 14 7 15 20 4294967295
6 15 14 16 4294967295 14
6 16 15 17 4294967295 15
6 17 16 18 4294967295 16
6 26 17 12 26 17
7 13 8 20 22 4294967295
7 14 13 14 4294967295 19
8 10 9 22 4294967295 4294967295
8 13 10 19 23 21
10 13 11 22 24 4294967295
11 13 12 23 4294967295 4294967295
17 25 18 26 6 4294967295
17 26 25 18 4294967295 25
22 24 23 28 4294967295 4294967295
22 28 24 3 4294967295 27
25 30 29 4294967295 30 9
27 29 30 11 29 4294967295
31
0 1
0 28
1 2
2 3
3 29
4 5
4 29
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 21
21 22
22 23
23 24
24 28
25 26
25 30
26 27
27 30
0
4
3 29
1
3 4
4 29
1
3 4
25 30
1
25 27
27 30
1
25 27

View file

@ -0,0 +1,43 @@
27
0 1 11 4294967295 5 3
0 3 2 2 6 4294967295
0 4 3 3 8 1
0 11 4 0 15 2
1 2 12 4294967295 7 5
1 12 11 4 24 0
2 3 13 1 12 7
2 13 12 6 25 4
3 4 5 2 14 9
3 5 7 8 16 10
3 7 12 9 20 11
3 12 15 10 25 13
3 14 13 13 26 6
3 15 14 11 26 12
4 6 5 15 16 8
4 11 6 3 19 14
5 6 7 14 18 9
6 8 9 19 21 18
6 9 7 17 20 16
6 11 8 15 22 17
7 9 12 18 23 10
8 10 9 22 23 17
8 11 10 19 24 21
9 10 12 21 24 20
10 11 12 22 5 23
12 13 15 7 26 11
13 14 15 12 13 25
9
3 4
3 12
4 5
5 6
6 8
8 9
9 10
10 11
11 12
0
0

View file

@ -0,0 +1,25 @@
9
0 1 2 4294967295 4294967295 1
0 2 4 0 3 2
0 4 9 1 6 4294967295
2 3 4 4294967295 5 1
3 5 6 4294967295 4294967295 5
3 6 4 4 6 3
4 6 9 5 7 2
6 7 9 4294967295 8 6
7 8 9 4294967295 4294967295 7
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,25 @@
9
0 1 2 4294967295 4294967295 1
0 2 4 0 3 2
0 4 9 1 6 4294967295
2 3 4 4294967295 5 1
3 5 6 4294967295 4294967295 5
3 6 4 4 6 3
4 6 9 5 7 2
6 7 9 4294967295 8 6
7 8 9 4294967295 4294967295 7
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,35 @@
19
0 1 2 4294967295 6 1
0 2 4 0 8 2
0 4 9 1 12 3
0 9 12 2 17 5
0 11 10 5 18 4294967295
0 12 11 3 18 4
1 3 2 7 8 0
1 8 3 4294967295 11 6
2 3 4 6 10 1
3 5 6 11 13 10
3 6 4 9 12 8
3 8 5 7 14 9
4 6 9 10 15 2
5 7 6 14 15 9
5 8 7 11 16 13
6 7 9 13 16 12
7 8 9 14 4294967295 15
9 10 12 4294967295 18 3
10 11 12 4 5 17
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,43 @@
27
0 1 11 4294967295 5 3
0 3 2 2 6 4294967295
0 4 3 3 8 1
0 11 4 0 15 2
1 2 12 4294967295 7 5
1 12 11 4 24 0
2 3 13 1 12 7
2 13 12 6 25 4
3 4 5 2 14 9
3 5 7 8 16 10
3 7 12 9 20 11
3 12 15 10 25 13
3 14 13 13 26 6
3 15 14 11 26 12
4 6 5 15 16 8
4 11 6 3 19 14
5 6 7 14 18 9
6 8 9 19 21 18
6 9 7 17 20 16
6 11 8 15 22 17
7 9 12 18 23 10
8 10 9 22 23 17
8 11 10 19 24 21
9 10 12 21 24 20
10 11 12 22 5 23
12 13 15 7 26 11
13 14 15 12 13 25
9
3 4
3 12
4 5
5 6
6 8
8 9
9 10
10 11
11 12
0
0

View file

@ -0,0 +1,25 @@
9
0 1 2 4294967295 4294967295 1
0 2 4 0 3 2
0 4 9 1 6 4294967295
2 3 4 4294967295 5 1
3 5 6 4294967295 4294967295 5
3 6 4 4 6 3
4 6 9 5 7 2
6 7 9 4294967295 8 6
7 8 9 4294967295 4294967295 7
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,25 @@
9
0 1 2 4294967295 4294967295 1
0 2 4 0 3 2
0 4 9 1 6 4294967295
2 3 4 4294967295 5 1
3 5 6 4294967295 4294967295 5
3 6 4 4 6 3
4 6 9 5 7 2
6 7 9 4294967295 8 6
7 8 9 4294967295 4294967295 7
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,35 @@
19
0 1 2 4294967295 6 1
0 2 4 0 8 2
0 4 9 1 12 3
0 9 12 2 17 5
0 11 10 5 18 4294967295
0 12 11 3 18 4
1 3 2 7 8 0
1 8 3 4294967295 11 6
2 3 4 6 10 1
3 5 6 11 13 10
3 6 4 9 12 8
3 8 5 7 14 9
4 6 9 10 15 2
5 7 6 14 15 9
5 8 7 11 16 13
6 7 9 13 16 12
7 8 9 14 4294967295 15
9 10 12 4294967295 18 3
10 11 12 4 5 17
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,43 @@
27
0 1 11 4294967295 5 3
0 3 2 2 6 4294967295
0 4 3 3 8 1
0 11 4 0 15 2
1 2 12 4294967295 7 5
1 12 11 4 24 0
2 3 13 1 12 7
2 13 12 6 25 4
3 4 5 2 14 9
3 5 7 8 16 10
3 7 12 9 20 11
3 12 15 10 25 13
3 14 13 13 26 6
3 15 14 11 26 12
4 6 5 15 16 8
4 11 6 3 19 14
5 6 7 14 18 9
6 8 9 19 21 18
6 9 7 17 20 16
6 11 8 15 22 17
7 9 12 18 23 10
8 10 9 22 23 17
8 11 10 19 24 21
9 10 12 21 24 20
10 11 12 22 5 23
12 13 15 7 26 11
13 14 15 12 13 25
9
3 4
3 12
4 5
5 6
6 8
8 9
9 10
10 11
11 12
0
0

View file

@ -0,0 +1,25 @@
9
0 1 2 4294967295 4294967295 1
0 2 4 0 3 2
0 4 9 1 6 4294967295
2 3 4 4294967295 5 1
3 5 6 4294967295 4294967295 5
3 6 4 4 6 3
4 6 9 5 7 2
6 7 9 4294967295 8 6
7 8 9 4294967295 4294967295 7
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,25 @@
9
0 1 2 4294967295 4294967295 1
0 2 4 0 3 2
0 4 9 1 6 4294967295
2 3 4 4294967295 5 1
3 5 6 4294967295 4294967295 5
3 6 4 4 6 3
4 6 9 5 7 2
6 7 9 4294967295 8 6
7 8 9 4294967295 4294967295 7
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,35 @@
19
0 1 2 4294967295 6 1
0 2 4 0 8 2
0 4 9 1 12 3
0 9 12 2 17 5
0 11 10 5 18 4294967295
0 12 11 3 18 4
1 3 2 7 8 0
1 8 3 4294967295 11 6
2 3 4 6 10 1
3 5 6 11 13 10
3 6 4 9 12 8
3 8 5 7 14 9
4 6 9 10 15 2
5 7 6 14 15 9
5 8 7 11 16 13
6 7 9 13 16 12
7 8 9 14 4294967295 15
9 10 12 4294967295 18 3
10 11 12 4 5 17
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,43 @@
27
0 1 11 4294967295 5 3
0 3 2 2 6 4294967295
0 4 3 3 8 1
0 11 4 0 15 2
1 2 12 4294967295 7 5
1 12 11 4 24 0
2 3 13 1 12 7
2 13 12 6 25 4
3 4 5 2 14 9
3 5 7 8 16 10
3 7 12 9 20 11
3 12 15 10 25 13
3 14 13 13 26 6
3 15 14 11 26 12
4 6 5 15 16 8
4 11 6 3 19 14
5 6 7 14 18 9
6 8 9 19 21 18
6 9 7 17 20 16
6 11 8 15 22 17
7 9 12 18 23 10
8 10 9 22 23 17
8 11 10 19 24 21
9 10 12 21 24 20
10 11 12 22 5 23
12 13 15 7 26 11
13 14 15 12 13 25
9
3 4
3 12
4 5
5 6
6 8
8 9
9 10
10 11
11 12
0
0

View file

@ -0,0 +1,25 @@
9
0 1 2 4294967295 4294967295 1
0 2 4 0 3 2
0 4 9 1 6 4294967295
2 3 4 4294967295 5 1
3 5 6 4294967295 4294967295 5
3 6 4 4 6 3
4 6 9 5 7 2
6 7 9 4294967295 8 6
7 8 9 4294967295 4294967295 7
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,25 @@
9
0 1 2 4294967295 4294967295 1
0 2 4 0 3 2
0 4 9 1 6 4294967295
2 3 4 4294967295 5 1
3 5 6 4294967295 4294967295 5
3 6 4 4 6 3
4 6 9 5 7 2
6 7 9 4294967295 8 6
7 8 9 4294967295 4294967295 7
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,35 @@
19
0 1 2 4294967295 6 1
0 2 4 0 8 2
0 4 9 1 12 3
0 9 12 2 17 5
0 11 10 5 18 4294967295
0 12 11 3 18 4
1 3 2 7 8 0
1 8 3 4294967295 11 6
2 3 4 6 10 1
3 5 6 11 13 10
3 6 4 9 12 8
3 8 5 7 14 9
4 6 9 10 15 2
5 7 6 14 15 9
5 8 7 11 16 13
6 7 9 13 16 12
7 8 9 14 4294967295 15
9 10 12 4294967295 18 3
10 11 12 4 5 17
9
0 1
0 9
1 2
2 3
3 5
5 6
6 7
7 8
8 9
0
0

View file

@ -0,0 +1,74 @@
17
0 1 2 4294967295 4294967295 1
0 2 16 0 2 4294967295
2 13 16 4294967295 15 1
3 4 18 7 8 6
3 5 6 4294967295 4294967295 5
3 6 20 4 11 7
3 18 13 3 16 4294967295
3 20 4 5 9 3
4 15 18 9 4294967295 3
4 20 15 7 4294967295 8
6 7 19 4294967295 12 11
6 19 20 10 4294967295 5
7 9 19 13 4294967295 10
7 14 9 4294967295 14 12
8 9 14 4294967295 13 4294967295
13 17 16 16 4294967295 2
13 18 17 6 4294967295 15
17
0 1
0 16
1 2
2 13
3 5
3 13
5 6
6 7
7 14
8 9
8 14
9 19
15 18
15 20
16 17
17 18
19 20
0
11
0 16
1
0 9
2 13
1
2 3
3 13
1
2 3
7 14
1
7 8
8 14
1
7 8
9 19
1
0 9
15 18
1
0 9
15 20
1
0 9
16 17
1
0 9
17 18
1
0 9
19 20
1
0 9

View file

@ -0,0 +1,40 @@
17
0 1 6 4294967295 5 3
0 3 2 2 7 4294967295
0 4 3 3 9 1
0 6 4 0 12 2
1 2 8 4294967295 8 6
1 7 6 6 14 0
1 8 7 4 15 5
2 3 9 1 10 8
2 9 8 7 16 4
3 4 10 2 12 11
3 5 9 11 13 7
3 10 5 9 13 10
4 6 10 3 14 9
5 10 9 11 16 10
6 7 10 5 15 12
7 8 10 6 16 14
8 9 10 8 13 15
4
3 10
6 10
7 10
8 10
0
4
3 10
1
3 7
6 10
1
6 8
7 10
1
3 7
8 10
1
6 8

View file

@ -0,0 +1,23 @@
15
0 1 7 4294967295 6 4
0 3 2 2 7 4294967295
0 4 3 3 9 1
0 6 4 4 12 2
0 7 6 0 12 3
1 2 8 4294967295 8 6
1 8 7 5 14 0
2 3 9 1 10 8
2 9 8 7 14 5
3 4 7 2 12 11
3 5 9 11 13 7
3 7 5 9 13 10
4 6 7 3 4 9
5 7 9 11 14 10
7 8 9 6 8 13
1
3 7
0
0

View file

@ -0,0 +1,8 @@
0
1
0 4
0
0

View file

@ -0,0 +1,8 @@
0
1
0 4
0
0

View file

@ -0,0 +1,14 @@
6
0 1 4 4294967295 3 2
0 2 6 2 4 4294967295
0 4 2 0 4 1
1 3 4 4294967295 4294967295 0
2 4 6 2 5 1
4 5 6 4294967295 4294967295 4
1
0 4
0
0

View file

@ -0,0 +1,23 @@
15
0 1 7 4294967295 6 4
0 3 2 2 7 4294967295
0 4 3 3 9 1
0 6 4 4 12 2
0 7 6 0 12 3
1 2 8 4294967295 8 6
1 8 7 5 14 0
2 3 9 1 10 8
2 9 8 7 14 5
3 4 7 2 12 11
3 5 9 11 13 7
3 7 5 9 13 10
4 6 7 3 4 9
5 7 9 11 14 10
7 8 9 6 8 13
1
3 7
0
0

View file

@ -0,0 +1,8 @@
0
1
0 4
0
0

View file

@ -0,0 +1,8 @@
0
1
0 4
0
0

View file

@ -0,0 +1,14 @@
6
0 1 4 4294967295 3 2
0 2 6 2 4 4294967295
0 4 2 0 4 1
1 3 4 4294967295 4294967295 0
2 4 6 2 5 1
4 5 6 4294967295 4294967295 4
1
0 4
0
0

View file

@ -0,0 +1,23 @@
15
0 1 6 4294967295 5 3
0 3 2 2 7 4294967295
0 4 3 3 9 1
0 6 4 0 12 2
1 2 8 4294967295 8 6
1 7 6 6 12 0
1 8 7 4 14 5
2 3 9 1 10 8
2 9 8 7 14 4
3 4 7 2 12 11
3 5 9 11 13 7
3 7 5 9 13 10
4 6 7 3 5 9
5 7 9 11 14 10
7 8 9 6 8 13
1
3 7
0
0

View file

@ -0,0 +1,8 @@
0
1
0 4
0
0

View file

@ -0,0 +1,8 @@
0
1
0 4
0
0

View file

@ -0,0 +1,14 @@
6
0 1 4 4294967295 3 2
0 2 6 2 4 4294967295
0 4 2 0 4 1
1 3 4 4294967295 4294967295 0
2 4 6 2 5 1
4 5 6 4294967295 4294967295 4
1
0 4
0
0

View file

@ -0,0 +1,23 @@
15
0 1 6 4294967295 5 3
0 3 2 2 7 4294967295
0 4 3 3 9 1
0 6 4 0 12 2
1 2 8 4294967295 8 6
1 7 6 6 12 0
1 8 7 4 14 5
2 3 9 1 10 8
2 9 8 7 14 4
3 4 7 2 12 11
3 5 9 11 13 7
3 7 5 9 13 10
4 6 7 3 5 9
5 7 9 11 14 10
7 8 9 6 8 13
1
3 7
0
0

View file

@ -0,0 +1,8 @@
0
1
0 4
0
0

View file

@ -0,0 +1,8 @@
0
1
0 4
0
0

View file

@ -0,0 +1,14 @@
6
0 1 4 4294967295 3 2
0 2 6 2 4 4294967295
0 4 2 0 4 1
1 3 4 4294967295 4294967295 0
2 4 6 2 5 1
4 5 6 4294967295 4294967295 4
1
0 4
0
0

View file

@ -0,0 +1,32 @@
17
0 1 4 4294967295 5 2
0 3 10 2 11 3
0 4 3 0 9 1
0 10 2 1 8 4294967295
1 2 9 4294967295 8 7
1 5 4 6 12 0
1 8 5 7 14 5
1 9 8 4 15 6
2 10 9 3 16 4
3 4 6 2 12 10
3 6 7 9 13 11
3 7 10 10 16 1
4 5 6 5 13 9
5 7 6 14 10 12
5 8 7 6 15 13
7 8 9 14 7 16
7 9 10 15 8 11
8
3 4
3 10
4 5
5 6
6 7
7 8
8 9
9 10
0
0

View file

@ -0,0 +1,21 @@
6
0 1 3 4294967295 3 1
0 3 4 0 4294967295 2
0 4 7 1 5 4294967295
1 2 3 4294967295 4294967295 0
4 5 6 4294967295 4294967295 5
4 6 7 4 4294967295 2
8
0 1
0 7
1 2
2 3
3 4
4 5
5 6
6 7
0
0

View file

@ -0,0 +1,21 @@
6
0 1 3 4294967295 3 1
0 3 4 0 4294967295 2
0 4 7 1 5 4294967295
1 2 3 4294967295 4294967295 0
4 5 6 4294967295 4294967295 5
4 6 7 4 4294967295 2
8
0 1
0 7
1 2
2 3
3 4
4 5
5 6
6 7
0
0

View file

@ -0,0 +1,23 @@
8
0 1 3 4294967295 3 1
0 3 4 0 4 2
0 4 7 1 7 4294967295
1 2 3 4294967295 4 0
2 4 3 5 1 3
2 5 4 4294967295 6 4
4 5 6 5 4294967295 7
4 6 7 6 4294967295 2
8
0 1
0 7
1 2
2 3
3 4
4 5
5 6
6 7
0
0

View file

@ -0,0 +1,32 @@
17
0 1 4 4294967295 5 2
0 3 10 2 11 3
0 4 3 0 9 1
0 10 2 1 8 4294967295
1 2 9 4294967295 8 7
1 5 4 6 12 0
1 8 5 7 14 5
1 9 8 4 15 6
2 10 9 3 16 4
3 4 6 2 12 10
3 6 7 9 13 11
3 7 10 10 16 1
4 5 6 5 13 9
5 7 6 14 10 12
5 8 7 6 15 13
7 8 9 14 7 16
7 9 10 15 8 11
8
3 4
3 10
4 5
5 6
6 7
7 8
8 9
9 10
0
0

View file

@ -0,0 +1,21 @@
6
0 1 3 4294967295 3 1
0 3 4 0 4294967295 2
0 4 7 1 5 4294967295
1 2 3 4294967295 4294967295 0
4 5 6 4294967295 4294967295 5
4 6 7 4 4294967295 2
8
0 1
0 7
1 2
2 3
3 4
4 5
5 6
6 7
0
0

View file

@ -0,0 +1,21 @@
6
0 1 3 4294967295 3 1
0 3 4 0 4294967295 2
0 4 7 1 5 4294967295
1 2 3 4294967295 4294967295 0
4 5 6 4294967295 4294967295 5
4 6 7 4 4294967295 2
8
0 1
0 7
1 2
2 3
3 4
4 5
5 6
6 7
0
0

View file

@ -0,0 +1,23 @@
8
0 1 3 4294967295 3 1
0 3 4 0 4 2
0 4 7 1 7 4294967295
1 2 3 4294967295 4 0
2 4 3 5 1 3
2 5 4 4294967295 6 4
4 5 6 5 4294967295 7
4 6 7 6 4294967295 2
8
0 1
0 7
1 2
2 3
3 4
4 5
5 6
6 7
0
0

View file

@ -0,0 +1,32 @@
17
0 1 3 4294967295 4 1
0 3 10 0 10 2
0 10 2 1 8 4294967295
1 2 9 4294967295 8 7
1 4 3 5 9 0
1 5 4 6 11 4
1 8 5 7 12 5
1 9 8 3 15 6
2 10 9 2 16 3
3 4 6 4 11 10
3 6 10 9 13 1
4 5 6 5 12 9
5 8 6 6 14 11
6 7 10 14 16 10
6 8 7 12 15 13
7 8 9 14 7 16
7 9 10 15 8 13
8
3 4
3 10
4 5
5 6
6 7
7 8
8 9
9 10
0
0

View file

@ -0,0 +1,21 @@
6
0 1 3 4294967295 2 1
0 3 7 0 3 4294967295
1 2 3 4294967295 4294967295 0
3 4 7 4294967295 5 1
4 5 6 4294967295 4294967295 5
4 6 7 4 4294967295 3
8
0 1
0 7
1 2
2 3
3 4
4 5
5 6
6 7
0
0

View file

@ -0,0 +1,21 @@
6
0 1 3 4294967295 2 1
0 3 7 0 3 4294967295
1 2 3 4294967295 4294967295 0
3 4 7 4294967295 5 1
4 5 6 4294967295 4294967295 5
4 6 7 4 4294967295 3
8
0 1
0 7
1 2
2 3
3 4
4 5
5 6
6 7
0
0

View file

@ -0,0 +1,23 @@
8
0 1 3 4294967295 2 1
0 3 7 0 4 4294967295
1 2 3 4294967295 3 0
2 5 3 4294967295 5 2
3 4 7 5 7 1
3 5 4 3 6 4
4 5 6 5 4294967295 7
4 6 7 6 4294967295 4
8
0 1
0 7
1 2
2 3
3 4
4 5
5 6
6 7
0
0

Some files were not shown because too many files have changed in this diff Show more